[
  {
    "path": ".github/workflows/build-object-detection-final-app.yml",
    "content": "# Workflow name\nname: Build CodelabMlkitAndroidObjectDetectionFinalApp\n\non:\n  workflow_dispatch:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Set Up JDK\n        uses: actions/setup-java@v3\n        with:\n          distribution: 'zulu'\n          java-version: '11'\n          cache: 'gradle'\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v4\n\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n        working-directory: ./object-detection/final\n\n      - name: Build CodelabMlkitAndroidObjectDetectionFinalApp app\n        working-directory: ./object-detection/final\n        run: ./gradlew :app:assembleDebug\n"
  },
  {
    "path": ".github/workflows/build-object-detection-starter-app.yml",
    "content": "# Workflow name\nname: Build CodelabMlkitAndroidObjectDetectionStarterApp\n\non:\n  workflow_dispatch:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Set Up JDK\n        uses: actions/setup-java@v3\n        with:\n          distribution: 'zulu'\n          java-version: '11'\n          cache: 'gradle'\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v4\n\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n        working-directory: ./object-detection/starter\n\n      - name: Build CodelabMlkitAndroidObjectDetectionStarterApp app\n        working-directory: ./object-detection/starter\n        run: ./gradlew :app:assembleDebug\n"
  },
  {
    "path": ".github/workflows/build-translate-starter-app.yml",
    "content": "# Workflow name\nname: Build CodelabMlkitAndroidTranslateStarterApp\n\non:\n  workflow_dispatch:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Set Up JDK\n        uses: actions/setup-java@v3\n        with:\n          distribution: 'zulu'\n          java-version: '11'\n          cache: 'gradle'\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v4\n\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n        working-directory: ./translate/starter\n\n      - name: Build CodelabMlkitAndroidTranslateStarterApp app\n        working-directory: ./translate/starter\n        run: ./gradlew :app:assembleDebug\n"
  },
  {
    "path": ".github/workflows/build-vision-final-app.yml",
    "content": "# Workflow name\nname: Build CodelabMlkitAndroidVisionFinalApp\n\non:\n  workflow_dispatch:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Set Up JDK\n        uses: actions/setup-java@v3\n        with:\n          distribution: 'zulu'\n          java-version: '11'\n          cache: 'gradle'\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v4\n\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n        working-directory: ./vision/final\n\n      - name: Build CodelabMlkitAndroidVisionFinalApp app\n        working-directory: ./vision/final\n        run: ./gradlew :app:assembleDebug\n"
  },
  {
    "path": ".github/workflows/build-vision-starter-app.yml",
    "content": "# Workflow name\nname: Build CodelabMlkitAndroidVisionStarterApp\n\non:\n  workflow_dispatch:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Set Up JDK\n        uses: actions/setup-java@v3\n        with:\n          distribution: 'zulu'\n          java-version: '11'\n          cache: 'gradle'\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v4\n\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n        working-directory: ./vision/starter\n\n      - name: Build CodelabMlkitAndroidVisionStarterApp app\n        working-directory: ./vision/starter\n        run: ./gradlew :app:assembleDebug\n"
  },
  {
    "path": ".gitignore",
    "content": ".gradle\nlocal.properties\n.idea\nbuild/\n.DS_Store\n*.iml\n*.apk\n*.aar\n*.zip\ngoogle-services.json\n*.tflite\n\n.project\n.settings\n.classpath\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to become a contributor and submit your own code\n\n## Contributor License Agreements\n\nWe'd love to accept your sample apps and patches! Before we can take them, we\nhave to jump a couple of legal hurdles.\n\nPlease fill out either the individual or corporate Contributor License Agreement\n(CLA).\n\n  * If you are an individual writing original source code and you're sure you\n    own the intellectual property, then you'll need to sign an [individual CLA]\n    (https://developers.google.com/open-source/cla/individual).\n  * If you work for a company that wants to allow you to contribute your work,\n    then you'll need to sign a [corporate CLA]\n    (https://developers.google.com/open-source/cla/corporate).\n\nFollow either of the two links above to access the appropriate CLA and\ninstructions for how to sign and return it. Once we receive it, we'll be able to\naccept your pull requests.\n\n## Contributing A Patch\n\n1. Submit an issue describing your proposed change to the repo in question.\n1. The repo owner will respond to your issue promptly.\n1. If your proposed change is accepted, and you haven't already done so, sign a\n   Contributor License Agreement (see details above).\n1. Fork the desired repo, develop and test your code changes.\n1. Ensure that your code adheres to the existing style in the sample to which\n   you are contributing. Refer to the\n   [Google Cloud Platform Samples Style Guide]\n   (https://github.com/GoogleCloudPlatform/Template/wiki/style.html) for the\n   recommended coding standards for this organization.\n1. Ensure that your code has an appropriate set of unit tests which all pass.\n1. Submit a pull request.\n\n"
  },
  {
    "path": "LICENSE",
    "content": "All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav\nand *.ogg) are licensed under the CC-BY 4.0 license. All other files are\nlicensed under the Apache 2 license.\n\n=======================================================================\n\nApache License\n--------------\n\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\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\nAll image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav \nand *.ogg) are licensed under the CC-BY 4.0 license. All other files are \nlicensed under the Apache 2 license.\n\nCC-BY 4.0 License\n-----------------\n\nAttribution 4.0 International\n\n=======================================================================\n\nCreative Commons Corporation (\"Creative Commons\") is not a law firm and\ndoes not provide legal services or legal advice. Distribution of\nCreative Commons public licenses does not create a lawyer-client or\nother relationship. Creative Commons makes its licenses and related\ninformation available on an \"as-is\" basis. Creative Commons gives no\nwarranties regarding its licenses, any material licensed under their\nterms and conditions, or any related information. Creative Commons\ndisclaims all liability for damages resulting from their use to the\nfullest extent possible.\n\nUsing Creative Commons Public Licenses\n\nCreative Commons public licenses provide a standard set of terms and\nconditions that creators and other rights holders may use to share\noriginal works of authorship and other material subject to copyright\nand certain other rights specified in the public license below. The\nfollowing considerations are for informational purposes only, are not\nexhaustive, and do not form part of our licenses.\n\n     Considerations for licensors: Our public licenses are\n     intended for use by those authorized to give the public\n     permission to use material in ways otherwise restricted by\n     copyright and certain other rights. Our licenses are\n     irrevocable. Licensors should read and understand the terms\n     and conditions of the license they choose before applying it.\n     Licensors should also secure all rights necessary before\n     applying our licenses so that the public can reuse the\n     material as expected. Licensors should clearly mark any\n     material not subject to the license. This includes other CC-\n     licensed material, or material used under an exception or\n     limitation to copyright. More considerations for licensors:\n\twiki.creativecommons.org/Considerations_for_licensors\n\n     Considerations for the public: By using one of our public\n     licenses, a licensor grants the public permission to use the\n     licensed material under specified terms and conditions. If\n     the licensor's permission is not necessary for any reason--for\n     example, because of any applicable exception or limitation to\n     copyright--then that use is not regulated by the license. Our\n     licenses grant only permissions under copyright and certain\n     other rights that a licensor has authority to grant. Use of\n     the licensed material may still be restricted for other\n     reasons, including because others have copyright or other\n     rights in the material. A licensor may make special requests,\n     such as asking that all changes be marked or described.\n     Although not required by our licenses, you are encouraged to\n     respect those requests where reasonable. More considerations\n     for the public: \n\twiki.creativecommons.org/Considerations_for_licensees\n\n=======================================================================\n\nCreative Commons Attribution 4.0 International Public License\n\nBy exercising the Licensed Rights (defined below), You accept and agree\nto be bound by the terms and conditions of this Creative Commons\nAttribution 4.0 International Public License (\"Public License\"). To the\nextent this Public License may be interpreted as a contract, You are\ngranted the Licensed Rights in consideration of Your acceptance of\nthese terms and conditions, and the Licensor grants You such rights in\nconsideration of benefits the Licensor receives from making the\nLicensed Material available under these terms and conditions.\n\n\nSection 1 -- Definitions.\n\n  a. Adapted Material means material subject to Copyright and Similar\n     Rights that is derived from or based upon the Licensed Material\n     and in which the Licensed Material is translated, altered,\n     arranged, transformed, or otherwise modified in a manner requiring\n     permission under the Copyright and Similar Rights held by the\n     Licensor. For purposes of this Public License, where the Licensed\n     Material is a musical work, performance, or sound recording,\n     Adapted Material is always produced where the Licensed Material is\n     synched in timed relation with a moving image.\n\n  b. Adapter's License means the license You apply to Your Copyright\n     and Similar Rights in Your contributions to Adapted Material in\n     accordance with the terms and conditions of this Public License.\n\n  c. Copyright and Similar Rights means copyright and/or similar rights\n     closely related to copyright including, without limitation,\n     performance, broadcast, sound recording, and Sui Generis Database\n     Rights, without regard to how the rights are labeled or\n     categorized. For purposes of this Public License, the rights\n     specified in Section 2(b)(1)-(2) are not Copyright and Similar\n     Rights.\n\n  d. Effective Technological Measures means those measures that, in the\n     absence of proper authority, may not be circumvented under laws\n     fulfilling obligations under Article 11 of the WIPO Copyright\n     Treaty adopted on December 20, 1996, and/or similar international\n     agreements.\n\n  e. Exceptions and Limitations means fair use, fair dealing, and/or\n     any other exception or limitation to Copyright and Similar Rights\n     that applies to Your use of the Licensed Material.\n\n  f. Licensed Material means the artistic or literary work, database,\n     or other material to which the Licensor applied this Public\n     License.\n\n  g. Licensed Rights means the rights granted to You subject to the\n     terms and conditions of this Public License, which are limited to\n     all Copyright and Similar Rights that apply to Your use of the\n     Licensed Material and that the Licensor has authority to license.\n\n  h. Licensor means the individual(s) or entity(ies) granting rights\n     under this Public License.\n\n  i. Share means to provide material to the public by any means or\n     process that requires permission under the Licensed Rights, such\n     as reproduction, public display, public performance, distribution,\n     dissemination, communication, or importation, and to make material\n     available to the public including in ways that members of the\n     public may access the material from a place and at a time\n     individually chosen by them.\n\n  j. Sui Generis Database Rights means rights other than copyright\n     resulting from Directive 96/9/EC of the European Parliament and of\n     the Council of 11 March 1996 on the legal protection of databases,\n     as amended and/or succeeded, as well as other essentially\n     equivalent rights anywhere in the world.\n\n  k. You means the individual or entity exercising the Licensed Rights\n     under this Public License. Your has a corresponding meaning.\n\n\nSection 2 -- Scope.\n\n  a. License grant.\n\n       1. Subject to the terms and conditions of this Public License,\n          the Licensor hereby grants You a worldwide, royalty-free,\n          non-sublicensable, non-exclusive, irrevocable license to\n          exercise the Licensed Rights in the Licensed Material to:\n\n            a. reproduce and Share the Licensed Material, in whole or\n               in part; and\n\n            b. produce, reproduce, and Share Adapted Material.\n\n       2. Exceptions and Limitations. For the avoidance of doubt, where\n          Exceptions and Limitations apply to Your use, this Public\n          License does not apply, and You do not need to comply with\n          its terms and conditions.\n\n       3. Term. The term of this Public License is specified in Section\n          6(a).\n\n       4. Media and formats; technical modifications allowed. The\n          Licensor authorizes You to exercise the Licensed Rights in\n          all media and formats whether now known or hereafter created,\n          and to make technical modifications necessary to do so. The\n          Licensor waives and/or agrees not to assert any right or\n          authority to forbid You from making technical modifications\n          necessary to exercise the Licensed Rights, including\n          technical modifications necessary to circumvent Effective\n          Technological Measures. For purposes of this Public License,\n          simply making modifications authorized by this Section 2(a)\n          (4) never produces Adapted Material.\n\n       5. Downstream recipients.\n\n            a. Offer from the Licensor -- Licensed Material. Every\n               recipient of the Licensed Material automatically\n               receives an offer from the Licensor to exercise the\n               Licensed Rights under the terms and conditions of this\n               Public License.\n\n            b. No downstream restrictions. You may not offer or impose\n               any additional or different terms or conditions on, or\n               apply any Effective Technological Measures to, the\n               Licensed Material if doing so restricts exercise of the\n               Licensed Rights by any recipient of the Licensed\n               Material.\n\n       6. No endorsement. Nothing in this Public License constitutes or\n          may be construed as permission to assert or imply that You\n          are, or that Your use of the Licensed Material is, connected\n          with, or sponsored, endorsed, or granted official status by,\n          the Licensor or others designated to receive attribution as\n          provided in Section 3(a)(1)(A)(i).\n\n  b. Other rights.\n\n       1. Moral rights, such as the right of integrity, are not\n          licensed under this Public License, nor are publicity,\n          privacy, and/or other similar personality rights; however, to\n          the extent possible, the Licensor waives and/or agrees not to\n          assert any such rights held by the Licensor to the limited\n          extent necessary to allow You to exercise the Licensed\n          Rights, but not otherwise.\n\n       2. Patent and trademark rights are not licensed under this\n          Public License.\n\n       3. To the extent possible, the Licensor waives any right to\n          collect royalties from You for the exercise of the Licensed\n          Rights, whether directly or through a collecting society\n          under any voluntary or waivable statutory or compulsory\n          licensing scheme. In all other cases the Licensor expressly\n          reserves any right to collect such royalties.\n\n\nSection 3 -- License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the\nfollowing conditions.\n\n  a. Attribution.\n\n       1. If You Share the Licensed Material (including in modified\n          form), You must:\n\n            a. retain the following if it is supplied by the Licensor\n               with the Licensed Material:\n\n                 i. identification of the creator(s) of the Licensed\n                    Material and any others designated to receive\n                    attribution, in any reasonable manner requested by\n                    the Licensor (including by pseudonym if\n                    designated);\n\n                ii. a copyright notice;\n\n               iii. a notice that refers to this Public License;\n\n                iv. a notice that refers to the disclaimer of\n                    warranties;\n\n                 v. a URI or hyperlink to the Licensed Material to the\n                    extent reasonably practicable;\n\n            b. indicate if You modified the Licensed Material and\n               retain an indication of any previous modifications; and\n\n            c. indicate the Licensed Material is licensed under this\n               Public License, and include the text of, or the URI or\n               hyperlink to, this Public License.\n\n       2. You may satisfy the conditions in Section 3(a)(1) in any\n          reasonable manner based on the medium, means, and context in\n          which You Share the Licensed Material. For example, it may be\n          reasonable to satisfy the conditions by providing a URI or\n          hyperlink to a resource that includes the required\n          information.\n\n       3. If requested by the Licensor, You must remove any of the\n          information required by Section 3(a)(1)(A) to the extent\n          reasonably practicable.\n\n       4. If You Share Adapted Material You produce, the Adapter's\n          License You apply must not prevent recipients of the Adapted\n          Material from complying with this Public License.\n\n\nSection 4 -- Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that\napply to Your use of the Licensed Material:\n\n  a. for the avoidance of doubt, Section 2(a)(1) grants You the right\n     to extract, reuse, reproduce, and Share all or a substantial\n     portion of the contents of the database;\n\n  b. if You include all or a substantial portion of the database\n     contents in a database in which You have Sui Generis Database\n     Rights, then the database in which You have Sui Generis Database\n     Rights (but not its individual contents) is Adapted Material; and\n\n  c. You must comply with the conditions in Section 3(a) if You Share\n     all or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not\nreplace Your obligations under this Public License where the Licensed\nRights include other Copyright and Similar Rights.\n\n\nSection 5 -- Disclaimer of Warranties and Limitation of Liability.\n\n  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE\n     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS\n     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF\n     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,\n     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,\n     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR\n     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,\n     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT\n     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT\n     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.\n\n  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE\n     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,\n     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,\n     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,\n     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR\n     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN\n     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR\n     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR\n     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.\n\n  c. The disclaimer of warranties and limitation of liability provided\n     above shall be interpreted in a manner that, to the extent\n     possible, most closely approximates an absolute disclaimer and\n     waiver of all liability.\n\n\nSection 6 -- Term and Termination.\n\n  a. This Public License applies for the term of the Copyright and\n     Similar Rights licensed here. However, if You fail to comply with\n     this Public License, then Your rights under this Public License\n     terminate automatically.\n\n  b. Where Your right to use the Licensed Material has terminated under\n     Section 6(a), it reinstates:\n\n       1. automatically as of the date the violation is cured, provided\n          it is cured within 30 days of Your discovery of the\n          violation; or\n\n       2. upon express reinstatement by the Licensor.\n\n     For the avoidance of doubt, this Section 6(b) does not affect any\n     right the Licensor may have to seek remedies for Your violations\n     of this Public License.\n\n  c. For the avoidance of doubt, the Licensor may also offer the\n     Licensed Material under separate terms or conditions or stop\n     distributing the Licensed Material at any time; however, doing so\n     will not terminate this Public License.\n\n  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public\n     License.\n\n\nSection 7 -- Other Terms and Conditions.\n\n  a. The Licensor shall not be bound by any additional or different\n     terms or conditions communicated by You unless expressly agreed.\n\n  b. Any arrangements, understandings, or agreements regarding the\n     Licensed Material not stated herein are separate from and\n     independent of the terms and conditions of this Public License.\n\n\nSection 8 -- Interpretation.\n\n  a. For the avoidance of doubt, this Public License does not, and\n     shall not be interpreted to, reduce, limit, restrict, or impose\n     conditions on any use of the Licensed Material that could lawfully\n     be made without permission under this Public License.\n\n  b. To the extent possible, if any provision of this Public License is\n     deemed unenforceable, it shall be automatically reformed to the\n     minimum extent necessary to make it enforceable. If the provision\n     cannot be reformed, it shall be severed from this Public License\n     without affecting the enforceability of the remaining terms and\n     conditions.\n\n  c. No term or condition of this Public License will be waived and no\n     failure to comply consented to unless expressly agreed to by the\n     Licensor.\n\n  d. Nothing in this Public License constitutes or may be interpreted\n     as a limitation upon, or waiver of, any privileges and immunities\n     that apply to the Licensor or You, including from the legal\n     processes of any jurisdiction or authority.\n\n\n=======================================================================\n\nCreative Commons is not a party to its public\nlicenses. Notwithstanding, Creative Commons may elect to apply one of\nits public licenses to material it publishes and in those instances\nwill be considered the “Licensor.” The text of the Creative Commons\npublic licenses is dedicated to the public domain under the CC0 Public\nDomain Dedication. Except for the limited purpose of indicating that\nmaterial is shared under a Creative Commons public license or as\notherwise permitted by the Creative Commons policies published at\ncreativecommons.org/policies, Creative Commons does not authorize the\nuse of the trademark \"Creative Commons\" or any other trademark or logo\nof Creative Commons without its prior written consent including,\nwithout limitation, in connection with any unauthorized modifications\nto any of its public licenses or any other arrangements,\nunderstandings, or agreements concerning use of licensed material. For\nthe avoidance of doubt, this paragraph does not form part of the\npublic licenses.\n\nCreative Commons may be contacted at creativecommons.org.\n"
  },
  {
    "path": "README.md",
    "content": "Codelabs for ML Kit\n============\n\nThis repository contains the code for the ML Kit codelabs:\n* [Recognize text and facial features with ML Kit](https://g.co/codelabs/mlkit-android)\n\nIntroduction\n------------\nIn these codelabs, you will build an Android app that uses various features\nof ML Kit to recognize text and detect facial features. You will learn how to use the built in on-device Text Recognition API and the face contour API.\n\nPre-requisites\n--------------\nNone.\n\nGetting Started\n---------------\nOpen the `final/` folder in Android Studio to see the final product.\nVisit the Google codelabs site to follow along the guided steps.\n\nScreenshots\n-----------\n\nSupport\n-------\n\n- Stack Overflow: http://stackoverflow.com/questions/tagged/google-mlkit\n\nIf you've found an error in this sample, please file an issue:\nhttps://github.com/googlecodelabs/mlkit-android/issues\n\nPatches are encouraged, and may be submitted by forking this project and\nsubmitting a pull request through GitHub.\n\nLicense\n-------\n\nCopyright 2018 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "custom-model/final/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\n"
  },
  {
    "path": "custom-model/final/app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "custom-model/final/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\napply plugin: 'kotlin-android'\n\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 29\n    buildToolsVersion \"29.0.2\"\n    defaultConfig {\n        applicationId \"com.google.firebase.codelab.mlkit_custommodel\"\n        minSdkVersion 21\n        targetSdkVersion 29\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    aaptOptions {\n        noCompress \"tflite\"\n    }\n}\n\ndependencies {\n    // Kotlin\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version\"\n\n    // Coroutines\n    def coroutines_version = '1.3.0'\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version\"\n\n    // AndroidX and widgets\n    implementation 'androidx.core:core-ktx:1.1.0'\n    implementation 'androidx.appcompat:appcompat:1.1.0'\n    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-rc02'\n    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'\n\n    // Firebase and MLKit\n    implementation 'com.google.firebase:firebase-core:17.2.1'\n    implementation 'com.google.firebase:firebase-ml-model-interpreter:22.0.0'\n\n    // Test-only dependencies\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.1'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'\n}\napply plugin: 'com.google.gms.google-services'"
  },
  {
    "path": "custom-model/final/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "custom-model/final/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.firebase.codelab.mlkit_custommodel\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".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>\n    </application>\n\n</manifest>"
  },
  {
    "path": "custom-model/final/app/src/main/assets/labels.txt",
    "content": "background\ntench\ngoldfish\ngreat white shark\ntiger shark\nhammerhead\nelectric ray\nstingray\ncock\nhen\nostrich\nbrambling\ngoldfinch\nhouse finch\njunco\nindigo bunting\nrobin\nbulbul\njay\nmagpie\nchickadee\nwater ouzel\nkite\nbald eagle\nvulture\ngreat grey owl\nEuropean fire salamander\ncommon newt\neft\nspotted salamander\naxolotl\nbullfrog\ntree frog\ntailed frog\nloggerhead\nleatherback turtle\nmud turtle\nterrapin\nbox turtle\nbanded gecko\ncommon iguana\nAmerican chameleon\nwhiptail\nagama\nfrilled lizard\nalligator lizard\nGila monster\ngreen lizard\nAfrican chameleon\nKomodo dragon\nAfrican crocodile\nAmerican alligator\ntriceratops\nthunder snake\nringneck snake\nhognose snake\ngreen snake\nking snake\ngarter snake\nwater snake\nvine snake\nnight snake\nboa constrictor\nrock python\nIndian cobra\ngreen mamba\nsea snake\nhorned viper\ndiamondback\nsidewinder\ntrilobite\nharvestman\nscorpion\nblack and gold garden spider\nbarn spider\ngarden spider\nblack widow\ntarantula\nwolf spider\ntick\ncentipede\nblack grouse\nptarmigan\nruffed grouse\nprairie chicken\npeacock\nquail\npartridge\nAfrican grey\nmacaw\nsulphur-crested cockatoo\nlorikeet\ncoucal\nbee eater\nhornbill\nhummingbird\njacamar\ntoucan\ndrake\nred-breasted merganser\ngoose\nblack swan\ntusker\nechidna\nplatypus\nwallaby\nkoala\nwombat\njellyfish\nsea anemone\nbrain coral\nflatworm\nnematode\nconch\nsnail\nslug\nsea slug\nchiton\nchambered nautilus\nDungeness crab\nrock crab\nfiddler crab\nking crab\nAmerican lobster\nspiny lobster\ncrayfish\nhermit crab\nisopod\nwhite stork\nblack stork\nspoonbill\nflamingo\nlittle blue heron\nAmerican egret\nbittern\ncrane\nlimpkin\nEuropean gallinule\nAmerican coot\nbustard\nruddy turnstone\nred-backed sandpiper\nredshank\ndowitcher\noystercatcher\npelican\nking penguin\nalbatross\ngrey whale\nkiller whale\ndugong\nsea lion\nChihuahua\nJapanese spaniel\nMaltese dog\nPekinese\nShih-Tzu\nBlenheim spaniel\npapillon\ntoy terrier\nRhodesian ridgeback\nAfghan hound\nbasset\nbeagle\nbloodhound\nbluetick\nblack-and-tan coonhound\nWalker hound\nEnglish foxhound\nredbone\nborzoi\nIrish wolfhound\nItalian greyhound\nwhippet\nIbizan hound\nNorwegian elkhound\notterhound\nSaluki\nScottish deerhound\nWeimaraner\nStaffordshire bullterrier\nAmerican Staffordshire terrier\nBedlington terrier\nBorder terrier\nKerry blue terrier\nIrish terrier\nNorfolk terrier\nNorwich terrier\nYorkshire terrier\nwire-haired fox terrier\nLakeland terrier\nSealyham terrier\nAiredale\ncairn\nAustralian terrier\nDandie Dinmont\nBoston bull\nminiature schnauzer\ngiant schnauzer\nstandard schnauzer\nScotch terrier\nTibetan terrier\nsilky terrier\nsoft-coated wheaten terrier\nWest Highland white terrier\nLhasa\nflat-coated retriever\ncurly-coated retriever\ngolden retriever\nLabrador retriever\nChesapeake Bay retriever\nGerman short-haired pointer\nvizsla\nEnglish setter\nIrish setter\nGordon setter\nBrittany spaniel\nclumber\nEnglish springer\nWelsh springer spaniel\ncocker spaniel\nSussex spaniel\nIrish water spaniel\nkuvasz\nschipperke\ngroenendael\nmalinois\nbriard\nkelpie\nkomondor\nOld English sheepdog\nShetland sheepdog\ncollie\nBorder collie\nBouvier des Flandres\nRottweiler\nGerman shepherd\nDoberman\nminiature pinscher\nGreater Swiss Mountain dog\nBernese mountain dog\nAppenzeller\nEntleBucher\nboxer\nbull mastiff\nTibetan mastiff\nFrench bulldog\nGreat Dane\nSaint Bernard\nEskimo dog\nmalamute\nSiberian husky\ndalmatian\naffenpinscher\nbasenji\npug\nLeonberg\nNewfoundland\nGreat Pyrenees\nSamoyed\nPomeranian\nchow\nkeeshond\nBrabancon griffon\nPembroke\nCardigan\ntoy poodle\nminiature poodle\nstandard poodle\nMexican hairless\ntimber wolf\nwhite wolf\nred wolf\ncoyote\ndingo\ndhole\nAfrican hunting dog\nhyena\nred fox\nkit fox\nArctic fox\ngrey fox\ntabby\ntiger cat\nPersian cat\nSiamese cat\nEgyptian cat\ncougar\nlynx\nleopard\nsnow leopard\njaguar\nlion\ntiger\ncheetah\nbrown bear\nAmerican black bear\nice bear\nsloth bear\nmongoose\nmeerkat\ntiger beetle\nladybug\nground beetle\nlong-horned beetle\nleaf beetle\ndung beetle\nrhinoceros beetle\nweevil\nfly\nbee\nant\ngrasshopper\ncricket\nwalking stick\ncockroach\nmantis\ncicada\nleafhopper\nlacewing\ndragonfly\ndamselfly\nadmiral\nringlet\nmonarch\ncabbage butterfly\nsulphur butterfly\nlycaenid\nstarfish\nsea urchin\nsea cucumber\nwood rabbit\nhare\nAngora\nhamster\nporcupine\nfox squirrel\nmarmot\nbeaver\nguinea pig\nsorrel\nzebra\nhog\nwild boar\nwarthog\nhippopotamus\nox\nwater buffalo\nbison\nram\nbighorn\nibex\nhartebeest\nimpala\ngazelle\nArabian camel\nllama\nweasel\nmink\npolecat\nblack-footed ferret\notter\nskunk\nbadger\narmadillo\nthree-toed sloth\norangutan\ngorilla\nchimpanzee\ngibbon\nsiamang\nguenon\npatas\nbaboon\nmacaque\nlangur\ncolobus\nproboscis monkey\nmarmoset\ncapuchin\nhowler monkey\ntiti\nspider monkey\nsquirrel monkey\nMadagascar cat\nindri\nIndian elephant\nAfrican elephant\nlesser panda\ngiant panda\nbarracouta\neel\ncoho\nrock beauty\nanemone fish\nsturgeon\ngar\nlionfish\npuffer\nabacus\nabaya\nacademic gown\naccordion\nacoustic guitar\naircraft carrier\nairliner\nairship\naltar\nambulance\namphibian\nanalog clock\napiary\napron\nashcan\nassault rifle\nbackpack\nbakery\nbalance beam\nballoon\nballpoint\nBand Aid\nbanjo\nbannister\nbarbell\nbarber chair\nbarbershop\nbarn\nbarometer\nbarrel\nbarrow\nbaseball\nbasketball\nbassinet\nbassoon\nbathing cap\nbath towel\nbathtub\nbeach wagon\nbeacon\nbeaker\nbearskin\nbeer bottle\nbeer glass\nbell cote\nbib\nbicycle-built-for-two\nbikini\nbinder\nbinoculars\nbirdhouse\nboathouse\nbobsled\nbolo tie\nbonnet\nbookcase\nbookshop\nbottlecap\nbow\nbow tie\nbrass\nbrassiere\nbreakwater\nbreastplate\nbroom\nbucket\nbuckle\nbulletproof vest\nbullet train\nbutcher shop\ncab\ncaldron\ncandle\ncannon\ncanoe\ncan opener\ncardigan\ncar mirror\ncarousel\ncarpenter's kit\ncarton\ncar wheel\ncash machine\ncassette\ncassette player\ncastle\ncatamaran\nCD player\ncello\ncellular telephone\nchain\nchainlink fence\nchain mail\nchain saw\nchest\nchiffonier\nchime\nchina cabinet\nChristmas stocking\nchurch\ncinema\ncleaver\ncliff dwelling\ncloak\nclog\ncocktail shaker\ncoffee mug\ncoffeepot\ncoil\ncombination lock\ncomputer keyboard\nconfectionery\ncontainer ship\nconvertible\ncorkscrew\ncornet\ncowboy boot\ncowboy hat\ncradle\ncrane\ncrash helmet\ncrate\ncrib\nCrock Pot\ncroquet ball\ncrutch\ncuirass\ndam\ndesk\ndesktop computer\ndial telephone\ndiaper\ndigital clock\ndigital watch\ndining table\ndishrag\ndishwasher\ndisk brake\ndock\ndogsled\ndome\ndoormat\ndrilling platform\ndrum\ndrumstick\ndumbbell\nDutch oven\nelectric fan\nelectric guitar\nelectric locomotive\nentertainment center\nenvelope\nespresso maker\nface powder\nfeather boa\nfile\nfireboat\nfire engine\nfire screen\nflagpole\nflute\nfolding chair\nfootball helmet\nforklift\nfountain\nfountain pen\nfour-poster\nfreight car\nFrench horn\nfrying pan\nfur coat\ngarbage truck\ngasmask\ngas pump\ngoblet\ngo-kart\ngolf ball\ngolfcart\ngondola\ngong\ngown\ngrand piano\ngreenhouse\ngrille\ngrocery store\nguillotine\nhair slide\nhair spray\nhalf track\nhammer\nhamper\nhand blower\nhand-held computer\nhandkerchief\nhard disc\nharmonica\nharp\nharvester\nhatchet\nholster\nhome theater\nhoneycomb\nhook\nhoopskirt\nhorizontal bar\nhorse cart\nhourglass\niPod\niron\njack-o'-lantern\njean\njeep\njersey\njigsaw puzzle\njinrikisha\njoystick\nkimono\nknee pad\nknot\nlab coat\nladle\nlampshade\nlaptop\nlawn mower\nlens cap\nletter opener\nlibrary\nlifeboat\nlighter\nlimousine\nliner\nlipstick\nLoafer\nlotion\nloudspeaker\nloupe\nlumbermill\nmagnetic compass\nmailbag\nmailbox\nmaillot\nmaillot\nmanhole cover\nmaraca\nmarimba\nmask\nmatchstick\nmaypole\nmaze\nmeasuring cup\nmedicine chest\nmegalith\nmicrophone\nmicrowave\nmilitary uniform\nmilk can\nminibus\nminiskirt\nminivan\nmissile\nmitten\nmixing bowl\nmobile home\nModel T\nmodem\nmonastery\nmonitor\nmoped\nmortar\nmortarboard\nmosque\nmosquito net\nmotor scooter\nmountain bike\nmountain tent\nmouse\nmousetrap\nmoving van\nmuzzle\nnail\nneck brace\nnecklace\nnipple\nnotebook\nobelisk\noboe\nocarina\nodometer\noil filter\norgan\noscilloscope\noverskirt\noxcart\noxygen mask\npacket\npaddle\npaddlewheel\npadlock\npaintbrush\npajama\npalace\npanpipe\npaper towel\nparachute\nparallel bars\npark bench\nparking meter\npassenger car\npatio\npay-phone\npedestal\npencil box\npencil sharpener\nperfume\nPetri dish\nphotocopier\npick\npickelhaube\npicket fence\npickup\npier\npiggy bank\npill bottle\npillow\nping-pong ball\npinwheel\npirate\npitcher\nplane\nplanetarium\nplastic bag\nplate rack\nplow\nplunger\nPolaroid camera\npole\npolice van\nponcho\npool table\npop bottle\npot\npotter's wheel\npower drill\nprayer rug\nprinter\nprison\nprojectile\nprojector\npuck\npunching bag\npurse\nquill\nquilt\nracer\nracket\nradiator\nradio\nradio telescope\nrain barrel\nrecreational vehicle\nreel\nreflex camera\nrefrigerator\nremote control\nrestaurant\nrevolver\nrifle\nrocking chair\nrotisserie\nrubber eraser\nrugby ball\nrule\nrunning shoe\nsafe\nsafety pin\nsaltshaker\nsandal\nsarong\nsax\nscabbard\nscale\nschool bus\nschooner\nscoreboard\nscreen\nscrew\nscrewdriver\nseat belt\nsewing machine\nshield\nshoe shop\nshoji\nshopping basket\nshopping cart\nshovel\nshower cap\nshower curtain\nski\nski mask\nsleeping bag\nslide rule\nsliding door\nslot\nsnorkel\nsnowmobile\nsnowplow\nsoap dispenser\nsoccer ball\nsock\nsolar dish\nsombrero\nsoup bowl\nspace bar\nspace heater\nspace shuttle\nspatula\nspeedboat\nspider web\nspindle\nsports car\nspotlight\nstage\nsteam locomotive\nsteel arch bridge\nsteel drum\nstethoscope\nstole\nstone wall\nstopwatch\nstove\nstrainer\nstreetcar\nstretcher\nstudio couch\nstupa\nsubmarine\nsuit\nsundial\nsunglass\nsunglasses\nsunscreen\nsuspension bridge\nswab\nsweatshirt\nswimming trunks\nswing\nswitch\nsyringe\ntable lamp\ntank\ntape player\nteapot\nteddy\ntelevision\ntennis ball\nthatch\ntheater curtain\nthimble\nthresher\nthrone\ntile roof\ntoaster\ntobacco shop\ntoilet seat\ntorch\ntotem pole\ntow truck\ntoyshop\ntractor\ntrailer truck\ntray\ntrench coat\ntricycle\ntrimaran\ntripod\ntriumphal arch\ntrolleybus\ntrombone\ntub\nturnstile\ntypewriter keyboard\numbrella\nunicycle\nupright\nvacuum\nvase\nvault\nvelvet\nvending machine\nvestment\nviaduct\nviolin\nvolleyball\nwaffle iron\nwall clock\nwallet\nwardrobe\nwarplane\nwashbasin\nwasher\nwater bottle\nwater jug\nwater tower\nwhiskey jug\nwhistle\nwig\nwindow screen\nwindow shade\nWindsor tie\nwine bottle\nwing\nwok\nwooden spoon\nwool\nworm fence\nwreck\nyawl\nyurt\nweb site\ncomic book\ncrossword puzzle\nstreet sign\ntraffic light\nbook jacket\nmenu\nplate\nguacamole\nconsomme\nhot pot\ntrifle\nice cream\nice lolly\nFrench loaf\nbagel\npretzel\ncheeseburger\nhotdog\nmashed potato\nhead cabbage\nbroccoli\ncauliflower\nzucchini\nspaghetti squash\nacorn squash\nbutternut squash\ncucumber\nartichoke\nbell pepper\ncardoon\nmushroom\nGranny Smith\nstrawberry\norange\nlemon\nfig\npineapple\nbanana\njackfruit\ncustard apple\npomegranate\nhay\ncarbonara\nchocolate sauce\ndough\nmeat loaf\npizza\npotpie\nburrito\nred wine\nespresso\ncup\neggnog\nalp\nbubble\ncliff\ncoral reef\ngeyser\nlakeside\npromontory\nsandbar\nseashore\nvalley\nvolcano\nballplayer\ngroom\nscuba diver\nrapeseed\ndaisy\nyellow lady's slipper\ncorn\nacorn\nhip\nbuckeye\ncoral fungus\nagaric\ngyromitra\nstinkhorn\nearthstar\nhen-of-the-woods\nbolete\near\ntoilet tissue\n"
  },
  {
    "path": "custom-model/final/app/src/main/java/com/google/firebase/codelab/mlkit_custommodel/GraphicOverlay.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.firebase.codelab.mlkit_custommodel;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * A view which renders a series of custom graphics to be overlayed on top of an associated preview\n * (i.e., the camera preview). The creator can add graphics objects, update the objects, and remove\n * them, triggering the appropriate drawing and invalidation within the view.\n * <p>\n * <p>Supports scaling and mirroring of the graphics relative the camera's preview properties. The\n * idea is that detection items are expressed in terms of a preview size, but need to be scaled up\n * to the full view size, and also mirrored in the case of the front-facing camera.\n * <p>\n * <p>Associated {@link Graphic} items should use the following methods to convert to view\n * coordinates for the graphics that are drawn:\n * <p>\n * <ol>\n * <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the\n * supplied value from the preview scale to the view scale.\n * <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n * coordinate from the preview's coordinate system to the view coordinate system.\n * </ol>\n */\npublic class GraphicOverlay extends View {\n    private final Object lock = new Object();\n    private int previewWidth;\n    private float widthScaleFactor = 1.0f;\n    private int previewHeight;\n    private float heightScaleFactor = 1.0f;\n    private int facing = CameraCharacteristics.LENS_FACING_BACK;\n    private Set<Graphic> graphics = new HashSet<>();\n\n    /**\n     * Base class for a custom graphics object to be rendered within the graphic overlay. Subclass\n     * this and implement the {@link Graphic#draw(Canvas)} method to define the graphics element. Add\n     * instances to the overlay using {@link GraphicOverlay#add(Graphic)}.\n     */\n    public abstract static class Graphic {\n        private GraphicOverlay overlay;\n\n        public Graphic(GraphicOverlay overlay) {\n            this.overlay = overlay;\n        }\n\n        /**\n         * Draw the graphic on the supplied canvas. Drawing should use the following methods to convert\n         * to view coordinates for the graphics that are drawn:\n         * <p>\n         * <ol>\n         * <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the\n         * supplied value from the preview scale to the view scale.\n         * <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n         * coordinate from the preview's coordinate system to the view coordinate system.\n         * </ol>\n         *\n         * @param canvas drawing canvas\n         */\n        public abstract void draw(Canvas canvas);\n\n        /**\n         * Adjusts a horizontal value of the supplied value from the preview scale to the view scale.\n         */\n        public float scaleX(float horizontal) {\n            return horizontal * overlay.widthScaleFactor;\n        }\n\n        /**\n         * Adjusts a vertical value of the supplied value from the preview scale to the view scale.\n         */\n        public float scaleY(float vertical) {\n            return vertical * overlay.heightScaleFactor;\n        }\n\n        /**\n         * Returns the application context of the app.\n         */\n        public Context getApplicationContext() {\n            return overlay.getContext().getApplicationContext();\n        }\n\n        /**\n         * Adjusts the x coordinate from the preview's coordinate system to the view coordinate system.\n         */\n        public float translateX(float x) {\n            if (overlay.facing == CameraCharacteristics.LENS_FACING_FRONT) {\n                return overlay.getWidth() - scaleX(x);\n            } else {\n                return scaleX(x);\n            }\n        }\n\n        /**\n         * Adjusts the y coordinate from the preview's coordinate system to the view coordinate system.\n         */\n        public float translateY(float y) {\n            return scaleY(y);\n        }\n\n        public void postInvalidate() {\n            overlay.postInvalidate();\n        }\n    }\n\n    public GraphicOverlay(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    /**\n     * Removes all graphics from the overlay.\n     */\n    public void clear() {\n        synchronized (lock) {\n            graphics.clear();\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Adds a graphic to the overlay.\n     */\n    public void add(Graphic graphic) {\n        synchronized (lock) {\n            graphics.add(graphic);\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Removes a graphic from the overlay.\n     */\n    public void remove(Graphic graphic) {\n        synchronized (lock) {\n            graphics.remove(graphic);\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Sets the camera attributes for size and facing direction, which informs how to transform image\n     * coordinates later.\n     */\n    public void setCameraInfo(int previewWidth, int previewHeight, int facing) {\n        synchronized (lock) {\n            this.previewWidth = previewWidth;\n            this.previewHeight = previewHeight;\n            this.facing = facing;\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Draws the overlay with its associated graphic objects.\n     */\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n\n        synchronized (lock) {\n            if ((previewWidth != 0) && (previewHeight != 0)) {\n                widthScaleFactor = (float) canvas.getWidth() / (float) previewWidth;\n                heightScaleFactor = (float) canvas.getHeight() / (float) previewHeight;\n            }\n\n            for (Graphic graphic : graphics) {\n                graphic.draw(canvas);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "custom-model/final/app/src/main/java/com/google/firebase/codelab/mlkit_custommodel/LabelGraphic.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.firebase.codelab.mlkit_custommodel;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\n\nimport java.util.List;\n\n/** Graphic instance for rendering image labels. */\npublic class LabelGraphic extends GraphicOverlay.Graphic {\n\n  private final Paint textPaint;\n  private final GraphicOverlay overlay;\n\n  private List<String> labels;\n\n  LabelGraphic(GraphicOverlay overlay, List<String> labels) {\n    super(overlay);\n    this.overlay = overlay;\n    this.labels = labels;\n    textPaint = new Paint();\n    textPaint.setColor(Color.WHITE);\n    textPaint.setTextSize(60.0f);\n  }\n\n  @Override\n  public synchronized void draw(Canvas canvas) {\n    float x = overlay.getWidth() / 4.0f;\n    float y = overlay.getHeight() / 4.0f;\n\n    for (String label : labels) {\n      canvas.drawText(label, x, y, textPaint);\n      y = y - 62.0f;\n    }\n  }\n}\n"
  },
  {
    "path": "custom-model/final/app/src/main/java/com/google/firebase/codelab/mlkit_custommodel/MainActivity.kt",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.firebase.codelab.mlkit_custommodel\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimport android.os.Bundle\nimport android.util.Log\nimport android.util.Pair\nimport android.view.View\nimport android.widget.AdapterView\nimport android.widget.ArrayAdapter\nimport android.widget.Toast\n\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.lifecycle.lifecycleScope\nimport com.google.firebase.ml.common.FirebaseMLException\nimport com.google.firebase.ml.common.modeldownload.FirebaseModelDownloadConditions\nimport com.google.firebase.ml.common.modeldownload.FirebaseModelManager\nimport com.google.firebase.ml.custom.*\nimport kotlinx.android.synthetic.main.activity_main.*\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.suspendCancellableCoroutine\n\nimport java.io.BufferedReader\nimport java.io.InputStreamReader\nimport java.nio.ByteBuffer\nimport java.nio.ByteOrder\nimport kotlin.RuntimeException\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.experimental.and\nimport kotlin.math.max\nimport kotlin.math.min\n\n\nclass MainActivity : AppCompatActivity(), AdapterView.OnItemSelectedListener {\n\n    /** Data structure holding pairs of <label, confidence> for each inference result */\n    data class LabelConfidence(val label: String, val confidence: Float)\n\n    /** Current image being displayed in our app's screen */\n    private var selectedImage: Bitmap? = null\n\n    /** List of JPG files in our assets folder */\n    private val imagePaths by lazy {\n        resources.assets.list(\"\")!!.filter { it.endsWith(\".jpg\") }\n    }\n\n    /** Labels corresponding to the output of the vision model. */\n    private val labelList by lazy {\n        BufferedReader(InputStreamReader(resources.assets.open(LABEL_PATH))).lineSequence().toList()\n    }\n\n    /** Preallocated buffers for storing image data. */\n    private val imageBuffer = IntArray(DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y)\n\n    // Gets the targeted width / height.\n    private val targetedWidthHeight: Pair<Int, Int>\n        get() {\n            val targetWidth: Int\n            val targetHeight: Int\n            val maxWidthForPortraitMode = image_view.width\n            val maxHeightForPortraitMode = image_view.height\n            targetWidth = maxWidthForPortraitMode\n            targetHeight = maxHeightForPortraitMode\n            return Pair(targetWidth, targetHeight)\n        }\n\n    /** Input options used for our Firebase model interpreter */\n    private val modelInputOutputOptions by lazy {\n        val inputDims = arrayOf(DIM_BATCH_SIZE, DIM_IMG_SIZE_X, DIM_IMG_SIZE_Y, DIM_PIXEL_SIZE)\n        val outputDims = arrayOf(DIM_BATCH_SIZE, labelList.size)\n        FirebaseModelInputOutputOptions.Builder()\n            .setInputFormat(0, FirebaseModelDataType.BYTE, inputDims.toIntArray())\n            .setOutputFormat(0, FirebaseModelDataType.BYTE, outputDims.toIntArray())\n            .build()\n    }\n\n    /** Firebase model interpreter used for the local model from assets */\n    private lateinit var modelInterpreter: FirebaseModelInterpreter\n\n    /** Initialize a local model interpreter from assets file */\n    private fun createLocalModelInterpreter(): FirebaseModelInterpreter {\n        // Select the first available .tflite file as our local model\n        val localModelName = resources.assets.list(\"\")?.firstOrNull { it.endsWith(\".tflite\") }\n            ?: throw(RuntimeException(\"Don't forget to add the tflite file to your assets folder\"))\n        Log.d(TAG, \"Local model found: $localModelName\")\n\n        // Create an interpreter with the local model asset\n        val localModel =\n            FirebaseCustomLocalModel.Builder().setAssetFilePath(localModelName).build()\n        val localInterpreter = FirebaseModelInterpreter.getInstance(\n            FirebaseModelInterpreterOptions.Builder(localModel).build())!!\n        Log.d(TAG, \"Local model interpreter initialized\")\n\n        // Return the interpreter\n        return localInterpreter\n    }\n\n    /** Initialize a remote model interpreter from Firebase server */\n    private suspend fun createRemoteModelInterpreter(): FirebaseModelInterpreter {\n        return suspendCancellableCoroutine { cont ->\n            runOnUiThread {\n                Toast.makeText(baseContext, \"Downloading model...\", Toast.LENGTH_LONG).show()\n            }\n\n            // Define conditions required for our model to be downloaded. We only request Wi-Fi.\n            val conditions =\n                FirebaseModelDownloadConditions.Builder().requireWifi().build()\n\n            // Build a remote model object by specifying the name you assigned the model\n            // when you uploaded it in the Firebase console.\n            val remoteModel =\n                FirebaseCustomRemoteModel.Builder(REMOTE_MODEL_NAME).build()\n            val manager = FirebaseModelManager.getInstance()\n            manager.download(remoteModel, conditions).addOnCompleteListener {\n                if (!it.isSuccessful) cont.resumeWithException(\n                    RuntimeException(\"Remote model failed to download\", it.exception))\n\n                val msg = \"Remote model successfully downloaded\"\n                runOnUiThread { Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() }\n                Log.d(TAG, msg)\n\n                val remoteInterpreter = FirebaseModelInterpreter.getInstance(\n                    FirebaseModelInterpreterOptions.Builder(remoteModel).build())!!\n                Log.d(TAG, \"Remote model interpreter initialized\")\n\n                // Return the interpreter via continuation object\n                cont.resume(remoteInterpreter)\n            }\n        }\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n        \n        val adapter = ArrayAdapter(\n            this, \n            android.R.layout.simple_spinner_dropdown_item, \n            imagePaths.mapIndexed { idx, _ -> \"Image ${idx + 1}\" })\n\n        spinner.adapter = adapter\n        spinner.onItemSelectedListener = this\n        button_run.setOnClickListener { runModelInference() }\n\n        // Disable the inference button until model is loaded\n        button_run.isEnabled = false\n\n        // Load the model interpreter in a coroutine\n        lifecycleScope.launch(Dispatchers.IO) {\n            //modelInterpreter = createLocalModelInterpreter()\n            //modelInterpreter = createRemoteModelInterpreter()\n            runOnUiThread { button_run.isEnabled = true }\n        }\n\n    }\n\n    /** Uses model to make predictions and interpret output into likely labels. */\n    private fun runModelInference() = selectedImage?.let { image ->\n\n        // Create input data.\n        val imgData = convertBitmapToByteBuffer(image)\n\n        try {\n            // Create model inputs from our image data.\n            val modelInputs = FirebaseModelInputs.Builder().add(imgData).build()\n\n            // Perform inference using our model interpreter.\n            modelInterpreter.run(modelInputs, modelInputOutputOptions).continueWith {\n                val inferenceOutput = it.result?.getOutput<Array<ByteArray>>(0)!!\n\n                // Display labels on the screen using an overlay\n                val topLabels = getTopLabels(inferenceOutput)\n                graphic_overlay.clear()\n                graphic_overlay.add(LabelGraphic(graphic_overlay, topLabels))\n                topLabels\n            }\n\n        } catch (exc: FirebaseMLException) {\n            val msg = \"Error running model inference\"\n            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()\n            Log.e(TAG, msg, exc)\n        }\n    }\n\n    /** Gets the top labels in the results. */\n    @Synchronized\n    private fun getTopLabels(inferenceOutput: Array<ByteArray>): List<String> {\n        // Since we ran inference on a single image, inference output will have a single row.\n        val imageInference = inferenceOutput.first()\n\n        // The columns of the image inference correspond to the confidence for each label.\n        return labelList.mapIndexed { idx, label ->\n            LabelConfidence(label, (imageInference[idx] and 0xFF.toByte()) / 255.0f)\n\n            // Sort the results in decreasing order of confidence and return only top 3.\n        }.sortedBy { it.confidence }.reversed().map { \"${it.label}:${it.confidence}\" }\n            .subList(0, min(labelList.size, RESULTS_TO_SHOW))\n    }\n\n    /** Writes Image data into a `ByteBuffer`. */\n    @Synchronized\n    private fun convertBitmapToByteBuffer(bitmap: Bitmap): ByteBuffer {\n        val imgData = ByteBuffer.allocateDirect(\n                DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE).apply {\n            order(ByteOrder.nativeOrder())\n            rewind()\n        }\n        val scaledBitmap =\n            Bitmap.createScaledBitmap(bitmap, DIM_IMG_SIZE_X, DIM_IMG_SIZE_Y, true)\n        scaledBitmap.getPixels(\n            imageBuffer, 0, scaledBitmap.width, 0, 0, scaledBitmap.width, scaledBitmap.height)\n        // Convert the image to int points.\n        var pixel = 0\n        for (i in 0 until DIM_IMG_SIZE_X) {\n            for (j in 0 until DIM_IMG_SIZE_Y) {\n                val `val` = imageBuffer[pixel++]\n                imgData.put((`val` shr 16 and 0xFF).toByte())\n                imgData.put((`val` shr 8 and 0xFF).toByte())\n                imgData.put((`val` and 0xFF).toByte())\n            }\n        }\n        return imgData\n    }\n\n    override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {\n        graphic_overlay.clear()\n        selectedImage = decodeBitmapAsset(this, imagePaths[position])\n        if (selectedImage != null) {\n            // Get the dimensions of the View\n            val targetedSize = targetedWidthHeight\n\n            val targetWidth = targetedSize.first\n            val maxHeight = targetedSize.second\n\n            // Determine how much to scale down the image\n            val scaleFactor = max(\n                    selectedImage!!.width.toFloat() / targetWidth.toFloat(),\n                    selectedImage!!.height.toFloat() / maxHeight.toFloat())\n\n            val resizedBitmap = Bitmap.createScaledBitmap(\n                    selectedImage!!,\n                    (selectedImage!!.width / scaleFactor).toInt(),\n                    (selectedImage!!.height / scaleFactor).toInt(),\n                    true)\n\n            image_view.setImageBitmap(resizedBitmap)\n            selectedImage = resizedBitmap\n        }\n    }\n\n    override fun onNothingSelected(parent: AdapterView<*>) = Unit\n\n    companion object {\n        private val TAG = MainActivity::class.java.simpleName\n\n        /** Name of the label file stored in Assets. */\n        private const val LABEL_PATH = \"labels.txt\"\n\n        /** Name of the remote model in Firebase. */\n        private const val REMOTE_MODEL_NAME = \"mobilenet_v1_224_quant\"\n\n        /** Number of results to show in the UI. */\n        private const val RESULTS_TO_SHOW = 3\n\n        /** Dimensions of inputs. */\n        private const val DIM_BATCH_SIZE = 1\n        private const val DIM_PIXEL_SIZE = 3\n        private const val DIM_IMG_SIZE_X = 224\n        private const val DIM_IMG_SIZE_Y = 224\n\n        /** Utility function for loading and resizing images from app asset folder. */\n        fun decodeBitmapAsset(context: Context, filePath: String): Bitmap =\n            context.assets.open(filePath).let { BitmapFactory.decodeStream(it) }\n    }\n}\n"
  },
  {
    "path": "custom-model/final/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#008577\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "custom-model/final/app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>\n"
  },
  {
    "path": "custom-model/final/app/src/main/res/layout/activity_main.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    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".MainActivity\">\n\n    <ImageView\n        android:id=\"@+id/image_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"fitStart\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        android:contentDescription=\"Select image for text recognition\" />\n\n    <com.google.firebase.codelab.mlkit_custommodel.GraphicOverlay\n        android:id=\"@+id/graphic_overlay\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\" />\n\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintBottom_toTopOf=\"@id/button_run\"\n        android:background=\"@android:drawable/btn_dropdown\"\n        android:spinnerMode=\"dropdown\" />\n\n    <Button\n        android:id=\"@+id/button_run\"\n        android:text=\"Run model\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "custom-model/final/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "custom-model/final/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "custom-model/final/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#008577</color>\n    <color name=\"colorPrimaryDark\">#00574B</color>\n    <color name=\"colorAccent\">#D81B60</color>\n</resources>\n"
  },
  {
    "path": "custom-model/final/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">MLKit Custom Model</string>\n</resources>\n"
  },
  {
    "path": "custom-model/final/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "custom-model/final/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = '1.3.50'\n\n    repositories {\n        google()\n        jcenter()\n        \n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.5.2'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n        classpath 'com.google.gms:google-services:4.3.2' // google-services plugin\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n        \n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "custom-model/final/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Nov 11 12:46:49 AEDT 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.4.1-all.zip\n"
  },
  {
    "path": "custom-model/final/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official\n"
  },
  {
    "path": "custom-model/final/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\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    which java >/dev/null 2>&1 || 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.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "custom-model/final/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "custom-model/final/settings.gradle",
    "content": "include ':app'\nrootProject.name='MLKit Custom Model'\n"
  },
  {
    "path": "custom-model/starter/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\n"
  },
  {
    "path": "custom-model/starter/app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "custom-model/starter/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\napply plugin: 'kotlin-android'\n\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 29\n    buildToolsVersion \"29.0.2\"\n    defaultConfig {\n        applicationId \"com.google.firebase.codelab.mlkit_custommodel\"\n        minSdkVersion 21\n        targetSdkVersion 29\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    aaptOptions {\n        noCompress \"tflite\"\n    }\n}\n\ndependencies {\n    // Kotlin\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version\"\n\n    // Coroutines\n    def coroutines_version = '1.3.0'\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version\"\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version\"\n\n    // AndroidX and widgets\n    implementation 'androidx.core:core-ktx:1.1.0'\n    implementation 'androidx.appcompat:appcompat:1.1.0'\n    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-rc02'\n    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'\n\n    // Firebase and MLKit\n    implementation 'com.google.firebase:firebase-core:17.2.1'\n    implementation 'com.google.firebase:firebase-ml-model-interpreter:22.0.0'\n\n    // Test-only dependencies\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.1'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'\n}\napply plugin: 'com.google.gms.google-services'"
  },
  {
    "path": "custom-model/starter/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "custom-model/starter/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.firebase.codelab.mlkit_custommodel\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".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>\n    </application>\n\n</manifest>"
  },
  {
    "path": "custom-model/starter/app/src/main/assets/labels.txt",
    "content": "background\ntench\ngoldfish\ngreat white shark\ntiger shark\nhammerhead\nelectric ray\nstingray\ncock\nhen\nostrich\nbrambling\ngoldfinch\nhouse finch\njunco\nindigo bunting\nrobin\nbulbul\njay\nmagpie\nchickadee\nwater ouzel\nkite\nbald eagle\nvulture\ngreat grey owl\nEuropean fire salamander\ncommon newt\neft\nspotted salamander\naxolotl\nbullfrog\ntree frog\ntailed frog\nloggerhead\nleatherback turtle\nmud turtle\nterrapin\nbox turtle\nbanded gecko\ncommon iguana\nAmerican chameleon\nwhiptail\nagama\nfrilled lizard\nalligator lizard\nGila monster\ngreen lizard\nAfrican chameleon\nKomodo dragon\nAfrican crocodile\nAmerican alligator\ntriceratops\nthunder snake\nringneck snake\nhognose snake\ngreen snake\nking snake\ngarter snake\nwater snake\nvine snake\nnight snake\nboa constrictor\nrock python\nIndian cobra\ngreen mamba\nsea snake\nhorned viper\ndiamondback\nsidewinder\ntrilobite\nharvestman\nscorpion\nblack and gold garden spider\nbarn spider\ngarden spider\nblack widow\ntarantula\nwolf spider\ntick\ncentipede\nblack grouse\nptarmigan\nruffed grouse\nprairie chicken\npeacock\nquail\npartridge\nAfrican grey\nmacaw\nsulphur-crested cockatoo\nlorikeet\ncoucal\nbee eater\nhornbill\nhummingbird\njacamar\ntoucan\ndrake\nred-breasted merganser\ngoose\nblack swan\ntusker\nechidna\nplatypus\nwallaby\nkoala\nwombat\njellyfish\nsea anemone\nbrain coral\nflatworm\nnematode\nconch\nsnail\nslug\nsea slug\nchiton\nchambered nautilus\nDungeness crab\nrock crab\nfiddler crab\nking crab\nAmerican lobster\nspiny lobster\ncrayfish\nhermit crab\nisopod\nwhite stork\nblack stork\nspoonbill\nflamingo\nlittle blue heron\nAmerican egret\nbittern\ncrane\nlimpkin\nEuropean gallinule\nAmerican coot\nbustard\nruddy turnstone\nred-backed sandpiper\nredshank\ndowitcher\noystercatcher\npelican\nking penguin\nalbatross\ngrey whale\nkiller whale\ndugong\nsea lion\nChihuahua\nJapanese spaniel\nMaltese dog\nPekinese\nShih-Tzu\nBlenheim spaniel\npapillon\ntoy terrier\nRhodesian ridgeback\nAfghan hound\nbasset\nbeagle\nbloodhound\nbluetick\nblack-and-tan coonhound\nWalker hound\nEnglish foxhound\nredbone\nborzoi\nIrish wolfhound\nItalian greyhound\nwhippet\nIbizan hound\nNorwegian elkhound\notterhound\nSaluki\nScottish deerhound\nWeimaraner\nStaffordshire bullterrier\nAmerican Staffordshire terrier\nBedlington terrier\nBorder terrier\nKerry blue terrier\nIrish terrier\nNorfolk terrier\nNorwich terrier\nYorkshire terrier\nwire-haired fox terrier\nLakeland terrier\nSealyham terrier\nAiredale\ncairn\nAustralian terrier\nDandie Dinmont\nBoston bull\nminiature schnauzer\ngiant schnauzer\nstandard schnauzer\nScotch terrier\nTibetan terrier\nsilky terrier\nsoft-coated wheaten terrier\nWest Highland white terrier\nLhasa\nflat-coated retriever\ncurly-coated retriever\ngolden retriever\nLabrador retriever\nChesapeake Bay retriever\nGerman short-haired pointer\nvizsla\nEnglish setter\nIrish setter\nGordon setter\nBrittany spaniel\nclumber\nEnglish springer\nWelsh springer spaniel\ncocker spaniel\nSussex spaniel\nIrish water spaniel\nkuvasz\nschipperke\ngroenendael\nmalinois\nbriard\nkelpie\nkomondor\nOld English sheepdog\nShetland sheepdog\ncollie\nBorder collie\nBouvier des Flandres\nRottweiler\nGerman shepherd\nDoberman\nminiature pinscher\nGreater Swiss Mountain dog\nBernese mountain dog\nAppenzeller\nEntleBucher\nboxer\nbull mastiff\nTibetan mastiff\nFrench bulldog\nGreat Dane\nSaint Bernard\nEskimo dog\nmalamute\nSiberian husky\ndalmatian\naffenpinscher\nbasenji\npug\nLeonberg\nNewfoundland\nGreat Pyrenees\nSamoyed\nPomeranian\nchow\nkeeshond\nBrabancon griffon\nPembroke\nCardigan\ntoy poodle\nminiature poodle\nstandard poodle\nMexican hairless\ntimber wolf\nwhite wolf\nred wolf\ncoyote\ndingo\ndhole\nAfrican hunting dog\nhyena\nred fox\nkit fox\nArctic fox\ngrey fox\ntabby\ntiger cat\nPersian cat\nSiamese cat\nEgyptian cat\ncougar\nlynx\nleopard\nsnow leopard\njaguar\nlion\ntiger\ncheetah\nbrown bear\nAmerican black bear\nice bear\nsloth bear\nmongoose\nmeerkat\ntiger beetle\nladybug\nground beetle\nlong-horned beetle\nleaf beetle\ndung beetle\nrhinoceros beetle\nweevil\nfly\nbee\nant\ngrasshopper\ncricket\nwalking stick\ncockroach\nmantis\ncicada\nleafhopper\nlacewing\ndragonfly\ndamselfly\nadmiral\nringlet\nmonarch\ncabbage butterfly\nsulphur butterfly\nlycaenid\nstarfish\nsea urchin\nsea cucumber\nwood rabbit\nhare\nAngora\nhamster\nporcupine\nfox squirrel\nmarmot\nbeaver\nguinea pig\nsorrel\nzebra\nhog\nwild boar\nwarthog\nhippopotamus\nox\nwater buffalo\nbison\nram\nbighorn\nibex\nhartebeest\nimpala\ngazelle\nArabian camel\nllama\nweasel\nmink\npolecat\nblack-footed ferret\notter\nskunk\nbadger\narmadillo\nthree-toed sloth\norangutan\ngorilla\nchimpanzee\ngibbon\nsiamang\nguenon\npatas\nbaboon\nmacaque\nlangur\ncolobus\nproboscis monkey\nmarmoset\ncapuchin\nhowler monkey\ntiti\nspider monkey\nsquirrel monkey\nMadagascar cat\nindri\nIndian elephant\nAfrican elephant\nlesser panda\ngiant panda\nbarracouta\neel\ncoho\nrock beauty\nanemone fish\nsturgeon\ngar\nlionfish\npuffer\nabacus\nabaya\nacademic gown\naccordion\nacoustic guitar\naircraft carrier\nairliner\nairship\naltar\nambulance\namphibian\nanalog clock\napiary\napron\nashcan\nassault rifle\nbackpack\nbakery\nbalance beam\nballoon\nballpoint\nBand Aid\nbanjo\nbannister\nbarbell\nbarber chair\nbarbershop\nbarn\nbarometer\nbarrel\nbarrow\nbaseball\nbasketball\nbassinet\nbassoon\nbathing cap\nbath towel\nbathtub\nbeach wagon\nbeacon\nbeaker\nbearskin\nbeer bottle\nbeer glass\nbell cote\nbib\nbicycle-built-for-two\nbikini\nbinder\nbinoculars\nbirdhouse\nboathouse\nbobsled\nbolo tie\nbonnet\nbookcase\nbookshop\nbottlecap\nbow\nbow tie\nbrass\nbrassiere\nbreakwater\nbreastplate\nbroom\nbucket\nbuckle\nbulletproof vest\nbullet train\nbutcher shop\ncab\ncaldron\ncandle\ncannon\ncanoe\ncan opener\ncardigan\ncar mirror\ncarousel\ncarpenter's kit\ncarton\ncar wheel\ncash machine\ncassette\ncassette player\ncastle\ncatamaran\nCD player\ncello\ncellular telephone\nchain\nchainlink fence\nchain mail\nchain saw\nchest\nchiffonier\nchime\nchina cabinet\nChristmas stocking\nchurch\ncinema\ncleaver\ncliff dwelling\ncloak\nclog\ncocktail shaker\ncoffee mug\ncoffeepot\ncoil\ncombination lock\ncomputer keyboard\nconfectionery\ncontainer ship\nconvertible\ncorkscrew\ncornet\ncowboy boot\ncowboy hat\ncradle\ncrane\ncrash helmet\ncrate\ncrib\nCrock Pot\ncroquet ball\ncrutch\ncuirass\ndam\ndesk\ndesktop computer\ndial telephone\ndiaper\ndigital clock\ndigital watch\ndining table\ndishrag\ndishwasher\ndisk brake\ndock\ndogsled\ndome\ndoormat\ndrilling platform\ndrum\ndrumstick\ndumbbell\nDutch oven\nelectric fan\nelectric guitar\nelectric locomotive\nentertainment center\nenvelope\nespresso maker\nface powder\nfeather boa\nfile\nfireboat\nfire engine\nfire screen\nflagpole\nflute\nfolding chair\nfootball helmet\nforklift\nfountain\nfountain pen\nfour-poster\nfreight car\nFrench horn\nfrying pan\nfur coat\ngarbage truck\ngasmask\ngas pump\ngoblet\ngo-kart\ngolf ball\ngolfcart\ngondola\ngong\ngown\ngrand piano\ngreenhouse\ngrille\ngrocery store\nguillotine\nhair slide\nhair spray\nhalf track\nhammer\nhamper\nhand blower\nhand-held computer\nhandkerchief\nhard disc\nharmonica\nharp\nharvester\nhatchet\nholster\nhome theater\nhoneycomb\nhook\nhoopskirt\nhorizontal bar\nhorse cart\nhourglass\niPod\niron\njack-o'-lantern\njean\njeep\njersey\njigsaw puzzle\njinrikisha\njoystick\nkimono\nknee pad\nknot\nlab coat\nladle\nlampshade\nlaptop\nlawn mower\nlens cap\nletter opener\nlibrary\nlifeboat\nlighter\nlimousine\nliner\nlipstick\nLoafer\nlotion\nloudspeaker\nloupe\nlumbermill\nmagnetic compass\nmailbag\nmailbox\nmaillot\nmaillot\nmanhole cover\nmaraca\nmarimba\nmask\nmatchstick\nmaypole\nmaze\nmeasuring cup\nmedicine chest\nmegalith\nmicrophone\nmicrowave\nmilitary uniform\nmilk can\nminibus\nminiskirt\nminivan\nmissile\nmitten\nmixing bowl\nmobile home\nModel T\nmodem\nmonastery\nmonitor\nmoped\nmortar\nmortarboard\nmosque\nmosquito net\nmotor scooter\nmountain bike\nmountain tent\nmouse\nmousetrap\nmoving van\nmuzzle\nnail\nneck brace\nnecklace\nnipple\nnotebook\nobelisk\noboe\nocarina\nodometer\noil filter\norgan\noscilloscope\noverskirt\noxcart\noxygen mask\npacket\npaddle\npaddlewheel\npadlock\npaintbrush\npajama\npalace\npanpipe\npaper towel\nparachute\nparallel bars\npark bench\nparking meter\npassenger car\npatio\npay-phone\npedestal\npencil box\npencil sharpener\nperfume\nPetri dish\nphotocopier\npick\npickelhaube\npicket fence\npickup\npier\npiggy bank\npill bottle\npillow\nping-pong ball\npinwheel\npirate\npitcher\nplane\nplanetarium\nplastic bag\nplate rack\nplow\nplunger\nPolaroid camera\npole\npolice van\nponcho\npool table\npop bottle\npot\npotter's wheel\npower drill\nprayer rug\nprinter\nprison\nprojectile\nprojector\npuck\npunching bag\npurse\nquill\nquilt\nracer\nracket\nradiator\nradio\nradio telescope\nrain barrel\nrecreational vehicle\nreel\nreflex camera\nrefrigerator\nremote control\nrestaurant\nrevolver\nrifle\nrocking chair\nrotisserie\nrubber eraser\nrugby ball\nrule\nrunning shoe\nsafe\nsafety pin\nsaltshaker\nsandal\nsarong\nsax\nscabbard\nscale\nschool bus\nschooner\nscoreboard\nscreen\nscrew\nscrewdriver\nseat belt\nsewing machine\nshield\nshoe shop\nshoji\nshopping basket\nshopping cart\nshovel\nshower cap\nshower curtain\nski\nski mask\nsleeping bag\nslide rule\nsliding door\nslot\nsnorkel\nsnowmobile\nsnowplow\nsoap dispenser\nsoccer ball\nsock\nsolar dish\nsombrero\nsoup bowl\nspace bar\nspace heater\nspace shuttle\nspatula\nspeedboat\nspider web\nspindle\nsports car\nspotlight\nstage\nsteam locomotive\nsteel arch bridge\nsteel drum\nstethoscope\nstole\nstone wall\nstopwatch\nstove\nstrainer\nstreetcar\nstretcher\nstudio couch\nstupa\nsubmarine\nsuit\nsundial\nsunglass\nsunglasses\nsunscreen\nsuspension bridge\nswab\nsweatshirt\nswimming trunks\nswing\nswitch\nsyringe\ntable lamp\ntank\ntape player\nteapot\nteddy\ntelevision\ntennis ball\nthatch\ntheater curtain\nthimble\nthresher\nthrone\ntile roof\ntoaster\ntobacco shop\ntoilet seat\ntorch\ntotem pole\ntow truck\ntoyshop\ntractor\ntrailer truck\ntray\ntrench coat\ntricycle\ntrimaran\ntripod\ntriumphal arch\ntrolleybus\ntrombone\ntub\nturnstile\ntypewriter keyboard\numbrella\nunicycle\nupright\nvacuum\nvase\nvault\nvelvet\nvending machine\nvestment\nviaduct\nviolin\nvolleyball\nwaffle iron\nwall clock\nwallet\nwardrobe\nwarplane\nwashbasin\nwasher\nwater bottle\nwater jug\nwater tower\nwhiskey jug\nwhistle\nwig\nwindow screen\nwindow shade\nWindsor tie\nwine bottle\nwing\nwok\nwooden spoon\nwool\nworm fence\nwreck\nyawl\nyurt\nweb site\ncomic book\ncrossword puzzle\nstreet sign\ntraffic light\nbook jacket\nmenu\nplate\nguacamole\nconsomme\nhot pot\ntrifle\nice cream\nice lolly\nFrench loaf\nbagel\npretzel\ncheeseburger\nhotdog\nmashed potato\nhead cabbage\nbroccoli\ncauliflower\nzucchini\nspaghetti squash\nacorn squash\nbutternut squash\ncucumber\nartichoke\nbell pepper\ncardoon\nmushroom\nGranny Smith\nstrawberry\norange\nlemon\nfig\npineapple\nbanana\njackfruit\ncustard apple\npomegranate\nhay\ncarbonara\nchocolate sauce\ndough\nmeat loaf\npizza\npotpie\nburrito\nred wine\nespresso\ncup\neggnog\nalp\nbubble\ncliff\ncoral reef\ngeyser\nlakeside\npromontory\nsandbar\nseashore\nvalley\nvolcano\nballplayer\ngroom\nscuba diver\nrapeseed\ndaisy\nyellow lady's slipper\ncorn\nacorn\nhip\nbuckeye\ncoral fungus\nagaric\ngyromitra\nstinkhorn\nearthstar\nhen-of-the-woods\nbolete\near\ntoilet tissue\n"
  },
  {
    "path": "custom-model/starter/app/src/main/java/com/google/firebase/codelab/mlkit_custommodel/GraphicOverlay.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.firebase.codelab.mlkit_custommodel;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * A view which renders a series of custom graphics to be overlayed on top of an associated preview\n * (i.e., the camera preview). The creator can add graphics objects, update the objects, and remove\n * them, triggering the appropriate drawing and invalidation within the view.\n * <p>\n * <p>Supports scaling and mirroring of the graphics relative the camera's preview properties. The\n * idea is that detection items are expressed in terms of a preview size, but need to be scaled up\n * to the full view size, and also mirrored in the case of the front-facing camera.\n * <p>\n * <p>Associated {@link Graphic} items should use the following methods to convert to view\n * coordinates for the graphics that are drawn:\n * <p>\n * <ol>\n * <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the\n * supplied value from the preview scale to the view scale.\n * <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n * coordinate from the preview's coordinate system to the view coordinate system.\n * </ol>\n */\npublic class GraphicOverlay extends View {\n    private final Object lock = new Object();\n    private int previewWidth;\n    private float widthScaleFactor = 1.0f;\n    private int previewHeight;\n    private float heightScaleFactor = 1.0f;\n    private int facing = CameraCharacteristics.LENS_FACING_BACK;\n    private Set<Graphic> graphics = new HashSet<>();\n\n    /**\n     * Base class for a custom graphics object to be rendered within the graphic overlay. Subclass\n     * this and implement the {@link Graphic#draw(Canvas)} method to define the graphics element. Add\n     * instances to the overlay using {@link GraphicOverlay#add(Graphic)}.\n     */\n    public abstract static class Graphic {\n        private GraphicOverlay overlay;\n\n        public Graphic(GraphicOverlay overlay) {\n            this.overlay = overlay;\n        }\n\n        /**\n         * Draw the graphic on the supplied canvas. Drawing should use the following methods to convert\n         * to view coordinates for the graphics that are drawn:\n         * <p>\n         * <ol>\n         * <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the\n         * supplied value from the preview scale to the view scale.\n         * <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n         * coordinate from the preview's coordinate system to the view coordinate system.\n         * </ol>\n         *\n         * @param canvas drawing canvas\n         */\n        public abstract void draw(Canvas canvas);\n\n        /**\n         * Adjusts a horizontal value of the supplied value from the preview scale to the view scale.\n         */\n        public float scaleX(float horizontal) {\n            return horizontal * overlay.widthScaleFactor;\n        }\n\n        /**\n         * Adjusts a vertical value of the supplied value from the preview scale to the view scale.\n         */\n        public float scaleY(float vertical) {\n            return vertical * overlay.heightScaleFactor;\n        }\n\n        /**\n         * Returns the application context of the app.\n         */\n        public Context getApplicationContext() {\n            return overlay.getContext().getApplicationContext();\n        }\n\n        /**\n         * Adjusts the x coordinate from the preview's coordinate system to the view coordinate system.\n         */\n        public float translateX(float x) {\n            if (overlay.facing == CameraCharacteristics.LENS_FACING_FRONT) {\n                return overlay.getWidth() - scaleX(x);\n            } else {\n                return scaleX(x);\n            }\n        }\n\n        /**\n         * Adjusts the y coordinate from the preview's coordinate system to the view coordinate system.\n         */\n        public float translateY(float y) {\n            return scaleY(y);\n        }\n\n        public void postInvalidate() {\n            overlay.postInvalidate();\n        }\n    }\n\n    public GraphicOverlay(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    /**\n     * Removes all graphics from the overlay.\n     */\n    public void clear() {\n        synchronized (lock) {\n            graphics.clear();\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Adds a graphic to the overlay.\n     */\n    public void add(Graphic graphic) {\n        synchronized (lock) {\n            graphics.add(graphic);\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Removes a graphic from the overlay.\n     */\n    public void remove(Graphic graphic) {\n        synchronized (lock) {\n            graphics.remove(graphic);\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Sets the camera attributes for size and facing direction, which informs how to transform image\n     * coordinates later.\n     */\n    public void setCameraInfo(int previewWidth, int previewHeight, int facing) {\n        synchronized (lock) {\n            this.previewWidth = previewWidth;\n            this.previewHeight = previewHeight;\n            this.facing = facing;\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Draws the overlay with its associated graphic objects.\n     */\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n\n        synchronized (lock) {\n            if ((previewWidth != 0) && (previewHeight != 0)) {\n                widthScaleFactor = (float) canvas.getWidth() / (float) previewWidth;\n                heightScaleFactor = (float) canvas.getHeight() / (float) previewHeight;\n            }\n\n            for (Graphic graphic : graphics) {\n                graphic.draw(canvas);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "custom-model/starter/app/src/main/java/com/google/firebase/codelab/mlkit_custommodel/LabelGraphic.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.firebase.codelab.mlkit_custommodel;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\n\nimport java.util.List;\n\n/** Graphic instance for rendering image labels. */\npublic class LabelGraphic extends GraphicOverlay.Graphic {\n\n  private final Paint textPaint;\n  private final GraphicOverlay overlay;\n\n  private List<String> labels;\n\n  LabelGraphic(GraphicOverlay overlay, List<String> labels) {\n    super(overlay);\n    this.overlay = overlay;\n    this.labels = labels;\n    textPaint = new Paint();\n    textPaint.setColor(Color.WHITE);\n    textPaint.setTextSize(60.0f);\n  }\n\n  @Override\n  public synchronized void draw(Canvas canvas) {\n    float x = overlay.getWidth() / 4.0f;\n    float y = overlay.getHeight() / 4.0f;\n\n    for (String label : labels) {\n      canvas.drawText(label, x, y, textPaint);\n      y = y - 62.0f;\n    }\n  }\n}\n"
  },
  {
    "path": "custom-model/starter/app/src/main/java/com/google/firebase/codelab/mlkit_custommodel/MainActivity.kt",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.firebase.codelab.mlkit_custommodel\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimport android.os.Bundle\nimport android.util.Log\nimport android.util.Pair\nimport android.view.View\nimport android.widget.AdapterView\nimport android.widget.ArrayAdapter\nimport android.widget.Toast\n\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.lifecycle.lifecycleScope\nimport com.google.firebase.ml.common.FirebaseMLException\nimport com.google.firebase.ml.common.modeldownload.FirebaseModelDownloadConditions\nimport com.google.firebase.ml.common.modeldownload.FirebaseModelManager\nimport com.google.firebase.ml.custom.*\nimport kotlinx.android.synthetic.main.activity_main.*\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.suspendCancellableCoroutine\n\nimport java.io.BufferedReader\nimport java.io.InputStreamReader\nimport java.nio.ByteBuffer\nimport java.nio.ByteOrder\nimport java.util.*\nimport kotlin.Comparator\nimport kotlin.RuntimeException\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.resumeWithException\nimport kotlin.experimental.and\nimport kotlin.math.max\nimport kotlin.math.min\n\n\nclass MainActivity : AppCompatActivity(), AdapterView.OnItemSelectedListener {\n\n    /** Data structure holding pairs of <label, confidence> for each inference result */\n    data class LabelConfidence(val label: String, val confidence: Float)\n\n    /** Current image being displayed in our app's screen */\n    private var selectedImage: Bitmap? = null\n\n    /** List of JPG files in our assets folder */\n    private val imagePaths by lazy {\n        resources.assets.list(\"\")!!.filter { it.endsWith(\".jpg\") }\n    }\n\n    /** Labels corresponding to the output of the vision model. */\n    private val labelList by lazy {\n        BufferedReader(InputStreamReader(resources.assets.open(LABEL_PATH))).lineSequence().toList()\n    }\n\n    /** Preallocated buffers for storing image data. */\n    private val imageBuffer = IntArray(DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y)\n\n    // Gets the targeted width / height.\n    private val targetedWidthHeight: Pair<Int, Int>\n        get() {\n            val targetWidth: Int\n            val targetHeight: Int\n            val maxWidthForPortraitMode = image_view.width\n            val maxHeightForPortraitMode = image_view.height\n            targetWidth = maxWidthForPortraitMode\n            targetHeight = maxHeightForPortraitMode\n            return Pair(targetWidth, targetHeight)\n        }\n\n    /** Input options used for our Firebase model interpreter */\n    private val modelInputOutputOptions by lazy {\n        val inputDims = arrayOf(DIM_BATCH_SIZE, DIM_IMG_SIZE_X, DIM_IMG_SIZE_Y, DIM_PIXEL_SIZE)\n        val outputDims = arrayOf(DIM_BATCH_SIZE, labelList.size)\n        FirebaseModelInputOutputOptions.Builder()\n            .setInputFormat(0, FirebaseModelDataType.BYTE, inputDims.toIntArray())\n            .setOutputFormat(0, FirebaseModelDataType.BYTE, outputDims.toIntArray())\n            .build()\n    }\n\n    /** Firebase model interpreter used for the local model from assets */\n    private lateinit var modelInterpreter: FirebaseModelInterpreter\n\n    /** Initialize a local model interpreter from assets file */\n    private fun createLocalModelInterpreter(): FirebaseModelInterpreter {\n        throw NotImplementedError(\"TODO: complete this section\")\n    }\n\n    /** Initialize a remote model interpreter from Firebase server */\n    private suspend fun createRemoteModelInterpreter(): FirebaseModelInterpreter {\n        throw NotImplementedError(\"TODO: complete this section\")\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n        \n        val adapter = ArrayAdapter(\n            this, \n            android.R.layout.simple_spinner_dropdown_item, \n            imagePaths.mapIndexed { idx, _ -> \"Image ${idx + 1}\" })\n\n        spinner.adapter = adapter\n        spinner.onItemSelectedListener = this\n        button_run.setOnClickListener { runModelInference() }\n\n        // Disable the inference button until model is loaded\n        button_run.isEnabled = false\n\n        // Load the model interpreter in a coroutine\n        lifecycleScope.launch(Dispatchers.IO) {\n            //modelInterpreter = createLocalModelInterpreter()\n            //modelInterpreter = createRemoteModelInterpreter()\n            runOnUiThread { button_run.isEnabled = true }\n        }\n\n    }\n\n    /** Uses model to make predictions and interpret output into likely labels. */\n    private fun runModelInference() = selectedImage?.let { image ->\n        throw NotImplementedError(\"TODO: complete this section\")\n    }\n\n    /** Gets the top labels in the results. */\n    @Synchronized\n    private fun getTopLabels(inferenceOutput: Array<ByteArray>): List<String> {\n        // Since we ran inference on a single image, inference output will have a single row.\n        val imageInference = inferenceOutput.first()\n\n        // The columns of the image inference correspond to the confidence for each label.\n        return labelList.mapIndexed { idx, label ->\n            LabelConfidence(label, (imageInference[idx] and 0xFF.toByte()) / 255.0f)\n\n            // Sort the results in decreasing order of confidence and return only top 3.\n        }.sortedBy { it.confidence }.reversed().map { \"${it.label}:${it.confidence}\" }\n            .subList(0, min(labelList.size, RESULTS_TO_SHOW))\n    }\n\n    /** Writes Image data into a `ByteBuffer`. */\n    @Synchronized\n    private fun convertBitmapToByteBuffer(bitmap: Bitmap): ByteBuffer {\n        val imgData = ByteBuffer.allocateDirect(\n                DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE).apply {\n            order(ByteOrder.nativeOrder())\n            rewind()\n        }\n        val scaledBitmap =\n            Bitmap.createScaledBitmap(bitmap, DIM_IMG_SIZE_X, DIM_IMG_SIZE_Y, true)\n        scaledBitmap.getPixels(\n            imageBuffer, 0, scaledBitmap.width, 0, 0, scaledBitmap.width, scaledBitmap.height)\n        // Convert the image to int points.\n        var pixel = 0\n        for (i in 0 until DIM_IMG_SIZE_X) {\n            for (j in 0 until DIM_IMG_SIZE_Y) {\n                val `val` = imageBuffer[pixel++]\n                imgData.put((`val` shr 16 and 0xFF).toByte())\n                imgData.put((`val` shr 8 and 0xFF).toByte())\n                imgData.put((`val` and 0xFF).toByte())\n            }\n        }\n        return imgData\n    }\n\n    override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {\n        graphic_overlay.clear()\n        selectedImage = decodeBitmapAsset(this, imagePaths[position])\n        if (selectedImage != null) {\n            // Get the dimensions of the View\n            val targetedSize = targetedWidthHeight\n\n            val targetWidth = targetedSize.first\n            val maxHeight = targetedSize.second\n\n            // Determine how much to scale down the image\n            val scaleFactor = max(\n                    selectedImage!!.width.toFloat() / targetWidth.toFloat(),\n                    selectedImage!!.height.toFloat() / maxHeight.toFloat())\n\n            val resizedBitmap = Bitmap.createScaledBitmap(\n                    selectedImage!!,\n                    (selectedImage!!.width / scaleFactor).toInt(),\n                    (selectedImage!!.height / scaleFactor).toInt(),\n                    true)\n\n            image_view.setImageBitmap(resizedBitmap)\n            selectedImage = resizedBitmap\n        }\n    }\n\n    override fun onNothingSelected(parent: AdapterView<*>) = Unit\n\n    companion object {\n        private val TAG = MainActivity::class.java.simpleName\n\n        /** Name of the label file stored in Assets. */\n        private const val LABEL_PATH = \"labels.txt\"\n\n        /** Name of the remote model in Firebase. */\n        private const val REMOTE_MODEL_NAME = \"mobilenet_v1_224_quant\"\n\n        /** Number of results to show in the UI. */\n        private const val RESULTS_TO_SHOW = 3\n\n        /** Dimensions of inputs. */\n        private const val DIM_BATCH_SIZE = 1\n        private const val DIM_PIXEL_SIZE = 3\n        private const val DIM_IMG_SIZE_X = 224\n        private const val DIM_IMG_SIZE_Y = 224\n\n        /** Utility function for loading and resizing images from app asset folder. */\n        fun decodeBitmapAsset(context: Context, filePath: String): Bitmap =\n            context.assets.open(filePath).let { BitmapFactory.decodeStream(it) }\n    }\n}\n"
  },
  {
    "path": "custom-model/starter/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#008577\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "custom-model/starter/app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>\n"
  },
  {
    "path": "custom-model/starter/app/src/main/res/layout/activity_main.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    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".MainActivity\">\n\n    <ImageView\n        android:id=\"@+id/image_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"fitStart\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        android:contentDescription=\"Select image for text recognition\" />\n\n    <com.google.firebase.codelab.mlkit_custommodel.GraphicOverlay\n        android:id=\"@+id/graphic_overlay\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\" />\n\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintBottom_toTopOf=\"@id/button_run\"\n        android:background=\"@android:drawable/btn_dropdown\"\n        android:spinnerMode=\"dropdown\" />\n\n    <Button\n        android:id=\"@+id/button_run\"\n        android:text=\"Run model\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "custom-model/starter/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "custom-model/starter/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "custom-model/starter/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#008577</color>\n    <color name=\"colorPrimaryDark\">#00574B</color>\n    <color name=\"colorAccent\">#D81B60</color>\n</resources>\n"
  },
  {
    "path": "custom-model/starter/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">MLKit Custom Model</string>\n</resources>\n"
  },
  {
    "path": "custom-model/starter/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "custom-model/starter/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = '1.3.50'\n\n    repositories {\n        google()\n        jcenter()\n        \n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.5.2'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n        classpath 'com.google.gms:google-services:4.3.2' // google-services plugin\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n        \n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "custom-model/starter/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Nov 11 12:46:49 AEDT 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.4.1-all.zip\n"
  },
  {
    "path": "custom-model/starter/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official\n"
  },
  {
    "path": "custom-model/starter/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\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    which java >/dev/null 2>&1 || 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.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "custom-model/starter/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "custom-model/starter/settings.gradle",
    "content": "include ':app'\nrootProject.name='MLKit Custom Model'\n"
  },
  {
    "path": "object-detection/.gitignore",
    "content": "**/*.iml\n.gradle\n/local.properties\n/.idea/caches/build_file_checksums.ser\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n**/.idea\nstarter/app/google-services.json\nfinal/app/google-services.json\n\n"
  },
  {
    "path": "object-detection/final/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\n.idea"
  },
  {
    "path": "object-detection/final/app/build.gradle",
    "content": "plugins {\n    id 'com.android.application'\n    id 'kotlin-android'\n}\n\nandroid {\n    compileSdkVersion 30\n    buildToolsVersion \"30.0.3\"\n\n    defaultConfig {\n        applicationId \"com.google.mlkit.codelab.objectdetection\"\n        minSdkVersion 23\n        targetSdkVersion 30\n        versionCode 1\n        versionName \"1.0\"\n\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n}\n\ndependencies {\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version\"\n    implementation 'androidx.core:core-ktx:1.3.2'\n    implementation 'androidx.appcompat:appcompat:1.2.0'\n    implementation 'com.google.android.material:material:1.3.0'\n    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'\n    implementation 'androidx.exifinterface:exifinterface:1.0.0'\n    testImplementation 'junit:junit:4.+'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.2'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'\n\n    // MLKit\n    implementation 'com.google.mlkit:object-detection:16.2.3'\n}"
  },
  {
    "path": "object-detection/final/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "object-detection/final/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.mlkit.codelab.objectdetection\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/Theme.ObjectDetection\">\n        <activity android:name=\".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>\n\n        <provider\n            android:name=\"androidx.core.content.FileProvider\"\n            android:authorities=\"com.google.mlkit.codelab.objectdetection.fileprovider\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\">\n            <meta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/file_paths\" />\n        </provider>\n    </application>\n\n</manifest>"
  },
  {
    "path": "object-detection/final/app/src/main/java/com/google/mlkit/codelab/objectdetection/MainActivity.kt",
    "content": "/**\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * 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\npackage com.google.mlkit.codelab.objectdetection\n\nimport android.app.Activity\nimport android.content.ActivityNotFoundException\nimport android.content.Intent\nimport android.graphics.*\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.Environment\nimport android.provider.MediaStore\nimport android.util.Log\nimport android.view.View\nimport android.widget.Button\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.content.FileProvider\nimport androidx.exifinterface.media.ExifInterface\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.objects.DetectedObject\nimport com.google.mlkit.vision.objects.ObjectDetection\nimport com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions\nimport java.io.File\nimport java.io.IOException\nimport java.text.SimpleDateFormat\nimport java.util.*\nimport kotlin.math.max\nimport kotlin.math.min\n\nclass MainActivity : AppCompatActivity(), View.OnClickListener {\n    companion object {\n        const val TAG = \"MLKit-ODT\"\n        const val REQUEST_IMAGE_CAPTURE: Int = 1\n        private const val MAX_FONT_SIZE = 96F\n    }\n\n    private lateinit var captureImageFab: Button\n    private lateinit var inputImageView: ImageView\n    private lateinit var imgSampleOne: ImageView\n    private lateinit var imgSampleTwo: ImageView\n    private lateinit var imgSampleThree: ImageView\n    private lateinit var tvPlaceholder: TextView\n    private lateinit var currentPhotoPath: String\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n\n        captureImageFab = findViewById(R.id.captureImageFab)\n        inputImageView = findViewById(R.id.imageView)\n        imgSampleOne = findViewById(R.id.imgSampleOne)\n        imgSampleTwo = findViewById(R.id.imgSampleTwo)\n        imgSampleThree = findViewById(R.id.imgSampleThree)\n        tvPlaceholder = findViewById(R.id.tvPlaceholder)\n\n        captureImageFab.setOnClickListener(this)\n        imgSampleOne.setOnClickListener(this)\n        imgSampleTwo.setOnClickListener(this)\n        imgSampleThree.setOnClickListener(this)\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        super.onActivityResult(requestCode, resultCode, data)\n        if (requestCode == REQUEST_IMAGE_CAPTURE &&\n            resultCode == Activity.RESULT_OK\n        ) {\n            setViewAndDetect(getCapturedImage())\n        }\n    }\n\n    override fun onClick(v: View?) {\n        when (v?.id) {\n            R.id.captureImageFab -> {\n                try {\n                    dispatchTakePictureIntent()\n                } catch (e: ActivityNotFoundException) {\n                    Log.e(TAG, e.message.toString())\n                }\n            }\n            R.id.imgSampleOne -> {\n                setViewAndDetect(getSampleImage(R.drawable.demo_img1))\n            }\n            R.id.imgSampleTwo -> {\n                setViewAndDetect(getSampleImage(R.drawable.demo_img2))\n            }\n            R.id.imgSampleThree -> {\n                setViewAndDetect(getSampleImage(R.drawable.demo_img3))\n            }\n        }\n    }\n\n    /**\n     * ML Kit Object Detection function. We'll add ML Kit code here in the codelab.\n     */\n    private fun runObjectDetection(bitmap: Bitmap) {\n        val image = InputImage.fromBitmap(bitmap, 0)\n\n        val options = ObjectDetectorOptions.Builder()\n            .setDetectorMode(ObjectDetectorOptions.SINGLE_IMAGE_MODE)\n            .enableMultipleObjects()\n            .enableClassification()\n            .build()\n        val objectDetector = ObjectDetection.getClient(options)\n\n        objectDetector.process(image).addOnSuccessListener { results ->\n            debugPrint(results)\n\n            // Parse ML Kit's DetectedObject and create corresponding visualization data\n            val detectedObjects = results.map {\n                var text = \"Unknown\"\n\n                // We will show the top confident detection result if it exist\n                if (it.labels.isNotEmpty()) {\n                    val firstLabel = it.labels.first()\n                    text = \"${firstLabel.text}, ${firstLabel.confidence.times(100).toInt()}%\"\n                }\n                BoxWithText(it.boundingBox, text)\n            }\n\n            // Draw the detection result on the input bitmap\n            val visualizedResult = drawDetectionResult(bitmap, detectedObjects)\n\n            // Show the detection result on the app screen\n            inputImageView.setImageBitmap(visualizedResult)\n        }.addOnFailureListener {\n            Log.e(TAG, it.message.toString())\n        }\n    }\n\n    /**\n     * Set image to view and call object detection\n     */\n    private fun setViewAndDetect(bitmap: Bitmap) {\n        // Display the captured image\n        inputImageView.setImageBitmap(bitmap)\n        tvPlaceholder.visibility = View.INVISIBLE\n\n        // Run object detection and display the result\n        runObjectDetection(bitmap)\n    }\n\n    /**\n     * getCapturedImage():\n     *     Decodes and crops the captured image from camera.\n     */\n    private fun getCapturedImage(): Bitmap {\n        // Get the dimensions of the View\n        val targetW: Int = inputImageView.width\n        val targetH: Int = inputImageView.height\n\n        val bmOptions = BitmapFactory.Options().apply {\n            // Get the dimensions of the bitmap\n            inJustDecodeBounds = true\n\n            BitmapFactory.decodeFile(currentPhotoPath, this)\n\n            val photoW: Int = outWidth\n            val photoH: Int = outHeight\n\n            // Determine how much to scale down the image\n            val scaleFactor: Int = max(1, min(photoW / targetW, photoH / targetH))\n\n            // Decode the image file into a Bitmap sized to fill the View\n            inJustDecodeBounds = false\n            inSampleSize = scaleFactor\n            inMutable = true\n        }\n        val exifInterface = ExifInterface(currentPhotoPath)\n        val orientation = exifInterface.getAttributeInt(\n            ExifInterface.TAG_ORIENTATION,\n            ExifInterface.ORIENTATION_UNDEFINED\n        )\n\n        val bitmap = BitmapFactory.decodeFile(currentPhotoPath, bmOptions)\n        return when (orientation) {\n            ExifInterface.ORIENTATION_ROTATE_90 -> {\n                rotateImage(bitmap, 90f)\n            }\n            ExifInterface.ORIENTATION_ROTATE_180 -> {\n                rotateImage(bitmap, 180f)\n            }\n            ExifInterface.ORIENTATION_ROTATE_270 -> {\n                rotateImage(bitmap, 270f)\n            }\n            else -> {\n                bitmap\n            }\n        }\n    }\n\n    /**\n     * Get image form drawable and convert to bitmap.\n     */\n    private fun getSampleImage(drawable: Int): Bitmap {\n        return BitmapFactory.decodeResource(resources, drawable, BitmapFactory.Options().apply {\n            inMutable = true\n        })\n    }\n\n    /**\n     * Rotate the given bitmap.\n     */\n    private fun rotateImage(source: Bitmap, angle: Float): Bitmap {\n        val matrix = Matrix()\n        matrix.postRotate(angle)\n        return Bitmap.createBitmap(\n            source, 0, 0, source.width, source.height,\n            matrix, true\n        )\n    }\n\n    /**\n     * Create a file to pass to a camera app for storing captured image.\n     */\n    @Throws(IOException::class)\n    private fun createImageFile(): File {\n        // Create an image file name\n        val timeStamp: String = SimpleDateFormat(\"yyyyMMdd_HHmmss\").format(Date())\n        val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)\n        return File.createTempFile(\n            \"JPEG_${timeStamp}_\", /* prefix */\n            \".jpg\", /* suffix */\n            storageDir /* directory */\n        ).apply {\n            // Save a file: path for use with ACTION_VIEW intents\n            currentPhotoPath = absolutePath\n        }\n    }\n\n    /**\n     * Open a camera app to take photo.\n     */\n    private fun dispatchTakePictureIntent() {\n        Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->\n            // Ensure that there's a camera activity to handle the intent\n            takePictureIntent.resolveActivity(packageManager)?.also {\n                // Create the File where the photo should go\n                val photoFile: File? = try {\n                    createImageFile()\n                } catch (e: IOException) {\n                    Log.e(TAG, e.message.toString())\n                    null\n                }\n                // Continue only if the File was successfully created\n                photoFile?.also {\n                    val photoURI: Uri = FileProvider.getUriForFile(\n                        this,\n                        \"com.google.mlkit.codelab.objectdetection.fileprovider\",\n                        it\n                    )\n                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)\n                    startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)\n                }\n            }\n        }\n    }\n\n    /**\n     * Draw bounding boxes around objects together with the object's name.\n     */\n    private fun drawDetectionResult(\n            bitmap: Bitmap,\n            detectionResults: List<BoxWithText>\n    ): Bitmap {\n        val outputBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)\n        val canvas = Canvas(outputBitmap)\n        val pen = Paint()\n        pen.textAlign = Paint.Align.LEFT\n\n        detectionResults.forEach {\n            // draw bounding box\n            pen.color = Color.RED\n            pen.strokeWidth = 8F\n            pen.style = Paint.Style.STROKE\n            val box = it.box\n            canvas.drawRect(box, pen)\n\n            val tagSize = Rect(0, 0, 0, 0)\n\n            // calculate the right font size\n            pen.style = Paint.Style.FILL_AND_STROKE\n            pen.color = Color.YELLOW\n            pen.strokeWidth = 2F\n\n            pen.textSize = MAX_FONT_SIZE\n            pen.getTextBounds(it.text, 0, it.text.length, tagSize)\n            val fontSize: Float = pen.textSize * box.width() / tagSize.width()\n\n            // adjust the font size so texts are inside the bounding box\n            if (fontSize < pen.textSize) pen.textSize = fontSize\n\n            var margin = (box.width() - tagSize.width()) / 2.0F\n            if (margin < 0F) margin = 0F\n            canvas.drawText(\n                it.text, box.left + margin,\n                box.top + tagSize.height().times(1F), pen\n            )\n        }\n        return outputBitmap\n    }\n\n    /**\n     * Print out the object detection result to Logcat.\n     */\n    private fun debugPrint(detectedObjects: List<DetectedObject>) {\n        detectedObjects.forEachIndexed { index, detectedObject ->\n            val box = detectedObject.boundingBox\n\n            Log.d(TAG, \"Detected object: $index\")\n            Log.d(TAG, \" trackingId: ${detectedObject.trackingId}\")\n            Log.d(TAG, \" boundingBox: (${box.left}, ${box.top}) - (${box.right},${box.bottom})\")\n            detectedObject.labels.forEach {\n                Log.d(TAG, \" categories: ${it.text}\")\n                Log.d(TAG, \" confidence: ${it.confidence}\")\n            }\n        }\n    }\n}\n\n/**\n * A general-purpose data class to store detection result for visualization\n */\ndata class BoxWithText(val box: Rect, val text: String)\n"
  },
  {
    "path": "object-detection/final/app/src/main/res/drawable/ic_camera.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24.0\" android:viewportWidth=\"24.0\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#FF000000\" android:pathData=\"M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0\"/>\n    <path android:fillColor=\"#FF000000\" android:pathData=\"M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z\"/>\n</vector>\n"
  },
  {
    "path": "object-detection/final/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#3DDC84\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "object-detection/final/app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path android:pathData=\"M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"85.84757\"\n                android:endY=\"92.4963\"\n                android:startX=\"42.9492\"\n                android:startY=\"49.59793\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>"
  },
  {
    "path": "object-detection/final/app/src/main/res/layout/activity_main.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    android:orientation=\"vertical\"\n    tools:context=\".MainActivity\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_above=\"@+id/tvDescription\">\n\n        <TextView\n            android:id=\"@+id/tvPlaceholder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:text=\"@string/tv_placeholder\"\n            android:textAlignment=\"center\"\n            android:textSize=\"40sp\" />\n\n        <ImageView\n            android:id=\"@+id/imageView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:adjustViewBounds=\"true\"\n            android:contentDescription=\"@null\"\n            android:scaleType=\"fitCenter\" />\n    </FrameLayout>\n\n    <TextView\n        android:id=\"@+id/tvDescription\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_above=\"@id/llSampleImage\"\n        android:layout_marginStart=\"16dp\"\n        android:layout_marginTop=\"10dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:text=\"@string/tv_description\" />\n\n    <LinearLayout\n        android:id=\"@+id/llSampleImage\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_above=\"@+id/captureImageFab\"\n        android:gravity=\"center_horizontal\"\n        android:orientation=\"horizontal\">\n\n        <ImageView\n            android:id=\"@+id/imgSampleOne\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:adjustViewBounds=\"true\"\n            android:contentDescription=\"@null\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/demo_img1\" />\n\n        <ImageView\n            android:id=\"@+id/imgSampleTwo\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:layout_marginStart=\"16dp\"\n            android:layout_marginEnd=\"16dp\"\n            android:adjustViewBounds=\"true\"\n            android:contentDescription=\"@null\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/demo_img2\" />\n\n        <ImageView\n            android:id=\"@+id/imgSampleThree\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:adjustViewBounds=\"true\"\n            android:contentDescription=\"@null\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/demo_img3\" />\n    </LinearLayout>\n\n    <Button\n        android:id=\"@+id/captureImageFab\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_gravity=\"center|bottom\"\n        android:layout_margin=\"16dp\"\n        android:drawableLeft=\"@drawable/ic_camera\"\n        android:text=\"@string/tv_take_photo\"\n        android:textAllCaps=\"false\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "object-detection/final/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "object-detection/final/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "object-detection/final/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"purple_200\">#FFBB86FC</color>\n    <color name=\"purple_500\">#FF6200EE</color>\n    <color name=\"purple_700\">#FF3700B3</color>\n    <color name=\"teal_200\">#FF03DAC5</color>\n    <color name=\"teal_700\">#FF018786</color>\n    <color name=\"black\">#FF000000</color>\n    <color name=\"white\">#FFFFFFFF</color>\n</resources>"
  },
  {
    "path": "object-detection/final/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">Object Detection Codelab</string>\n    <string name=\"tv_take_photo\">Take photo</string>\n    <string name=\"tv_description\">Select a preset image or take a new photo</string>\n    <string name=\"tv_placeholder\">Object detection demo</string>\n</resources>"
  },
  {
    "path": "object-detection/final/app/src/main/res/values/themes.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. -->\n    <style name=\"Theme.ObjectDetection\" parent=\"Theme.MaterialComponents.DayNight.DarkActionBar\">\n        <!-- Primary brand color. -->\n        <item name=\"colorPrimary\">@color/purple_500</item>\n        <item name=\"colorPrimaryVariant\">@color/purple_700</item>\n        <item name=\"colorOnPrimary\">@color/white</item>\n        <!-- Secondary brand color. -->\n        <item name=\"colorSecondary\">@color/teal_200</item>\n        <item name=\"colorSecondaryVariant\">@color/teal_700</item>\n        <item name=\"colorOnSecondary\">@color/black</item>\n        <!-- Status bar color. -->\n        <item name=\"android:statusBarColor\" tools:targetApi=\"l\">?attr/colorPrimaryVariant</item>\n        <!-- Customize your theme here. -->\n    </style>\n</resources>"
  },
  {
    "path": "object-detection/final/app/src/main/res/values-night/themes.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. -->\n    <style name=\"Theme.ObjectDetection\" parent=\"Theme.MaterialComponents.DayNight.DarkActionBar\">\n        <!-- Primary brand color. -->\n        <item name=\"colorPrimary\">@color/purple_200</item>\n        <item name=\"colorPrimaryVariant\">@color/purple_700</item>\n        <item name=\"colorOnPrimary\">@color/black</item>\n        <!-- Secondary brand color. -->\n        <item name=\"colorSecondary\">@color/teal_200</item>\n        <item name=\"colorSecondaryVariant\">@color/teal_200</item>\n        <item name=\"colorOnSecondary\">@color/black</item>\n        <!-- Status bar color. -->\n        <item name=\"android:statusBarColor\" tools:targetApi=\"l\">?attr/colorPrimaryVariant</item>\n        <!-- Customize your theme here. -->\n    </style>\n</resources>"
  },
  {
    "path": "object-detection/final/app/src/main/res/xml/file_paths.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<paths xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <external-files-path name=\"my_images\" path=\"Pictures\" />\n</paths>\n"
  },
  {
    "path": "object-detection/final/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nbuildscript {\n    ext.kotlin_version = \"1.3.72\"\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath \"com.android.tools.build:gradle:4.1.2\"\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}"
  },
  {
    "path": "object-detection/final/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Tue Mar 02 15:07:56 ICT 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-bin.zip\n"
  },
  {
    "path": "object-detection/final/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app\"s APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official"
  },
  {
    "path": "object-detection/final/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\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    which java >/dev/null 2>&1 || 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.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "object-detection/final/gradlew.bat",
    "content": "@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\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\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=\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%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\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 init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\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@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 %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"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\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "object-detection/final/settings.gradle",
    "content": "include ':app'\nrootProject.name = \"MLKit Object Detection Codelab\""
  },
  {
    "path": "object-detection/starter/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\n.idea"
  },
  {
    "path": "object-detection/starter/app/build.gradle",
    "content": "plugins {\n    id 'com.android.application'\n    id 'kotlin-android'\n}\n\nandroid {\n    compileSdkVersion 30\n    buildToolsVersion \"30.0.3\"\n\n    defaultConfig {\n        applicationId \"com.google.mlkit.codelab.objectdetection\"\n        minSdkVersion 23\n        targetSdkVersion 30\n        versionCode 1\n        versionName \"1.0\"\n\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n}\n\ndependencies {\n\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version\"\n    implementation 'androidx.core:core-ktx:1.3.2'\n    implementation 'androidx.appcompat:appcompat:1.2.0'\n    implementation 'com.google.android.material:material:1.3.0'\n    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'\n    implementation 'androidx.exifinterface:exifinterface:1.0.0'\n    testImplementation 'junit:junit:4.+'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.2'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'\n\n    // MLKit\n\n}"
  },
  {
    "path": "object-detection/starter/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "object-detection/starter/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.mlkit.codelab.objectdetection\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/Theme.ObjectDetection\">\n        <activity android:name=\".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>\n\n        <provider\n            android:name=\"androidx.core.content.FileProvider\"\n            android:authorities=\"com.google.mlkit.codelab.objectdetection.fileprovider\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\">\n            <meta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/file_paths\" />\n        </provider>\n    </application>\n\n</manifest>"
  },
  {
    "path": "object-detection/starter/app/src/main/java/com/google/mlkit/codelab/objectdetection/MainActivity.kt",
    "content": "/**\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * 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\npackage com.google.mlkit.codelab.objectdetection\n\nimport android.app.Activity\nimport android.content.ActivityNotFoundException\nimport android.content.Intent\nimport android.graphics.*\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.Environment\nimport android.provider.MediaStore\nimport android.util.Log\nimport android.view.View\nimport android.widget.Button\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.content.FileProvider\nimport androidx.exifinterface.media.ExifInterface\nimport java.io.File\nimport java.io.IOException\nimport java.text.SimpleDateFormat\nimport java.util.*\nimport kotlin.math.max\nimport kotlin.math.min\n\nclass MainActivity : AppCompatActivity(), View.OnClickListener {\n    companion object {\n        const val TAG = \"MLKit-ODT\"\n        const val REQUEST_IMAGE_CAPTURE: Int = 1\n        private const val MAX_FONT_SIZE = 96F\n    }\n\n    private lateinit var captureImageFab: Button\n    private lateinit var inputImageView: ImageView\n    private lateinit var imgSampleOne: ImageView\n    private lateinit var imgSampleTwo: ImageView\n    private lateinit var imgSampleThree: ImageView\n    private lateinit var tvPlaceholder: TextView\n    private lateinit var currentPhotoPath: String\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n\n        captureImageFab = findViewById(R.id.captureImageFab)\n        inputImageView = findViewById(R.id.imageView)\n        imgSampleOne = findViewById(R.id.imgSampleOne)\n        imgSampleTwo = findViewById(R.id.imgSampleTwo)\n        imgSampleThree = findViewById(R.id.imgSampleThree)\n        tvPlaceholder = findViewById(R.id.tvPlaceholder)\n\n        captureImageFab.setOnClickListener(this)\n        imgSampleOne.setOnClickListener(this)\n        imgSampleTwo.setOnClickListener(this)\n        imgSampleThree.setOnClickListener(this)\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        super.onActivityResult(requestCode, resultCode, data)\n        if (requestCode == REQUEST_IMAGE_CAPTURE &&\n            resultCode == Activity.RESULT_OK\n        ) {\n            setViewAndDetect(getCapturedImage())\n        }\n    }\n\n    override fun onClick(v: View?) {\n        when (v?.id) {\n            R.id.captureImageFab -> {\n                try {\n                    dispatchTakePictureIntent()\n                } catch (e: ActivityNotFoundException) {\n                    Log.e(TAG, e.message.toString())\n                }\n            }\n            R.id.imgSampleOne -> {\n                setViewAndDetect(getSampleImage(R.drawable.demo_img1))\n            }\n            R.id.imgSampleTwo -> {\n                setViewAndDetect(getSampleImage(R.drawable.demo_img2))\n            }\n            R.id.imgSampleThree -> {\n                setViewAndDetect(getSampleImage(R.drawable.demo_img3))\n            }\n        }\n    }\n\n    /**\n     * ML Kit Object Detection function. We'll add ML Kit code here in the codelab.\n     */\n    private fun runObjectDetection(bitmap: Bitmap) {\n\n    }\n\n    /**\n     * Set image to view and call object detection\n     */\n    private fun setViewAndDetect(bitmap: Bitmap) {\n        // Display the captured image\n        inputImageView.setImageBitmap(bitmap)\n        tvPlaceholder.visibility = View.INVISIBLE\n\n        // Run object detection and display the result\n        runObjectDetection(bitmap)\n    }\n\n    /**\n     * getCapturedImage():\n     *     Decodes and crops the captured image from camera.\n     */\n    private fun getCapturedImage(): Bitmap {\n        // Get the dimensions of the View\n        val targetW: Int = inputImageView.width\n        val targetH: Int = inputImageView.height\n\n        val bmOptions = BitmapFactory.Options().apply {\n            // Get the dimensions of the bitmap\n            inJustDecodeBounds = true\n\n            BitmapFactory.decodeFile(currentPhotoPath, this)\n\n            val photoW: Int = outWidth\n            val photoH: Int = outHeight\n\n            // Determine how much to scale down the image\n            val scaleFactor: Int = max(1, min(photoW / targetW, photoH / targetH))\n\n            // Decode the image file into a Bitmap sized to fill the View\n            inJustDecodeBounds = false\n            inSampleSize = scaleFactor\n            inMutable = true\n        }\n        val exifInterface = ExifInterface(currentPhotoPath)\n        val orientation = exifInterface.getAttributeInt(\n            ExifInterface.TAG_ORIENTATION,\n            ExifInterface.ORIENTATION_UNDEFINED\n        )\n\n        val bitmap = BitmapFactory.decodeFile(currentPhotoPath, bmOptions)\n        return when (orientation) {\n            ExifInterface.ORIENTATION_ROTATE_90 -> {\n                rotateImage(bitmap, 90f)\n            }\n            ExifInterface.ORIENTATION_ROTATE_180 -> {\n                rotateImage(bitmap, 180f)\n            }\n            ExifInterface.ORIENTATION_ROTATE_270 -> {\n                rotateImage(bitmap, 270f)\n            }\n            else -> {\n                bitmap\n            }\n        }\n    }\n\n    /**\n     * Get image form drawable and convert to bitmap.\n     */\n    private fun getSampleImage(drawable: Int): Bitmap {\n        return BitmapFactory.decodeResource(resources, drawable, BitmapFactory.Options().apply {\n            inMutable = true\n        })\n    }\n\n    /**\n     * Rotate the given bitmap.\n     */\n    private fun rotateImage(source: Bitmap, angle: Float): Bitmap {\n        val matrix = Matrix()\n        matrix.postRotate(angle)\n        return Bitmap.createBitmap(\n            source, 0, 0, source.width, source.height,\n            matrix, true\n        )\n    }\n\n    /**\n     * Create a file to pass to a camera app for storing captured image.\n     */\n    @Throws(IOException::class)\n    private fun createImageFile(): File {\n        // Create an image file name\n        val timeStamp: String = SimpleDateFormat(\"yyyyMMdd_HHmmss\").format(Date())\n        val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)\n        return File.createTempFile(\n            \"JPEG_${timeStamp}_\", /* prefix */\n            \".jpg\", /* suffix */\n            storageDir /* directory */\n        ).apply {\n            // Save a file: path for use with ACTION_VIEW intents\n            currentPhotoPath = absolutePath\n        }\n    }\n\n    /**\n     * Open a camera app to take photo.\n     */\n    private fun dispatchTakePictureIntent() {\n        Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->\n            // Ensure that there's a camera activity to handle the intent\n            takePictureIntent.resolveActivity(packageManager)?.also {\n                // Create the File where the photo should go\n                val photoFile: File? = try {\n                    createImageFile()\n                } catch (e: IOException) {\n                    Log.e(TAG, e.message.toString())\n                    null\n                }\n                // Continue only if the File was successfully created\n                photoFile?.also {\n                    val photoURI: Uri = FileProvider.getUriForFile(\n                        this,\n                        \"com.google.mlkit.codelab.objectdetection.fileprovider\",\n                        it\n                    )\n                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)\n                    startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)\n                }\n            }\n        }\n    }\n\n    /**\n     * Draw bounding boxes around objects together with the object's name.\n     */\n    private fun drawDetectionResult(\n            bitmap: Bitmap,\n            detectionResults: List<BoxWithText>\n    ): Bitmap {\n        val outputBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)\n        val canvas = Canvas(outputBitmap)\n        val pen = Paint()\n        pen.textAlign = Paint.Align.LEFT\n\n        detectionResults.forEach {\n            // draw bounding box\n            pen.color = Color.RED\n            pen.strokeWidth = 8F\n            pen.style = Paint.Style.STROKE\n            val box = it.box\n            canvas.drawRect(box, pen)\n\n            val tagSize = Rect(0, 0, 0, 0)\n\n            // calculate the right font size\n            pen.style = Paint.Style.FILL_AND_STROKE\n            pen.color = Color.YELLOW\n            pen.strokeWidth = 2F\n\n            pen.textSize = MAX_FONT_SIZE\n            pen.getTextBounds(it.text, 0, it.text.length, tagSize)\n            val fontSize: Float = pen.textSize * box.width() / tagSize.width()\n\n            // adjust the font size so texts are inside the bounding box\n            if (fontSize < pen.textSize) pen.textSize = fontSize\n\n            var margin = (box.width() - tagSize.width()) / 2.0F\n            if (margin < 0F) margin = 0F\n            canvas.drawText(\n                it.text, box.left + margin,\n                box.top + tagSize.height().times(1F), pen\n            )\n        }\n        return outputBitmap\n    }\n\n}\n\n/**\n * A general-purpose data class to store detection result for visualization\n */\ndata class BoxWithText(val box: Rect, val text: String)\n"
  },
  {
    "path": "object-detection/starter/app/src/main/res/drawable/ic_camera.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24.0\" android:viewportWidth=\"24.0\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#FF000000\" android:pathData=\"M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0\"/>\n    <path android:fillColor=\"#FF000000\" android:pathData=\"M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z\"/>\n</vector>\n"
  },
  {
    "path": "object-detection/starter/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#3DDC84\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "object-detection/starter/app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path android:pathData=\"M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"85.84757\"\n                android:endY=\"92.4963\"\n                android:startX=\"42.9492\"\n                android:startY=\"49.59793\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>"
  },
  {
    "path": "object-detection/starter/app/src/main/res/layout/activity_main.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    android:orientation=\"vertical\"\n    tools:context=\".MainActivity\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_above=\"@+id/tvDescription\">\n\n        <TextView\n            android:id=\"@+id/tvPlaceholder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:text=\"@string/tv_placeholder\"\n            android:textAlignment=\"center\"\n            android:textSize=\"40sp\" />\n\n        <ImageView\n            android:id=\"@+id/imageView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:adjustViewBounds=\"true\"\n            android:contentDescription=\"@null\"\n            android:scaleType=\"fitCenter\" />\n    </FrameLayout>\n\n    <TextView\n        android:id=\"@+id/tvDescription\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_above=\"@id/llSampleImage\"\n        android:layout_marginStart=\"16dp\"\n        android:layout_marginTop=\"10dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:text=\"@string/tv_description\" />\n\n    <LinearLayout\n        android:id=\"@+id/llSampleImage\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_above=\"@+id/captureImageFab\"\n        android:gravity=\"center_horizontal\"\n        android:orientation=\"horizontal\">\n\n        <ImageView\n            android:id=\"@+id/imgSampleOne\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:adjustViewBounds=\"true\"\n            android:contentDescription=\"@null\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/demo_img1\" />\n\n        <ImageView\n            android:id=\"@+id/imgSampleTwo\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:layout_marginStart=\"16dp\"\n            android:layout_marginEnd=\"16dp\"\n            android:adjustViewBounds=\"true\"\n            android:contentDescription=\"@null\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/demo_img2\" />\n\n        <ImageView\n            android:id=\"@+id/imgSampleThree\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:adjustViewBounds=\"true\"\n            android:contentDescription=\"@null\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/demo_img3\" />\n    </LinearLayout>\n\n    <Button\n        android:id=\"@+id/captureImageFab\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_gravity=\"center|bottom\"\n        android:layout_margin=\"16dp\"\n        android:drawableLeft=\"@drawable/ic_camera\"\n        android:text=\"@string/tv_take_photo\"\n        android:textAllCaps=\"false\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "object-detection/starter/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "object-detection/starter/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "object-detection/starter/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"purple_200\">#FFBB86FC</color>\n    <color name=\"purple_500\">#FF6200EE</color>\n    <color name=\"purple_700\">#FF3700B3</color>\n    <color name=\"teal_200\">#FF03DAC5</color>\n    <color name=\"teal_700\">#FF018786</color>\n    <color name=\"black\">#FF000000</color>\n    <color name=\"white\">#FFFFFFFF</color>\n</resources>"
  },
  {
    "path": "object-detection/starter/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">Object Detection Codelab</string>\n    <string name=\"tv_take_photo\">Take photo</string>\n    <string name=\"tv_description\">Select a preset image or take a new photo</string>\n    <string name=\"tv_placeholder\">Object detection demo</string>\n</resources>"
  },
  {
    "path": "object-detection/starter/app/src/main/res/values/themes.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. -->\n    <style name=\"Theme.ObjectDetection\" parent=\"Theme.MaterialComponents.DayNight.DarkActionBar\">\n        <!-- Primary brand color. -->\n        <item name=\"colorPrimary\">@color/purple_500</item>\n        <item name=\"colorPrimaryVariant\">@color/purple_700</item>\n        <item name=\"colorOnPrimary\">@color/white</item>\n        <!-- Secondary brand color. -->\n        <item name=\"colorSecondary\">@color/teal_200</item>\n        <item name=\"colorSecondaryVariant\">@color/teal_700</item>\n        <item name=\"colorOnSecondary\">@color/black</item>\n        <!-- Status bar color. -->\n        <item name=\"android:statusBarColor\" tools:targetApi=\"l\">?attr/colorPrimaryVariant</item>\n        <!-- Customize your theme here. -->\n    </style>\n</resources>"
  },
  {
    "path": "object-detection/starter/app/src/main/res/values-night/themes.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. -->\n    <style name=\"Theme.ObjectDetection\" parent=\"Theme.MaterialComponents.DayNight.DarkActionBar\">\n        <!-- Primary brand color. -->\n        <item name=\"colorPrimary\">@color/purple_200</item>\n        <item name=\"colorPrimaryVariant\">@color/purple_700</item>\n        <item name=\"colorOnPrimary\">@color/black</item>\n        <!-- Secondary brand color. -->\n        <item name=\"colorSecondary\">@color/teal_200</item>\n        <item name=\"colorSecondaryVariant\">@color/teal_200</item>\n        <item name=\"colorOnSecondary\">@color/black</item>\n        <!-- Status bar color. -->\n        <item name=\"android:statusBarColor\" tools:targetApi=\"l\">?attr/colorPrimaryVariant</item>\n        <!-- Customize your theme here. -->\n    </style>\n</resources>"
  },
  {
    "path": "object-detection/starter/app/src/main/res/xml/file_paths.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<paths xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <external-files-path name=\"my_images\" path=\"Pictures\" />\n</paths>\n"
  },
  {
    "path": "object-detection/starter/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nbuildscript {\n    ext.kotlin_version = \"1.3.72\"\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath \"com.android.tools.build:gradle:4.1.2\"\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}"
  },
  {
    "path": "object-detection/starter/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Tue Mar 02 15:07:56 ICT 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-bin.zip\n"
  },
  {
    "path": "object-detection/starter/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app\"s APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official"
  },
  {
    "path": "object-detection/starter/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\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    which java >/dev/null 2>&1 || 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.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "object-detection/starter/gradlew.bat",
    "content": "@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\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\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=\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%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\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 init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\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@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 %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"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\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "object-detection/starter/settings.gradle",
    "content": "include ':app'\nrootProject.name = \"MLKit Object Detection Codelab\""
  },
  {
    "path": "translate/README.md",
    "content": "# ML Kit Translate Demo with Material Design\n\nThis app demonstrates how to build an end-to-end user experience with [Google ML Kit APIs](https://developers.google.com/ml-kit) and following the new [Material for ML design guidelines](https://material.io/collections/machine-learning/).\n\nThe goal is to make it as easy as possible to integrate ML Kit into your app with an experience that has been user tested:\n\n* Real-time translate using the on-device Text Recognition, Language ID, Translate APIs - an end-to-end solution from text recognition to translate in live camera.\n\n![live_translate](./demo.gif)\n\n\n## Steps to run the app\n\n1. Clone this repo locally\n  ```\n  git clone https://github.com/googlecodelabs/mlkit-android\n  ```\n2. Import the project in the `translate/starter` directory. This is the starter app that doesn't have the ML Kit functionalies implemented yet. You will need to follow the codelab [here](https://codelabs.developers.google.com/codelabs/mlkit-android-translate) in order to build out the app so that it can recognize and translate text.\n3. Alternatively, if you don't want to follow the codelab to build out the app, the completed version of the app can be found [here](https://github.com/googlesamples/mlkit/tree/master/android/translate-showcase).\n3. Build and run it on a physical device (the simulator isn't recommended, as the app needs to use the camera on the device).\n\n## How to use the app\n\nThis app demonstrates live text translate using the camera:\n* Open the app and point the bounding box of the camera at a text of interest. The recognized text and it's detected language will show up on the top part of the bottom sheet.\n* As you keep the camera stable to recognize a text, you'll see the translated version of this text on the bottom in real-time using the on-device Translate API.\n* You can also switch the translate language using the drop down menu.\n\n\n## License\n© Google, 2019. Licensed under an [Apache-2](./LICENSE) license.\n\n"
  },
  {
    "path": "translate/starter/app/build.gradle",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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\napply plugin: 'com.android.application'\n\napply plugin: 'kotlin-android'\n\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 29\n    buildToolsVersion \"29.0.2\"\n    defaultConfig {\n        applicationId \"com.google.mlkit.codelab.translate\"\n        minSdkVersion 21\n        targetSdkVersion 29\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    kotlinOptions {\n        jvmTarget = \"1.8\"\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation\"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n    implementation 'androidx.appcompat:appcompat:1.1.0'\n    implementation 'androidx.core:core-ktx:1.3.0'\n    implementation 'androidx.fragment:fragment-ktx:1.2.4'\n    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'\n    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'\n    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'androidx.test:runner:1.2.0'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'\n\n    // Add CameraX dependencies\n    def camerax_version = \"1.0.0-beta05\"\n    implementation \"androidx.camera:camera-core:${camerax_version}\"\n    implementation \"androidx.camera:camera-camera2:${camerax_version}\"\n    implementation \"androidx.camera:camera-lifecycle:${camerax_version}\"\n    implementation \"androidx.camera:camera-view:1.0.0-alpha12\"\n\n    // Add ML Kit dependencies\n    implementation 'com.google.android.gms:play-services-mlkit-text-recognition:16.0.0'\n    implementation 'com.google.mlkit:language-id:16.0.0'\n    implementation 'com.google.mlkit:translate:16.0.0'\n}\n"
  },
  {
    "path": "translate/starter/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "translate/starter/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF 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<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.mlkit.codelab.translate\">\n\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".MainActivity\" android:screenOrientation=\"portrait\">\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>\n        <!-- Automatically download the text recognition model after app install -->\n        <meta-data\n            android:name=\"com.google.ml.vision.DEPENDENCIES\"\n            android:value=\"ocr\" />\n    </application>\n\n</manifest>"
  },
  {
    "path": "translate/starter/app/src/main/java/com/google/mlkit/codelab/translate/MainActivity.kt",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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\npackage com.google.mlkit.codelab.translate\n\nimport androidx.appcompat.app.AppCompatActivity\nimport android.os.Bundle\nimport com.google.mlkit.codelab.translate.main.MainFragment\n\nclass MainActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.main_activity)\n        if (savedInstanceState == null) {\n            supportFragmentManager.beginTransaction()\n                .replace(R.id.container, MainFragment.newInstance())\n                .commitNow()\n        }\n    }\n\n}\n"
  },
  {
    "path": "translate/starter/app/src/main/java/com/google/mlkit/codelab/translate/analyzer/TextAnalyzer.kt",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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\npackage com.google.mlkit.codelab.translate.analyzer\n\nimport android.content.Context\nimport android.graphics.Rect\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.camera.core.ImageAnalysis\nimport androidx.camera.core.ImageProxy\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.MutableLiveData\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.common.MlKitException\nimport com.google.mlkit.codelab.translate.util.ImageUtils\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.text.Text\nimport com.google.mlkit.vision.text.TextRecognition\nimport java.lang.Exception\n\n/**\n * Analyzes the frames passed in from the camera and returns any detected text within the requested\n * crop region.\n */\nclass TextAnalyzer(\n    private val context: Context,\n    private val lifecycle: Lifecycle,\n    private val result: MutableLiveData<String>,\n    private val imageCropPercentages: MutableLiveData<Pair<Int, Int>>\n) : ImageAnalysis.Analyzer {\n\n    // TODO: Instantiate TextRecognition detector\n\n    // TODO: Add lifecycle observer to properly close ML Kit detectors\n\n    @androidx.camera.core.ExperimentalGetImage\n    override fun analyze(imageProxy: ImageProxy) {\n        val mediaImage = imageProxy.image ?: return\n\n        val rotationDegrees = imageProxy.imageInfo.rotationDegrees\n\n        // We requested a setTargetAspectRatio, but it's not guaranteed that's what the camera\n        // stack is able to support, so we calculate the actual ratio from the first frame to\n        // know how to appropriately crop the image we want to analyze.\n        val imageHeight = mediaImage.height\n        val imageWidth = mediaImage.width\n\n        val actualAspectRatio = imageWidth / imageHeight\n\n        val convertImageToBitmap = ImageUtils.convertYuv420888ImageToBitmap(mediaImage)\n        val cropRect = Rect(0, 0, imageWidth, imageHeight)\n\n        // If the image has a way wider aspect ratio than expected, crop less of the height so we\n        // don't end up cropping too much of the image. If the image has a way taller aspect ratio\n        // than expected, we don't have to make any changes to our cropping so we don't handle it\n        // here.\n        val currentCropPercentages = imageCropPercentages.value ?: return\n        if (actualAspectRatio > 3) {\n            val originalHeightCropPercentage = currentCropPercentages.first\n            val originalWidthCropPercentage = currentCropPercentages.second\n            imageCropPercentages.value =\n                Pair(originalHeightCropPercentage / 2, originalWidthCropPercentage)\n        }\n\n        // If the image is rotated by 90 (or 270) degrees, swap height and width when calculating\n        // the crop.\n        val cropPercentages = imageCropPercentages.value ?: return\n        val heightCropPercent = cropPercentages.first\n        val widthCropPercent = cropPercentages.second\n        val (widthCrop, heightCrop) = when (rotationDegrees) {\n            90, 270 -> Pair(heightCropPercent / 100f, widthCropPercent / 100f)\n            else -> Pair(widthCropPercent / 100f, heightCropPercent / 100f)\n        }\n\n        cropRect.inset(\n            (imageWidth * widthCrop / 2).toInt(),\n            (imageHeight * heightCrop / 2).toInt()\n        )\n        val croppedBitmap =\n            ImageUtils.rotateAndCrop(convertImageToBitmap, rotationDegrees, cropRect)\n\n        // TODO call recognizeText() once implemented\n    }\n\n    fun recognizeText() {\n        // TODO Use ML Kit's TextRecognition to analyze frames from the camera live feed.\n    }\n\n    private fun getErrorMessage(exception: Exception): String? {\n        val mlKitException = exception as? MlKitException ?: return exception.message\n        return if (mlKitException.errorCode == MlKitException.UNAVAILABLE) {\n            \"Waiting for text recognition model to be downloaded\"\n        } else exception.message\n    }\n\n    companion object {\n        private const val TAG = \"TextAnalyzer\"\n    }\n}"
  },
  {
    "path": "translate/starter/app/src/main/java/com/google/mlkit/codelab/translate/main/MainFragment.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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\npackage com.google.mlkit.codelab.translate.main\n\nimport android.Manifest\nimport android.content.pm.PackageManager\nimport android.graphics.*\nimport android.os.Bundle\nimport android.util.DisplayMetrics\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.SurfaceHolder\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.AdapterView\nimport android.widget.ArrayAdapter\nimport android.widget.Toast\nimport androidx.camera.core.*\nimport androidx.camera.core.Camera\nimport androidx.camera.lifecycle.ProcessCameraProvider\nimport androidx.camera.view.PreviewView\nimport androidx.constraintlayout.widget.ConstraintLayout\nimport androidx.core.content.ContextCompat\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.viewModels\nimport androidx.lifecycle.Observer\nimport com.google.mlkit.codelab.translate.R\nimport com.google.mlkit.codelab.translate.analyzer.TextAnalyzer\nimport com.google.mlkit.codelab.translate.util.Language\nimport com.google.mlkit.codelab.translate.util.ScopedExecutor\nimport kotlinx.android.synthetic.main.main_fragment.*\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport kotlin.math.abs\nimport kotlin.math.ln\nimport kotlin.math.max\nimport kotlin.math.min\n\nclass MainFragment : Fragment() {\n\n    companion object {\n        fun newInstance() = MainFragment()\n\n        // We only need to analyze the part of the image that has text, so we set crop percentages\n        // to avoid analyze the entire image from the live camera feed.\n        const val DESIRED_WIDTH_CROP_PERCENT = 8\n        const val DESIRED_HEIGHT_CROP_PERCENT = 74\n\n        // This is an arbitrary number we are using to keep tab of the permission\n        // request. Where an app has multiple context for requesting permission,\n        // this can help differentiate the different contexts\n        private const val REQUEST_CODE_PERMISSIONS = 10\n\n        // This is an array of all the permission specified in the manifest\n        private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)\n        private const val RATIO_4_3_VALUE = 4.0 / 3.0\n        private const val RATIO_16_9_VALUE = 16.0 / 9.0\n        private const val TAG = \"MainFragment\"\n    }\n\n    private var displayId: Int = -1\n    private val viewModel: MainViewModel by viewModels()\n    private var cameraProvider: ProcessCameraProvider? = null\n    private var camera: Camera? = null\n    private var imageAnalyzer: ImageAnalysis? = null\n    private lateinit var container: ConstraintLayout\n    private lateinit var viewFinder: PreviewView\n\n    /** Blocking camera operations are performed using this executor */\n    private lateinit var cameraExecutor: ExecutorService\n\n    private lateinit var scopedExecutor: ScopedExecutor\n\n    override fun onCreateView(\n        inflater: LayoutInflater, container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View {\n        return inflater.inflate(R.layout.main_fragment, container, false)\n    }\n\n    override fun onDestroyView() {\n        super.onDestroyView()\n\n        // Shut down our background executor\n        cameraExecutor.shutdown()\n        scopedExecutor.shutdown()\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n        container = view as ConstraintLayout\n        viewFinder = container.findViewById(R.id.viewfinder)\n\n        // Initialize our background executor\n        cameraExecutor = Executors.newSingleThreadExecutor()\n        scopedExecutor = ScopedExecutor(cameraExecutor)\n\n        // Request camera permissions\n        if (allPermissionsGranted()) {\n            // Wait for the views to be properly laid out\n            viewFinder.post {\n                // Keep track of the display in which this view is attached\n                displayId = viewFinder.display.displayId\n\n                // Set up the camera and its use cases\n                setUpCamera()\n            }\n        } else {\n            requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)\n        }\n\n        // Get available language list and set up the target language spinner\n        // with default selections.\n        val adapter = ArrayAdapter(\n            requireContext(),\n            android.R.layout.simple_spinner_dropdown_item, viewModel.availableLanguages\n        )\n\n        targetLangSelector.adapter = adapter\n        targetLangSelector.setSelection(adapter.getPosition(Language(\"en\")))\n        targetLangSelector.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {\n            override fun onItemSelected(\n                parent: AdapterView<*>,\n                view: View?,\n                position: Int,\n                id: Long\n            ) {\n                viewModel.targetLang.value = adapter.getItem(position)\n            }\n\n            override fun onNothingSelected(parent: AdapterView<*>) {}\n        }\n\n        viewModel.sourceLang.observe(viewLifecycleOwner, Observer { srcLang.text = it.displayName })\n        viewModel.translatedText.observe(viewLifecycleOwner, Observer { resultOrError ->\n            resultOrError?.let {\n                if (it.error != null) {\n                    translatedText.error = resultOrError.error?.localizedMessage\n                } else {\n                    translatedText.text = resultOrError.result\n                }\n            }\n        })\n        viewModel.modelDownloading.observe(viewLifecycleOwner, Observer { isDownloading ->\n            progressBar.visibility = if (isDownloading) {\n                View.VISIBLE\n            } else {\n                View.INVISIBLE\n            }\n            progressText.visibility = progressBar.visibility\n        })\n\n        overlay.apply {\n            setZOrderOnTop(true)\n            holder.setFormat(PixelFormat.TRANSPARENT)\n            holder.addCallback(object : SurfaceHolder.Callback {\n                override fun surfaceChanged(\n                    holder: SurfaceHolder?,\n                    format: Int,\n                    width: Int,\n                    height: Int\n                ) {\n                }\n\n                override fun surfaceDestroyed(holder: SurfaceHolder?) {\n                }\n\n                override fun surfaceCreated(holder: SurfaceHolder?) {\n                    holder?.let { drawOverlay(it, DESIRED_HEIGHT_CROP_PERCENT, DESIRED_WIDTH_CROP_PERCENT) }\n                }\n\n            })\n        }\n    }\n\n\n    /** Initialize CameraX, and prepare to bind the camera use cases  */\n    private fun setUpCamera() {\n        val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())\n        cameraProviderFuture.addListener(Runnable {\n\n            // CameraProvider\n            cameraProvider = cameraProviderFuture.get()\n\n            // Build and bind the camera use cases\n            bindCameraUseCases()\n        }, ContextCompat.getMainExecutor(requireContext()))\n    }\n\n    private fun bindCameraUseCases() {\n        val cameraProvider = cameraProvider\n            ?: throw IllegalStateException(\"Camera initialization failed.\")\n\n        // Get screen metrics used to setup camera for full screen resolution\n        val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }\n        Log.d(TAG, \"Screen metrics: ${metrics.widthPixels} x ${metrics.heightPixels}\")\n\n        val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels)\n        Log.d(TAG, \"Preview aspect ratio: $screenAspectRatio\")\n\n        val rotation = viewFinder.display.rotation\n\n        val preview = Preview.Builder()\n            .setTargetAspectRatio(screenAspectRatio)\n            .setTargetRotation(rotation)\n            .build()\n\n        // Build the image analysis use case and instantiate our analyzer\n        imageAnalyzer = ImageAnalysis.Builder()\n            // We request aspect ratio but no resolution\n            .setTargetAspectRatio(screenAspectRatio)\n            .setTargetRotation(rotation)\n            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)\n            .build()\n            .also {\n                it.setAnalyzer(\n                    cameraExecutor\n                    , TextAnalyzer(\n                        requireContext(),\n                        lifecycle,\n                        viewModel.sourceText,\n                        viewModel.imageCropPercentages\n                    )\n                )\n            }\n        viewModel.sourceText.observe(viewLifecycleOwner, Observer { srcText.text = it })\n        viewModel.imageCropPercentages.observe(viewLifecycleOwner,\n            Observer { drawOverlay(overlay.holder, it.first, it.second) })\n\n        // Select back camera since text detection does not work with front camera\n        val cameraSelector =\n            CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()\n\n        try {\n            // Unbind use cases before rebinding\n            cameraProvider.unbindAll()\n\n            // Bind use cases to camera\n            camera = cameraProvider.bindToLifecycle(\n                this, cameraSelector, preview, imageAnalyzer\n            )\n            preview.setSurfaceProvider(viewFinder.createSurfaceProvider())\n        } catch (exc: IllegalStateException) {\n            Log.e(TAG, \"Use case binding failed. This must be running on main thread.\", exc)\n        }\n    }\n\n    private fun drawOverlay(\n        holder: SurfaceHolder,\n        heightCropPercent: Int,\n        widthCropPercent: Int\n    ) {\n        val canvas = holder.lockCanvas()\n        val bgPaint = Paint().apply {\n            alpha = 140\n        }\n        canvas.drawPaint(bgPaint)\n        val rectPaint = Paint()\n        rectPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)\n        rectPaint.style = Paint.Style.FILL\n        rectPaint.color = Color.WHITE\n        val outlinePaint = Paint()\n        outlinePaint.style = Paint.Style.STROKE\n        outlinePaint.color = Color.WHITE\n        outlinePaint.strokeWidth = 4f\n        val surfaceWidth = holder.surfaceFrame.width()\n        val surfaceHeight = holder.surfaceFrame.height()\n\n        val cornerRadius = 25f\n        // Set rect centered in frame\n        val rectTop = surfaceHeight * heightCropPercent / 2 / 100f\n        val rectLeft = surfaceWidth * widthCropPercent / 2 / 100f\n        val rectRight = surfaceWidth * (1 - widthCropPercent / 2 / 100f)\n        val rectBottom = surfaceHeight * (1 - heightCropPercent / 2 / 100f)\n        val rect = RectF(rectLeft, rectTop, rectRight, rectBottom)\n        canvas.drawRoundRect(\n            rect, cornerRadius, cornerRadius, rectPaint\n        )\n        canvas.drawRoundRect(\n            rect, cornerRadius, cornerRadius, outlinePaint\n        )\n        val textPaint = Paint()\n        textPaint.color = Color.WHITE\n        textPaint.textSize = 50F\n\n        val overlayText = getString(R.string.overlay_help)\n        val textBounds = Rect()\n        textPaint.getTextBounds(overlayText, 0, overlayText.length, textBounds)\n        val textX = (surfaceWidth - textBounds.width()) / 2f\n        val textY = rectBottom + textBounds.height() + 15f // put text below rect and 15f padding\n        canvas.drawText(getString(R.string.overlay_help), textX, textY, textPaint)\n        holder.unlockCanvasAndPost(canvas)\n    }\n\n    /**\n     *  [androidx.camera.core.ImageAnalysisConfig] requires enum value of\n     *  [androidx.camera.core.AspectRatio]. Currently it has values of 4:3 & 16:9.\n     *\n     *  Detecting the most suitable ratio for dimensions provided in @params by comparing absolute\n     *  of preview ratio to one of the provided values.\n     *\n     *  @param width - preview width\n     *  @param height - preview height\n     *  @return suitable aspect ratio\n     */\n    private fun aspectRatio(width: Int, height: Int): Int {\n        val previewRatio = ln(max(width, height).toDouble() / min(width, height))\n        if (abs(previewRatio - ln(RATIO_4_3_VALUE))\n            <= abs(previewRatio - ln(RATIO_16_9_VALUE))\n        ) {\n            return AspectRatio.RATIO_4_3\n        }\n        return AspectRatio.RATIO_16_9\n    }\n\n    /**\n     * Process result from permission request dialog box, has the request\n     * been granted? If yes, start Camera. Otherwise display a toast\n     */\n    override fun onRequestPermissionsResult(\n        requestCode: Int, permissions: Array<String>, grantResults: IntArray\n    ) {\n        if (requestCode == REQUEST_CODE_PERMISSIONS) {\n            if (allPermissionsGranted()) {\n                viewFinder.post {\n                    // Keep track of the display in which this view is attached\n                    displayId = viewFinder.display.displayId\n\n                    // Set up the camera and its use cases\n                    setUpCamera()\n                }\n            } else {\n                Toast.makeText(\n                    context,\n                    \"Permissions not granted by the user.\",\n                    Toast.LENGTH_SHORT\n                ).show()\n            }\n        }\n    }\n\n    /**\n     * Check if all permission specified in the manifest have been granted\n     */\n    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {\n        ContextCompat.checkSelfPermission(\n            requireContext(), it\n        ) == PackageManager.PERMISSION_GRANTED\n    }\n}\n"
  },
  {
    "path": "translate/starter/app/src/main/java/com/google/mlkit/codelab/translate/main/MainViewModel.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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\npackage com.google.mlkit.codelab.translate.main\n\nimport android.app.Application\nimport android.os.Handler\nimport android.util.LruCache\nimport androidx.lifecycle.AndroidViewModel\nimport androidx.lifecycle.MediatorLiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.Transformations\nimport com.google.android.gms.tasks.OnCompleteListener\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.Tasks\nimport com.google.mlkit.codelab.translate.util.Language\nimport com.google.mlkit.codelab.translate.util.ResultOrError\nimport com.google.mlkit.codelab.translate.util.SmoothedMutableLiveData\nimport com.google.mlkit.nl.languageid.LanguageIdentification\nimport com.google.mlkit.nl.translate.TranslateLanguage\nimport com.google.mlkit.nl.translate.Translation\nimport com.google.mlkit.nl.translate.Translator\nimport com.google.mlkit.nl.translate.TranslatorOptions\nimport com.google.mlkit.codelab.translate.main.MainFragment.Companion.DESIRED_HEIGHT_CROP_PERCENT\nimport com.google.mlkit.codelab.translate.main.MainFragment.Companion.DESIRED_WIDTH_CROP_PERCENT\n\nclass MainViewModel(application: Application) : AndroidViewModel(application) {\n\n    // TODO Instantiate LanguageIdentification\n    val targetLang = MutableLiveData<Language>()\n    val sourceText = SmoothedMutableLiveData<String>(SMOOTHING_DURATION)\n\n    // We set desired crop percentages to avoid having to analyze the whole image from the live\n    // camera feed. However, we are not guaranteed what aspect ratio we will get from the camera, so\n    // we use the first frame we get back from the camera to update these crop percentages based on\n    // the actual aspect ratio of images.\n    val imageCropPercentages = MutableLiveData<Pair<Int, Int>>()\n        .apply { value = Pair(DESIRED_HEIGHT_CROP_PERCENT, DESIRED_WIDTH_CROP_PERCENT) }\n    val translatedText = MediatorLiveData<ResultOrError>()\n    private val translating = MutableLiveData<Boolean>()\n    val modelDownloading = SmoothedMutableLiveData<Boolean>(SMOOTHING_DURATION)\n\n    private var modelDownloadTask: Task<Void> = Tasks.forCanceled()\n\n    private val translators =\n        object : LruCache<TranslatorOptions, Translator>(NUM_TRANSLATORS) {\n            override fun create(options: TranslatorOptions): Translator {\n                return Translation.getClient(options)\n            }\n\n            override fun entryRemoved(\n                evicted: Boolean,\n                key: TranslatorOptions,\n                oldValue: Translator,\n                newValue: Translator?\n            ) {\n                oldValue.close()\n            }\n        }\n\n    val sourceLang = Transformations.switchMap(sourceText) { text ->\n        val result = MutableLiveData<Language>()\n        // TODO  Call the language identification method and assigns the result if it is not\n        //  undefined (“und”)\n        result\n    }\n\n    override fun onCleared() {\n        // TODO Shut down ML Kit clients.\n    }\n\n    private fun translate(): Task<String> {\n        // TODO Take the source language value, target language value, and the source text and\n        //  perform the translation.\n        //  If the chosen target language model has not been downloaded to the device yet,\n        //  call downloadModelIfNeeded() and then proceed with the translation.\n        return Tasks.forResult(\"\") // replace this with your code\n    }\n\n    // Gets a list of all available translation languages.\n    val availableLanguages: List<Language> = TranslateLanguage.getAllLanguages()\n        .map { Language(it) }\n\n    init {\n        modelDownloading.setValue(false)\n        translating.value = false\n        // Create a translation result or error object.\n        val processTranslation =\n            OnCompleteListener<String> { task ->\n                if (task.isSuccessful) {\n                    translatedText.value = ResultOrError(task.result, null)\n                } else {\n                    if (task.isCanceled) {\n                        // Tasks are cancelled for reasons such as gating; ignore.\n                        return@OnCompleteListener\n                    }\n                    translatedText.value = ResultOrError(null, task.exception)\n                }\n            }\n        // Start translation if any of the following change: detected text, source lang, target lang.\n        translatedText.addSource(sourceText) { translate().addOnCompleteListener(processTranslation) }\n        translatedText.addSource(sourceLang) { translate().addOnCompleteListener(processTranslation) }\n        translatedText.addSource(targetLang) { translate().addOnCompleteListener(processTranslation) }\n    }\n\n    companion object {\n        // Amount of time (in milliseconds) to wait for detected text to settle\n        private const val SMOOTHING_DURATION = 50L\n\n        private const val NUM_TRANSLATORS = 1\n    }\n}\n"
  },
  {
    "path": "translate/starter/app/src/main/java/com/google/mlkit/codelab/translate/util/ImageUtils.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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\npackage com.google.mlkit.codelab.translate.util\n\nimport android.graphics.Bitmap\nimport android.graphics.ImageFormat\nimport android.graphics.Matrix\nimport android.graphics.Rect\nimport android.media.Image\nimport androidx.annotation.ColorInt\n\n/**\n * Utility class for manipulating images.\n */\nobject ImageUtils {\n    private val CHANNEL_RANGE = 0 until (1 shl 18)\n\n    fun convertYuv420888ImageToBitmap(image: Image): Bitmap {\n        require(image.format == ImageFormat.YUV_420_888) {\n            \"Unsupported image format $(image.format)\"\n        }\n\n        val planes = image.planes\n\n        // Because of the variable row stride it's not possible to know in\n        // advance the actual necessary dimensions of the yuv planes.\n        val yuvBytes = planes.map { plane ->\n            val buffer = plane.buffer\n            val yuvBytes = ByteArray(buffer.capacity())\n            buffer[yuvBytes]\n            buffer.rewind()  // Be kind…\n            yuvBytes\n        }\n\n        val yRowStride = planes[0].rowStride\n        val uvRowStride = planes[1].rowStride\n        val uvPixelStride = planes[1].pixelStride\n        val width = image.width\n        val height = image.height\n        @ColorInt val argb8888 = IntArray(width * height)\n        var i = 0\n        for (y in 0 until height) {\n            val pY = yRowStride * y\n            val uvRowStart = uvRowStride * (y shr 1)\n            for (x in 0 until width) {\n                val uvOffset = (x shr 1) * uvPixelStride\n                argb8888[i++] =\n                    yuvToRgb(\n                        yuvBytes[0][pY + x].toIntUnsigned(),\n                        yuvBytes[1][uvRowStart + uvOffset].toIntUnsigned(),\n                        yuvBytes[2][uvRowStart + uvOffset].toIntUnsigned()\n                    )\n            }\n        }\n        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)\n        bitmap.setPixels(argb8888, 0, width, 0, 0, width, height)\n        return bitmap\n    }\n\n    fun rotateAndCrop(\n        bitmap: Bitmap,\n        imageRotationDegrees: Int,\n        cropRect: Rect\n    ): Bitmap {\n        val matrix = Matrix()\n        matrix.preRotate(imageRotationDegrees.toFloat())\n        return Bitmap.createBitmap(\n            bitmap,\n            cropRect.left,\n            cropRect.top,\n            cropRect.width(),\n            cropRect.height(),\n            matrix,\n            true\n        )\n    }\n\n    @ColorInt\n    private fun yuvToRgb(nY: Int, nU: Int, nV: Int): Int {\n        var nY = nY\n        var nU = nU\n        var nV = nV\n        nY -= 16\n        nU -= 128\n        nV -= 128\n        nY = nY.coerceAtLeast(0)\n\n        // This is the floating point equivalent. We do the conversion in integer\n        // because some Android devices do not have floating point in hardware.\n        // nR = (int)(1.164 * nY + 2.018 * nU);\n        // nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);\n        // nB = (int)(1.164 * nY + 1.596 * nV);\n        var nR = 1192 * nY + 1634 * nV\n        var nG = 1192 * nY - 833 * nV - 400 * nU\n        var nB = 1192 * nY + 2066 * nU\n\n        // Clamp the values before normalizing them to 8 bits.\n        nR = nR.coerceIn(CHANNEL_RANGE) shr 10 and 0xff\n        nG = nG.coerceIn(CHANNEL_RANGE) shr 10 and 0xff\n        nB = nB.coerceIn(CHANNEL_RANGE) shr 10 and 0xff\n        return -0x1000000 or (nR shl 16) or (nG shl 8) or nB\n    }\n}\n\nprivate fun Byte.toIntUnsigned(): Int {\n    return toInt() and 0xFF\n}\n"
  },
  {
    "path": "translate/starter/app/src/main/java/com/google/mlkit/codelab/translate/util/Language.kt",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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\npackage com.google.mlkit.codelab.translate.util\n\nimport java.util.*\n\n/**\n * Holds the language code (i.e. \"en\") and the corresponding localized full language name\n * (i.e. \"English\")\n */\nclass Language(val code: String) : Comparable<Language> {\n\n    val displayName: String\n        get() = Locale(code).displayName\n\n    override fun equals(other: Any?): Boolean {\n        if (other === this) {\n            return true\n        }\n\n        if (other !is Language) {\n            return false\n        }\n\n        val otherLang = other as Language?\n        return otherLang!!.code == code\n    }\n\n    override fun toString(): String {\n        return displayName\n    }\n\n    override fun compareTo(other: Language): Int {\n        return this.displayName.compareTo(other.displayName)\n    }\n\n    override fun hashCode(): Int {\n        return code.hashCode()\n    }\n}\n"
  },
  {
    "path": "translate/starter/app/src/main/java/com/google/mlkit/codelab/translate/util/ResultOrError.kt",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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\npackage com.google.mlkit.codelab.translate.util\n\n/**\n * Holds a result or some operation or the exception.\n */\nclass ResultOrError(var result: String?, var error: Exception?)\n"
  },
  {
    "path": "translate/starter/app/src/main/java/com/google/mlkit/codelab/translate/util/ScopedExecutor.kt",
    "content": "package com.google.mlkit.codelab.translate.util\n\nimport java.util.concurrent.Executor\nimport java.util.concurrent.atomic.AtomicBoolean\n\nclass ScopedExecutor(private val executor: Executor) : Executor {\n\n    private val isShutdown = AtomicBoolean()\n\n    fun shutdown() {\n        isShutdown.set(true)\n    }\n\n    override fun execute(command: Runnable) {\n        executor.execute {\n            if (!isShutdown.get()) command.run()\n        }\n    }\n}"
  },
  {
    "path": "translate/starter/app/src/main/java/com/google/mlkit/codelab/translate/util/SmoothedMutableLiveData.kt",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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\npackage com.google.mlkit.codelab.translate.util\n\nimport android.os.Handler\nimport androidx.lifecycle.MutableLiveData\n\n/**\n * A {@link MutableLiveData} that only emits change events when the underlying data has been stable\n * for the configured amount of time.\n *\n * @param duration time delay to wait in milliseconds\n */\nclass SmoothedMutableLiveData<T>(private val duration: Long) : MutableLiveData<T>() {\n    private var pendingValue: T? = null\n    private val runnable = Runnable {\n        super.setValue(pendingValue)\n    }\n\n    override fun setValue(value: T) {\n        if (value != pendingValue) {\n            pendingValue = value\n            Handler().removeCallbacks(runnable)\n            Handler().postDelayed(runnable, duration)\n        }\n    }\n}\n"
  },
  {
    "path": "translate/starter/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF 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<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#008577\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "translate/starter/app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF 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<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>\n"
  },
  {
    "path": "translate/starter/app/src/main/res/layout/main_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF 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<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".MainActivity\" />\n"
  },
  {
    "path": "translate/starter/app/src/main/res/layout/main_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2020 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF 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<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:id=\"@+id/main\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.google.mlkit.showcase.translate.main.MainFragment\">\n\n    <androidx.camera.view.PreviewView\n        android:id=\"@+id/viewfinder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintBottom_toTopOf=\"@id/middle\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n    <SurfaceView\n        android:id=\"@+id/overlay\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        app:layout_constraintStart_toStartOf=\"@id/viewfinder\"\n        app:layout_constraintEnd_toEndOf=\"@id/viewfinder\"\n        app:layout_constraintBottom_toBottomOf=\"@id/viewfinder\"\n        app:layout_constraintTop_toTopOf=\"@id/viewfinder\" />\n\n    <androidx.constraintlayout.widget.Guideline\n        android:id=\"@+id/middle\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        app:layout_constraintGuide_percent=\".5\" />\n\n    <TextView\n        android:id=\"@+id/srcLang\"\n        style=\"@style/SrcLangText\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"20dp\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginEnd=\"20dp\"\n        android:layout_marginBottom=\"4dp\"\n        app:layout_constraintBottom_toTopOf=\"@+id/srcTextScrollView\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/middle\"\n        tools:text=\"source lang\" />\n\n    <ScrollView\n        android:id=\"@+id/srcTextScrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"100dp\"\n        android:layout_marginBottom=\"4dp\"\n        android:fillViewport=\"true\"\n        android:scrollbars=\"vertical\"\n        app:layout_constraintBottom_toTopOf=\"@+id/divider\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/srcLang\">\n\n        <TextView\n            android:id=\"@+id/srcText\"\n            style=\"@style/SrcText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"20dp\"\n            android:layout_marginEnd=\"20dp\"\n            tools:text=\"source text\" />\n    </ScrollView>\n\n    <View\n        android:id=\"@+id/divider\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_marginStart=\"20dp\"\n        android:layout_marginEnd=\"20dp\"\n        android:background=\"?android:attr/listDivider\"\n        app:layout_constraintBottom_toTopOf=\"@+id/targetLangSelector\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/srcTextScrollView\" />\n\n    <Spinner\n        android:id=\"@+id/targetLangSelector\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"20dp\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/divider\" />\n\n    <ScrollView\n        android:id=\"@+id/translatedTextScrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"100dp\"\n        android:layout_marginBottom=\"4dp\"\n        android:fillViewport=\"true\"\n        android:scrollbars=\"vertical\"\n        app:layout_constraintBottom_toTopOf=\"@+id/divider2\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/targetLangSelector\">\n\n        <TextView\n            android:id=\"@+id/translatedText\"\n            style=\"@style/TranslatedText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"20dp\"\n            android:layout_marginEnd=\"20dp\"\n            android:layout_marginBottom=\"4dp\"\n            tools:text=\"translated text\" />\n    </ScrollView>\n\n    <View\n        android:id=\"@+id/divider2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_marginStart=\"20dp\"\n        android:layout_marginTop=\"4dp\"\n        android:layout_marginEnd=\"20dp\"\n        android:layout_marginBottom=\"4dp\"\n        android:background=\"?android:attr/listDivider\"\n        app:layout_constraintBottom_toTopOf=\"@id/imageView\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/translatedTextScrollView\" />\n\n    <ImageView\n        android:id=\"@+id/imageView\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"18dp\"\n        android:layout_marginStart=\"4dp\"\n        android:layout_marginTop=\"4dp\"\n        android:layout_marginEnd=\"4dp\"\n        android:layout_marginBottom=\"4dp\"\n        android:contentDescription=\"@string/content_description_google_translate_attribution\"\n        android:scaleType=\"fitCenter\"\n        android:src=\"@drawable/greyscale_regular_3x\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/divider2\" />\n\n    <ProgressBar\n        android:id=\"@+id/progressBar\"\n        style=\"?android:attr/progressBarStyle\"\n        android:layout_width=\"30dp\"\n        android:layout_height=\"30dp\"\n        android:visibility=\"invisible\"\n        app:layout_constraintStart_toEndOf=\"@+id/targetLangSelector\"\n        app:layout_constraintTop_toTopOf=\"@id/targetLangSelector\"\n        app:layout_constraintBottom_toBottomOf=\"@id/targetLangSelector\" />\n\n    <TextView\n        android:id=\"@+id/progressText\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:text=\"@string/downloading_model_files\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toEndOf=\"@+id/progressBar\"\n        app:layout_constraintBottom_toBottomOf=\"@id/progressBar\"\n        android:gravity=\"center_vertical\"\n        app:layout_constraintTop_toTopOf=\"@id/progressBar\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "translate/starter/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF 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<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "translate/starter/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF 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<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "translate/starter/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF 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<resources>\n    <color name=\"colorPrimary\">#008577</color>\n    <color name=\"colorPrimaryDark\">#00574B</color>\n    <color name=\"colorAccent\">#D81B60</color>\n</resources>\n"
  },
  {
    "path": "translate/starter/app/src/main/res/values/strings.xml",
    "content": "<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF 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<resources>\n    <string name=\"app_name\">ML Kit Translate Codelab</string>\n    <string name=\"unknown_error\">Unknown error occurred.</string>\n    <string name=\"content_description_google_translate_attribution\">Google Translate attribution</string>\n    <string name=\"overlay_help\">Center text in box</string>\n    <string name=\"downloading_model_files\">Downloading model files...</string>\n</resources>\n"
  },
  {
    "path": "translate/starter/app/src/main/res/values/styles.xml",
    "content": "<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF 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<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n    <style name=\"BaseText\">\n        <item name=\"android:fontFamily\">@font/pt_sans</item>\n    </style>\n\n    <style name=\"SrcLangText\" parent=\"BaseText\">\n        <item name=\"android:textSize\">16sp</item>\n        <item name=\"android:textStyle\">bold</item>\n        <item name=\"android:textAllCaps\">true</item>\n        <item name=\"android:textColor\">@android:color/darker_gray</item>\n    </style>\n\n    <style name=\"TranslatedLangText\" parent=\"SrcLangText\">\n        <item name=\"android:textColor\">@android:color/black</item>\n    </style>\n\n    <style name=\"SrcText\" parent=\"BaseText\">\n        <item name=\"android:textSize\">28sp</item>\n        <item name=\"android:textColor\">@android:color/darker_gray</item>\n    </style>\n\n    <style name=\"TranslatedText\" parent=\"BaseText\">\n        <item name=\"android:textSize\">38sp</item>\n        <item name=\"android:textColor\">@android:color/black</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "translate/starter/build.gradle",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = '1.3.50'\n    repositories {\n        google()\n        jcenter()\n\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.5.0'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "translate/starter/gradle/wrapper/gradle-wrapper.properties",
    "content": "#\n# Copyright 2019 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF 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#Wed Sep 18 03:11:32 EDT 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.4.1-all.zip\n"
  },
  {
    "path": "translate/starter/gradle.properties",
    "content": "#\n# Copyright 2019 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF 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# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official\n"
  },
  {
    "path": "translate/starter/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\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    which java >/dev/null 2>&1 || 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.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "translate/starter/gradlew.bat",
    "content": "@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\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\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=\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%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\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 init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\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@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 %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"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\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "translate/starter/settings.gradle",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF 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\ninclude ':app'\nrootProject.name='ML Kit Translate Codelab'\n"
  },
  {
    "path": "vision/final/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 28\n    defaultConfig {\n        applicationId \"com.google.codelab.mlkit\"\n        minSdkVersion 19\n        targetSdkVersion 28\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    packagingOptions {\n        exclude 'META-INF/androidx.exifinterface_exifinterface.version'\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation 'androidx.appcompat:appcompat:1.1.0'\n    implementation 'androidx.legacy:legacy-support-v4:1.0.0'\n    implementation 'androidx.exifinterface:exifinterface:1.2.0'\n    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'\n    testImplementation 'junit:junit:4.13'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.1'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'\n\n    // Face features\n    implementation 'com.google.mlkit:face-detection:16.0.0'\n\n    // Text features\n    implementation 'com.google.android.gms:play-services-mlkit-text-recognition:16.0.0'\n}\n"
  },
  {
    "path": "vision/final/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "vision/final/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.codelab.mlkit\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"\n        android:maxSdkVersion=\"18\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"\n        android:maxSdkVersion=\"18\" />\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".MainActivity\"\n            android:screenOrientation=\"portrait\"\n            android:configChanges=\"keyboardHidden|orientation|screenSize\">\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>\n    </application>\n\n</manifest>"
  },
  {
    "path": "vision/final/app/src/main/java/com/google/codelab/mlkit/FaceContourGraphic.java",
    "content": "package com.google.codelab.mlkit;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.PointF;\n\nimport com.google.mlkit.vision.face.Face;\nimport com.google.mlkit.vision.face.FaceContour;\nimport com.google.mlkit.vision.face.FaceLandmark;\n\nimport java.util.List;\n\n/** Graphic instance for rendering face contours graphic overlay view. */\npublic class FaceContourGraphic extends GraphicOverlay.Graphic {\n\n  private static final float FACE_POSITION_RADIUS = 10.0f;\n  private static final float ID_TEXT_SIZE = 70.0f;\n  private static final float ID_Y_OFFSET = 80.0f;\n  private static final float ID_X_OFFSET = -70.0f;\n  private static final float BOX_STROKE_WIDTH = 5.0f;\n\n  private static final int[] COLOR_CHOICES = {\n    Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.RED, Color.WHITE, Color.YELLOW\n  };\n  private static int currentColorIndex = 0;\n\n  private final Paint facePositionPaint;\n  private final Paint idPaint;\n  private final Paint boxPaint;\n\n  private volatile Face face;\n\n  public FaceContourGraphic(GraphicOverlay overlay) {\n    super(overlay);\n\n    currentColorIndex = (currentColorIndex + 1) % COLOR_CHOICES.length;\n    final int selectedColor = COLOR_CHOICES[currentColorIndex];\n\n    facePositionPaint = new Paint();\n    facePositionPaint.setColor(selectedColor);\n\n    idPaint = new Paint();\n    idPaint.setColor(selectedColor);\n    idPaint.setTextSize(ID_TEXT_SIZE);\n\n    boxPaint = new Paint();\n    boxPaint.setColor(selectedColor);\n    boxPaint.setStyle(Paint.Style.STROKE);\n    boxPaint.setStrokeWidth(BOX_STROKE_WIDTH);\n  }\n\n  /**\n   * Updates the face instance from the detection of the most recent frame. Invalidates the relevant\n   * portions of the overlay to trigger a redraw.\n   */\n  public void updateFace(Face face) {\n    this.face = face;\n    postInvalidate();\n  }\n\n  /** Draws the face annotations for position on the supplied canvas. */\n  @Override\n  public void draw(Canvas canvas) {\n    Face face = this.face;\n    if (face == null) {\n      return;\n    }\n\n    // Draws a circle at the position of the detected face, with the face's track id below.\n    float x = translateX(face.getBoundingBox().centerX());\n    float y = translateY(face.getBoundingBox().centerY());\n    canvas.drawCircle(x, y, FACE_POSITION_RADIUS, facePositionPaint);\n    canvas.drawText(\"id: \" + face.getTrackingId(), x + ID_X_OFFSET, y + ID_Y_OFFSET, idPaint);\n\n    // Draws a bounding box around the face.\n    float xOffset = scaleX(face.getBoundingBox().width() / 2.0f);\n    float yOffset = scaleY(face.getBoundingBox().height() / 2.0f);\n    float left = x - xOffset;\n    float top = y - yOffset;\n    float right = x + xOffset;\n    float bottom = y + yOffset;\n    canvas.drawRect(left, top, right, bottom, boxPaint);\n\n    List<FaceContour> contour = face.getAllContours();\n    for (FaceContour faceContour : contour) {\n      for (PointF point : faceContour.getPoints()) {\n        float px = translateX(point.x);\n        float py = translateY(point.y);\n        canvas.drawCircle(px, py, FACE_POSITION_RADIUS, facePositionPaint);\n      }\n    }\n\n    if (face.getSmilingProbability() != null) {\n      canvas.drawText(\n          \"happiness: \" + String.format(\"%.2f\", face.getSmilingProbability()),\n          x + ID_X_OFFSET * 3,\n          y - ID_Y_OFFSET,\n          idPaint);\n    }\n\n    if (face.getRightEyeOpenProbability() != null) {\n      canvas.drawText(\n          \"right eye: \" + String.format(\"%.2f\", face.getRightEyeOpenProbability()),\n          x - ID_X_OFFSET,\n          y,\n          idPaint);\n    }\n    if (face.getLeftEyeOpenProbability() != null) {\n      canvas.drawText(\n          \"left eye: \" + String.format(\"%.2f\", face.getLeftEyeOpenProbability()),\n          x + ID_X_OFFSET * 6,\n          y,\n          idPaint);\n    }\n    FaceLandmark leftEye = face.getLandmark(FaceLandmark.LEFT_EYE);\n    if (leftEye != null) {\n      canvas.drawCircle(\n          translateX(leftEye.getPosition().x),\n          translateY(leftEye.getPosition().y),\n          FACE_POSITION_RADIUS,\n          facePositionPaint);\n    }\n    FaceLandmark rightEye = face.getLandmark(FaceLandmark.RIGHT_EYE);\n    if (rightEye != null) {\n      canvas.drawCircle(\n          translateX(rightEye.getPosition().x),\n          translateY(rightEye.getPosition().y),\n          FACE_POSITION_RADIUS,\n          facePositionPaint);\n    }\n\n    FaceLandmark leftCheek = face.getLandmark(FaceLandmark.LEFT_CHEEK);\n    if (leftCheek != null) {\n      canvas.drawCircle(\n          translateX(leftCheek.getPosition().x),\n          translateY(leftCheek.getPosition().y),\n          FACE_POSITION_RADIUS,\n          facePositionPaint);\n    }\n    FaceLandmark rightCheek =\n        face.getLandmark(FaceLandmark.RIGHT_CHEEK);\n    if (rightCheek != null) {\n      canvas.drawCircle(\n          translateX(rightCheek.getPosition().x),\n          translateY(rightCheek.getPosition().y),\n          FACE_POSITION_RADIUS,\n          facePositionPaint);\n    }\n  }\n}\n"
  },
  {
    "path": "vision/final/app/src/main/java/com/google/codelab/mlkit/GraphicOverlay.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\npackage com.google.codelab.mlkit;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * A view which renders a series of custom graphics to be overlayed on top of an associated preview\n * (i.e., the camera preview). The creator can add graphics objects, update the objects, and remove\n * them, triggering the appropriate drawing and invalidation within the view.\n * <p>\n * <p>Supports scaling and mirroring of the graphics relative the camera's preview properties. The\n * idea is that detection items are expressed in terms of a preview size, but need to be scaled up\n * to the full view size, and also mirrored in the case of the front-facing camera.\n * <p>\n * <p>Associated {@link Graphic} items should use the following methods to convert to view\n * coordinates for the graphics that are drawn:\n * <p>\n * <ol>\n * <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the\n * supplied value from the preview scale to the view scale.\n * <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n * coordinate from the preview's coordinate system to the view coordinate system.\n * </ol>\n */\npublic class GraphicOverlay extends View {\n    private final Object lock = new Object();\n    private int previewWidth;\n    private float widthScaleFactor = 1.0f;\n    private int previewHeight;\n    private float heightScaleFactor = 1.0f;\n    private int facing = CameraCharacteristics.LENS_FACING_BACK;\n    private Set<Graphic> graphics = new HashSet<>();\n\n    /**\n     * Base class for a custom graphics object to be rendered within the graphic overlay. Subclass\n     * this and implement the {@link Graphic#draw(Canvas)} method to define the graphics element. Add\n     * instances to the overlay using {@link GraphicOverlay#add(Graphic)}.\n     */\n    public abstract static class Graphic {\n        private GraphicOverlay overlay;\n\n        public Graphic(GraphicOverlay overlay) {\n            this.overlay = overlay;\n        }\n\n        /**\n         * Draw the graphic on the supplied canvas. Drawing should use the following methods to convert\n         * to view coordinates for the graphics that are drawn:\n         * <p>\n         * <ol>\n         * <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the\n         * supplied value from the preview scale to the view scale.\n         * <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n         * coordinate from the preview's coordinate system to the view coordinate system.\n         * </ol>\n         *\n         * @param canvas drawing canvas\n         */\n        public abstract void draw(Canvas canvas);\n\n        /**\n         * Adjusts a horizontal value of the supplied value from the preview scale to the view scale.\n         */\n        public float scaleX(float horizontal) {\n            return horizontal * overlay.widthScaleFactor;\n        }\n\n        /**\n         * Adjusts a vertical value of the supplied value from the preview scale to the view scale.\n         */\n        public float scaleY(float vertical) {\n            return vertical * overlay.heightScaleFactor;\n        }\n\n        /**\n         * Returns the application context of the app.\n         */\n        public Context getApplicationContext() {\n            return overlay.getContext().getApplicationContext();\n        }\n\n        /**\n         * Adjusts the x coordinate from the preview's coordinate system to the view coordinate system.\n         */\n        public float translateX(float x) {\n            if (overlay.facing == CameraCharacteristics.LENS_FACING_FRONT) {\n                return overlay.getWidth() - scaleX(x);\n            } else {\n                return scaleX(x);\n            }\n        }\n\n        /**\n         * Adjusts the y coordinate from the preview's coordinate system to the view coordinate system.\n         */\n        public float translateY(float y) {\n            return scaleY(y);\n        }\n\n        public void postInvalidate() {\n            overlay.postInvalidate();\n        }\n    }\n\n    public GraphicOverlay(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    /**\n     * Removes all graphics from the overlay.\n     */\n    public void clear() {\n        synchronized (lock) {\n            graphics.clear();\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Adds a graphic to the overlay.\n     */\n    public void add(Graphic graphic) {\n        synchronized (lock) {\n            graphics.add(graphic);\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Removes a graphic from the overlay.\n     */\n    public void remove(Graphic graphic) {\n        synchronized (lock) {\n            graphics.remove(graphic);\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Sets the camera attributes for size and facing direction, which informs how to transform image\n     * coordinates later.\n     */\n    public void setCameraInfo(int previewWidth, int previewHeight, int facing) {\n        synchronized (lock) {\n            this.previewWidth = previewWidth;\n            this.previewHeight = previewHeight;\n            this.facing = facing;\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Draws the overlay with its associated graphic objects.\n     */\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n\n        synchronized (lock) {\n            if ((previewWidth != 0) && (previewHeight != 0)) {\n                widthScaleFactor = (float) canvas.getWidth() / (float) previewWidth;\n                heightScaleFactor = (float) canvas.getHeight() / (float) previewHeight;\n            }\n\n            for (Graphic graphic : graphics) {\n                graphic.draw(canvas);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "vision/final/app/src/main/java/com/google/codelab/mlkit/LabelGraphic.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.codelab.mlkit;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.text.TextPaint;\n\nimport java.util.List;\n\n/**\n * Graphic instance for rendering image labels.\n */\npublic class LabelGraphic extends GraphicOverlay.Graphic {\n\n    private final Paint textPaint;\n    private final Paint bgPaint;\n    private final GraphicOverlay overlay;\n\n    private List<String> labels;\n\n    LabelGraphic(GraphicOverlay overlay, List<String> labels) {\n        super(overlay);\n        this.overlay = overlay;\n        this.labels = labels;\n        textPaint = new Paint();\n        textPaint.setColor(Color.WHITE);\n        textPaint.setTextSize(60.0f);\n        bgPaint = new Paint();\n        bgPaint.setColor(Color.BLACK);\n        bgPaint.setAlpha(50);\n    }\n\n    @Override\n    public synchronized void draw(Canvas canvas) {\n        float x = overlay.getWidth() / 4.0f;\n        float y = overlay.getHeight() / 4.0f;\n\n        for (String label : labels) {\n            drawTextWithBackground(label, x, y, new TextPaint(textPaint), bgPaint, canvas);\n            y = y - 62.0f;\n        }\n    }\n\n    private void drawTextWithBackground(String text, float x, float y, TextPaint paint,\n                                        Paint bgPaint, Canvas canvas) {\n        Paint.FontMetrics fontMetrics = paint.getFontMetrics();\n        canvas.drawRect(new Rect((int) (x), (int) (y + fontMetrics.top),\n                (int) (x + paint.measureText(text)), (int) (y + fontMetrics.bottom)), bgPaint);\n        canvas.drawText(text, x, y, textPaint);\n    }\n}\n"
  },
  {
    "path": "vision/final/app/src/main/java/com/google/codelab/mlkit/MainActivity.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.codelab.mlkit;\n\nimport android.content.Context;\nimport android.content.res.AssetManager;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport android.util.Pair;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.Spinner;\nimport android.widget.Toast;\n\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.codelab.mlkit.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.face.Face;\nimport com.google.mlkit.vision.face.FaceDetection;\nimport com.google.mlkit.vision.face.FaceDetector;\nimport com.google.mlkit.vision.face.FaceDetectorOptions;\nimport com.google.mlkit.vision.text.Text;\nimport com.google.mlkit.vision.text.TextRecognition;\nimport com.google.mlkit.vision.text.TextRecognizer;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.PriorityQueue;\n\npublic class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {\n    private static final String TAG = \"MainActivity\";\n    private ImageView mImageView;\n    private Button mTextButton;\n    private Button mFaceButton;\n    private Bitmap mSelectedImage;\n    private GraphicOverlay mGraphicOverlay;\n    // Max width (portrait mode)\n    private Integer mImageMaxWidth;\n    // Max height (portrait mode)\n    private Integer mImageMaxHeight;\n\n    /**\n     * Number of results to show in the UI.\n     */\n    private static final int RESULTS_TO_SHOW = 3;\n    /**\n     * Dimensions of inputs.\n     */\n    private static final int DIM_IMG_SIZE_X = 224;\n    private static final int DIM_IMG_SIZE_Y = 224;\n\n    private final PriorityQueue<Map.Entry<String, Float>> sortedLabels =\n            new PriorityQueue<>(\n                    RESULTS_TO_SHOW,\n                    new Comparator<Map.Entry<String, Float>>() {\n                        @Override\n                        public int compare(Map.Entry<String, Float> o1, Map.Entry<String, Float>\n                                o2) {\n                            return (o1.getValue()).compareTo(o2.getValue());\n                        }\n                    });\n\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        mImageView = findViewById(R.id.image_view);\n\n        mTextButton = findViewById(R.id.button_text);\n        mFaceButton = findViewById(R.id.button_face);\n\n        mGraphicOverlay = findViewById(R.id.graphic_overlay);\n        mTextButton.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                runTextRecognition();\n            }\n        });\n        mFaceButton.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                runFaceContourDetection();\n            }\n        });\n        Spinner dropdown = findViewById(R.id.spinner);\n        String[] items = new String[]{\"Test Image 1 (Text)\", \"Test Image 2 (Face)\"};\n        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout\n                .simple_spinner_dropdown_item, items);\n        dropdown.setAdapter(adapter);\n        dropdown.setOnItemSelectedListener(this);\n    }\n\n    private void runTextRecognition() {\n        InputImage image = InputImage.fromBitmap(mSelectedImage, 0);\n        TextRecognizer recognizer = TextRecognition.getClient();\n        mTextButton.setEnabled(false);\n        recognizer.process(image)\n                .addOnSuccessListener(\n                        new OnSuccessListener<Text>() {\n                            @Override\n                            public void onSuccess(Text texts) {\n                                mTextButton.setEnabled(true);\n                                processTextRecognitionResult(texts);\n                            }\n                        })\n                .addOnFailureListener(\n                        new OnFailureListener() {\n                            @Override\n                            public void onFailure(@NonNull Exception e) {\n                                // Task failed with an exception\n                                mTextButton.setEnabled(true);\n                                e.printStackTrace();\n                            }\n                        });\n    }\n\n    private void processTextRecognitionResult(Text texts) {\n        List<Text.TextBlock> blocks = texts.getTextBlocks();\n        if (blocks.size() == 0) {\n            showToast(\"No text found\");\n            return;\n        }\n        mGraphicOverlay.clear();\n        for (int i = 0; i < blocks.size(); i++) {\n            List<Text.Line> lines = blocks.get(i).getLines();\n            for (int j = 0; j < lines.size(); j++) {\n                List<Text.Element> elements = lines.get(j).getElements();\n                for (int k = 0; k < elements.size(); k++) {\n                    Graphic textGraphic = new TextGraphic(mGraphicOverlay, elements.get(k));\n                    mGraphicOverlay.add(textGraphic);\n\n                }\n            }\n        }\n    }\n\n    private void runFaceContourDetection() {\n        InputImage image = InputImage.fromBitmap(mSelectedImage, 0);\n        FaceDetectorOptions options =\n                new FaceDetectorOptions.Builder()\n                        .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_FAST)\n                        .setContourMode(FaceDetectorOptions.CONTOUR_MODE_ALL)\n                        .build();\n\n        mFaceButton.setEnabled(false);\n        FaceDetector detector = FaceDetection.getClient(options);\n        detector.process(image)\n                .addOnSuccessListener(\n                        new OnSuccessListener<List<Face>>() {\n                            @Override\n                            public void onSuccess(List<Face> faces) {\n                                mFaceButton.setEnabled(true);\n                                processFaceContourDetectionResult(faces);\n                            }\n                        })\n                .addOnFailureListener(\n                        new OnFailureListener() {\n                            @Override\n                            public void onFailure(@NonNull Exception e) {\n                                // Task failed with an exception\n                                mFaceButton.setEnabled(true);\n                                e.printStackTrace();\n                            }\n                        });\n\n    }\n\n    private void processFaceContourDetectionResult(List<Face> faces) {\n        // Task completed successfully\n        if (faces.size() == 0) {\n            showToast(\"No face found\");\n            return;\n        }\n        mGraphicOverlay.clear();\n        for (int i = 0; i < faces.size(); ++i) {\n            Face face = faces.get(i);\n            FaceContourGraphic faceGraphic = new FaceContourGraphic(mGraphicOverlay);\n            mGraphicOverlay.add(faceGraphic);\n            faceGraphic.updateFace(face);\n        }\n    }\n\n    private void showToast(String message) {\n        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();\n    }\n\n    // Functions for loading images from app assets.\n\n    // Returns max image width, always for portrait mode. Caller needs to swap width / height for\n    // landscape mode.\n    private Integer getImageMaxWidth() {\n        if (mImageMaxWidth == null) {\n            // Calculate the max width in portrait mode. This is done lazily since we need to\n            // wait for\n            // a UI layout pass to get the right values. So delay it to first time image\n            // rendering time.\n            mImageMaxWidth = mImageView.getWidth();\n        }\n\n        return mImageMaxWidth;\n    }\n\n    // Returns max image height, always for portrait mode. Caller needs to swap width / height for\n    // landscape mode.\n    private Integer getImageMaxHeight() {\n        if (mImageMaxHeight == null) {\n            // Calculate the max width in portrait mode. This is done lazily since we need to\n            // wait for\n            // a UI layout pass to get the right values. So delay it to first time image\n            // rendering time.\n            mImageMaxHeight =\n                    mImageView.getHeight();\n        }\n\n        return mImageMaxHeight;\n    }\n\n    // Gets the targeted width / height.\n    private Pair<Integer, Integer> getTargetedWidthHeight() {\n        int targetWidth;\n        int targetHeight;\n        int maxWidthForPortraitMode = getImageMaxWidth();\n        int maxHeightForPortraitMode = getImageMaxHeight();\n        targetWidth = maxWidthForPortraitMode;\n        targetHeight = maxHeightForPortraitMode;\n        return new Pair<>(targetWidth, targetHeight);\n    }\n\n    public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {\n        mGraphicOverlay.clear();\n        switch (position) {\n            case 0:\n                mSelectedImage = getBitmapFromAsset(this, \"Please_walk_on_the_grass.jpg\");\n                break;\n            case 1:\n                // Whatever you want to happen when the thrid item gets selected\n                mSelectedImage = getBitmapFromAsset(this, \"grace_hopper.jpg\");\n                break;\n        }\n        if (mSelectedImage != null) {\n            // Get the dimensions of the View\n            Pair<Integer, Integer> targetedSize = getTargetedWidthHeight();\n\n            int targetWidth = targetedSize.first;\n            int maxHeight = targetedSize.second;\n\n            // Determine how much to scale down the image\n            float scaleFactor =\n                    Math.max(\n                            (float) mSelectedImage.getWidth() / (float) targetWidth,\n                            (float) mSelectedImage.getHeight() / (float) maxHeight);\n\n            Bitmap resizedBitmap =\n                    Bitmap.createScaledBitmap(\n                            mSelectedImage,\n                            (int) (mSelectedImage.getWidth() / scaleFactor),\n                            (int) (mSelectedImage.getHeight() / scaleFactor),\n                            true);\n\n            mImageView.setImageBitmap(resizedBitmap);\n            mSelectedImage = resizedBitmap;\n        }\n    }\n\n    @Override\n    public void onNothingSelected(AdapterView<?> parent) {\n        // Do nothing\n    }\n\n    public static Bitmap getBitmapFromAsset(Context context, String filePath) {\n        AssetManager assetManager = context.getAssets();\n\n        InputStream is;\n        Bitmap bitmap = null;\n        try {\n            is = assetManager.open(filePath);\n            bitmap = BitmapFactory.decodeStream(is);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        return bitmap;\n    }\n}\n"
  },
  {
    "path": "vision/final/app/src/main/java/com/google/codelab/mlkit/TextGraphic.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.codelab.mlkit;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport android.util.Log;\n\nimport com.google.codelab.mlkit.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.text.Text;\n\n/**\n * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic\n * overlay view.\n */\npublic class TextGraphic extends Graphic {\n\n    private static final String TAG = \"TextGraphic\";\n    private static final int TEXT_COLOR = Color.RED;\n    private static final float TEXT_SIZE = 54.0f;\n    private static final float STROKE_WIDTH = 4.0f;\n\n    private final Paint rectPaint;\n    private final Paint textPaint;\n    private final Text.Element element;\n\n    TextGraphic(GraphicOverlay overlay, Text.Element element) {\n        super(overlay);\n\n        this.element = element;\n\n        rectPaint = new Paint();\n        rectPaint.setColor(TEXT_COLOR);\n        rectPaint.setStyle(Paint.Style.STROKE);\n        rectPaint.setStrokeWidth(STROKE_WIDTH);\n\n        textPaint = new Paint();\n        textPaint.setColor(TEXT_COLOR);\n        textPaint.setTextSize(TEXT_SIZE);\n        // Redraw the overlay, as this graphic has been added.\n        postInvalidate();\n    }\n\n    /**\n     * Draws the text block annotations for position, size, and raw value on the supplied canvas.\n     */\n    @Override\n    public void draw(Canvas canvas) {\n        Log.d(TAG, \"on draw text graphic\");\n        if (element == null) {\n            throw new IllegalStateException(\"Attempting to draw a null text.\");\n        }\n\n        // Draws the bounding box around the TextBlock.\n        RectF rect = new RectF(element.getBoundingBox());\n        canvas.drawRect(rect, rectPaint);\n\n        // Renders the text at the bottom of the box.\n        canvas.drawText(element.getText(), rect.left, rect.bottom, textPaint);\n    }\n}\n"
  },
  {
    "path": "vision/final/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillColor=\"#26A69A\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n</vector>\n"
  },
  {
    "path": "vision/final/app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\" />\n</vector>\n"
  },
  {
    "path": "vision/final/app/src/main/res/layout/activity_main.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    tools:context=\".MainActivity\">\n\n    <ImageView\n        android:id=\"@+id/image_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"fitStart\"\n        app:layout_constraintTop_toBottomOf=\"parent\"\n        app:layout_constraintBottom_toTopOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        android:contentDescription=\"@string/select_image_for_text_recognition\" />\n    <com.google.codelab.mlkit.GraphicOverlay\n        android:id=\"@+id/graphic_overlay\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        app:layout_constraintTop_toTopOf=\"@id/image_view\"\n        app:layout_constraintBottom_toBottomOf=\"@id/image_view\"\n        app:layout_constraintLeft_toLeftOf=\"@id/image_view\"\n        app:layout_constraintRight_toRightOf=\"@id/image_view\"\n        android:layout_alignParentStart=\"true\" />\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintBottom_toTopOf=\"@id/button_text\"\n        android:background=\"@android:drawable/btn_dropdown\"\n        android:spinnerMode=\"dropdown\"\n        />\n    <Button\n        android:id=\"@+id/button_text\"\n        android:text=\"@string/find_text_button\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"55dp\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toLeftOf=\"@id/button_face\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"/>\n\n    <Button\n        android:id=\"@+id/button_face\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"55dp\"\n        android:text=\"@string/find_face_contour_button\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintLeft_toRightOf=\"@id/button_text\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "vision/final/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "vision/final/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "vision/final/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"texBackgroundColor\">#33000000</color>\n</resources>\n"
  },
  {
    "path": "vision/final/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">ML Kit Codelab</string>\n    <string name=\"select_image_for_text_recognition\">Select image for text recognition</string>\n    <string name=\"find_text_button\">Find text</string>\n    <string name=\"find_face_contour_button\">Find face contour</string>\n    <string name=\"find_text_cloud_button\">Find text (cloud)</string>\n    <string name=\"find_objects_button\">Find objects</string>\n</resources>\n"
  },
  {
    "path": "vision/final/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "vision/final/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n\n    repositories {\n        maven { url rootProject.projectDir.getAbsolutePath() + '/libraries' }\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.4.0'\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        maven { url rootProject.projectDir.getAbsolutePath() + '/libraries' }\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "vision/final/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Fri May 03 10:49:49 EDT 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.1.1-all.zip\n"
  },
  {
    "path": "vision/final/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\nandroid.enableJetifier=true\nandroid.useAndroidX=true\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "vision/final/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\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    which java >/dev/null 2>&1 || 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.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "vision/final/gradlew.bat",
    "content": "@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\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\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=\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%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\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 init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\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@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 %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"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\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "vision/final/settings.gradle",
    "content": "include ':app'\n"
  },
  {
    "path": "vision/starter/app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "vision/starter/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 28\n    defaultConfig {\n        applicationId \"com.google.codelab.mlkit\"\n        minSdkVersion 19\n        targetSdkVersion 28\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    packagingOptions {\n        exclude 'META-INF/androidx.exifinterface_exifinterface.version'\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation 'androidx.appcompat:appcompat:1.1.0'\n    implementation 'androidx.legacy:legacy-support-v4:1.0.0'\n    implementation 'androidx.exifinterface:exifinterface:1.2.0'\n    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'\n    testImplementation 'junit:junit:4.13'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.1'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'\n\n    // Face features\n    implementation 'com.google.mlkit:face-detection:16.0.0'\n\n    // Text features\n    implementation 'com.google.android.gms:play-services-mlkit-text-recognition:16.0.0'\n}\n"
  },
  {
    "path": "vision/starter/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "vision/starter/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.codelab.mlkit\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"\n        android:maxSdkVersion=\"18\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"\n        android:maxSdkVersion=\"18\" />\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".MainActivity\"\n            android:screenOrientation=\"portrait\"\n            android:configChanges=\"keyboardHidden|orientation|screenSize\">\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>\n    </application>\n\n</manifest>"
  },
  {
    "path": "vision/starter/app/src/main/java/com/google/codelab/mlkit/FaceContourGraphic.java",
    "content": "package com.google.codelab.mlkit;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.PointF;\n\nimport com.google.mlkit.vision.face.Face;\nimport com.google.mlkit.vision.face.FaceContour;\nimport com.google.mlkit.vision.face.FaceLandmark;\n\nimport java.util.List;\n\n\n/** Graphic instance for rendering face contours graphic overlay view. */\npublic class FaceContourGraphic extends GraphicOverlay.Graphic {\n\n  private static final float FACE_POSITION_RADIUS = 10.0f;\n  private static final float ID_TEXT_SIZE = 70.0f;\n  private static final float ID_Y_OFFSET = 80.0f;\n  private static final float ID_X_OFFSET = -70.0f;\n  private static final float BOX_STROKE_WIDTH = 5.0f;\n\n  private static final int[] COLOR_CHOICES = {\n          Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.RED, Color.WHITE, Color.YELLOW\n  };\n  private static int currentColorIndex = 0;\n\n  private final Paint facePositionPaint;\n  private final Paint idPaint;\n  private final Paint boxPaint;\n\n  private volatile Face face;\n\n  public FaceContourGraphic(GraphicOverlay overlay) {\n    super(overlay);\n\n    currentColorIndex = (currentColorIndex + 1) % COLOR_CHOICES.length;\n    final int selectedColor = COLOR_CHOICES[currentColorIndex];\n\n    facePositionPaint = new Paint();\n    facePositionPaint.setColor(selectedColor);\n\n    idPaint = new Paint();\n    idPaint.setColor(selectedColor);\n    idPaint.setTextSize(ID_TEXT_SIZE);\n\n    boxPaint = new Paint();\n    boxPaint.setColor(selectedColor);\n    boxPaint.setStyle(Paint.Style.STROKE);\n    boxPaint.setStrokeWidth(BOX_STROKE_WIDTH);\n  }\n\n  /**\n   * Updates the face instance from the detection of the most recent frame. Invalidates the relevant\n   * portions of the overlay to trigger a redraw.\n   */\n  public void updateFace(Face face) {\n    this.face = face;\n    postInvalidate();\n  }\n\n  /** Draws the face annotations for position on the supplied canvas. */\n  @Override\n  public void draw(Canvas canvas) {\n    Face face = this.face;\n    if (face == null) {\n      return;\n    }\n\n    // Draws a circle at the position of the detected face, with the face's track id below.\n    float x = translateX(face.getBoundingBox().centerX());\n    float y = translateY(face.getBoundingBox().centerY());\n    canvas.drawCircle(x, y, FACE_POSITION_RADIUS, facePositionPaint);\n    canvas.drawText(\"id: \" + face.getTrackingId(), x + ID_X_OFFSET, y + ID_Y_OFFSET, idPaint);\n\n    // Draws a bounding box around the face.\n    float xOffset = scaleX(face.getBoundingBox().width() / 2.0f);\n    float yOffset = scaleY(face.getBoundingBox().height() / 2.0f);\n    float left = x - xOffset;\n    float top = y - yOffset;\n    float right = x + xOffset;\n    float bottom = y + yOffset;\n    canvas.drawRect(left, top, right, bottom, boxPaint);\n\n    List<FaceContour> contour = face.getAllContours();\n    for (FaceContour faceContour : contour) {\n      for (PointF point : faceContour.getPoints()) {\n        float px = translateX(point.x);\n        float py = translateY(point.y);\n        canvas.drawCircle(px, py, FACE_POSITION_RADIUS, facePositionPaint);\n      }\n    }\n\n    if (face.getSmilingProbability() != null) {\n      canvas.drawText(\n              \"happiness: \" + String.format(\"%.2f\", face.getSmilingProbability()),\n              x + ID_X_OFFSET * 3,\n              y - ID_Y_OFFSET,\n              idPaint);\n    }\n\n    if (face.getRightEyeOpenProbability() != null) {\n      canvas.drawText(\n              \"right eye: \" + String.format(\"%.2f\", face.getRightEyeOpenProbability()),\n              x - ID_X_OFFSET,\n              y,\n              idPaint);\n    }\n    if (face.getLeftEyeOpenProbability() != null) {\n      canvas.drawText(\n              \"left eye: \" + String.format(\"%.2f\", face.getLeftEyeOpenProbability()),\n              x + ID_X_OFFSET * 6,\n              y,\n              idPaint);\n    }\n    FaceLandmark leftEye = face.getLandmark(FaceLandmark.LEFT_EYE);\n    if (leftEye != null) {\n      canvas.drawCircle(\n              translateX(leftEye.getPosition().x),\n              translateY(leftEye.getPosition().y),\n              FACE_POSITION_RADIUS,\n              facePositionPaint);\n    }\n    FaceLandmark rightEye = face.getLandmark(FaceLandmark.RIGHT_EYE);\n    if (rightEye != null) {\n      canvas.drawCircle(\n              translateX(rightEye.getPosition().x),\n              translateY(rightEye.getPosition().y),\n              FACE_POSITION_RADIUS,\n              facePositionPaint);\n    }\n\n    FaceLandmark leftCheek = face.getLandmark(FaceLandmark.LEFT_CHEEK);\n    if (leftCheek != null) {\n      canvas.drawCircle(\n              translateX(leftCheek.getPosition().x),\n              translateY(leftCheek.getPosition().y),\n              FACE_POSITION_RADIUS,\n              facePositionPaint);\n    }\n    FaceLandmark rightCheek =\n            face.getLandmark(FaceLandmark.RIGHT_CHEEK);\n    if (rightCheek != null) {\n      canvas.drawCircle(\n              translateX(rightCheek.getPosition().x),\n              translateY(rightCheek.getPosition().y),\n              FACE_POSITION_RADIUS,\n              facePositionPaint);\n    }\n  }\n}\n\n"
  },
  {
    "path": "vision/starter/app/src/main/java/com/google/codelab/mlkit/GraphicOverlay.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\npackage com.google.codelab.mlkit;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * A view which renders a series of custom graphics to be overlayed on top of an associated preview\n * (i.e., the camera preview). The creator can add graphics objects, update the objects, and remove\n * them, triggering the appropriate drawing and invalidation within the view.\n * <p>\n * <p>Supports scaling and mirroring of the graphics relative the camera's preview properties. The\n * idea is that detection items are expressed in terms of a preview size, but need to be scaled up\n * to the full view size, and also mirrored in the case of the front-facing camera.\n * <p>\n * <p>Associated {@link Graphic} items should use the following methods to convert to view\n * coordinates for the graphics that are drawn:\n * <p>\n * <ol>\n * <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the\n * supplied value from the preview scale to the view scale.\n * <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n * coordinate from the preview's coordinate system to the view coordinate system.\n * </ol>\n */\npublic class GraphicOverlay extends View {\n    private final Object lock = new Object();\n    private int previewWidth;\n    private float widthScaleFactor = 1.0f;\n    private int previewHeight;\n    private float heightScaleFactor = 1.0f;\n    private int facing = CameraCharacteristics.LENS_FACING_BACK;\n    private Set<Graphic> graphics = new HashSet<>();\n\n    /**\n     * Base class for a custom graphics object to be rendered within the graphic overlay. Subclass\n     * this and implement the {@link Graphic#draw(Canvas)} method to define the graphics element. Add\n     * instances to the overlay using {@link GraphicOverlay#add(Graphic)}.\n     */\n    public abstract static class Graphic {\n        private GraphicOverlay overlay;\n\n        public Graphic(GraphicOverlay overlay) {\n            this.overlay = overlay;\n        }\n\n        /**\n         * Draw the graphic on the supplied canvas. Drawing should use the following methods to convert\n         * to view coordinates for the graphics that are drawn:\n         * <p>\n         * <ol>\n         * <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the\n         * supplied value from the preview scale to the view scale.\n         * <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n         * coordinate from the preview's coordinate system to the view coordinate system.\n         * </ol>\n         *\n         * @param canvas drawing canvas\n         */\n        public abstract void draw(Canvas canvas);\n\n        /**\n         * Adjusts a horizontal value of the supplied value from the preview scale to the view scale.\n         */\n        public float scaleX(float horizontal) {\n            return horizontal * overlay.widthScaleFactor;\n        }\n\n        /**\n         * Adjusts a vertical value of the supplied value from the preview scale to the view scale.\n         */\n        public float scaleY(float vertical) {\n            return vertical * overlay.heightScaleFactor;\n        }\n\n        /**\n         * Returns the application context of the app.\n         */\n        public Context getApplicationContext() {\n            return overlay.getContext().getApplicationContext();\n        }\n\n        /**\n         * Adjusts the x coordinate from the preview's coordinate system to the view coordinate system.\n         */\n        public float translateX(float x) {\n            if (overlay.facing == CameraCharacteristics.LENS_FACING_FRONT) {\n                return overlay.getWidth() - scaleX(x);\n            } else {\n                return scaleX(x);\n            }\n        }\n\n        /**\n         * Adjusts the y coordinate from the preview's coordinate system to the view coordinate system.\n         */\n        public float translateY(float y) {\n            return scaleY(y);\n        }\n\n        public void postInvalidate() {\n            overlay.postInvalidate();\n        }\n    }\n\n    public GraphicOverlay(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    /**\n     * Removes all graphics from the overlay.\n     */\n    public void clear() {\n        synchronized (lock) {\n            graphics.clear();\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Adds a graphic to the overlay.\n     */\n    public void add(Graphic graphic) {\n        synchronized (lock) {\n            graphics.add(graphic);\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Removes a graphic from the overlay.\n     */\n    public void remove(Graphic graphic) {\n        synchronized (lock) {\n            graphics.remove(graphic);\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Sets the camera attributes for size and facing direction, which informs how to transform image\n     * coordinates later.\n     */\n    public void setCameraInfo(int previewWidth, int previewHeight, int facing) {\n        synchronized (lock) {\n            this.previewWidth = previewWidth;\n            this.previewHeight = previewHeight;\n            this.facing = facing;\n        }\n        postInvalidate();\n    }\n\n    /**\n     * Draws the overlay with its associated graphic objects.\n     */\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n\n        synchronized (lock) {\n            if ((previewWidth != 0) && (previewHeight != 0)) {\n                widthScaleFactor = (float) canvas.getWidth() / (float) previewWidth;\n                heightScaleFactor = (float) canvas.getHeight() / (float) previewHeight;\n            }\n\n            for (Graphic graphic : graphics) {\n                graphic.draw(canvas);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "vision/starter/app/src/main/java/com/google/codelab/mlkit/LabelGraphic.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.codelab.mlkit;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.text.TextPaint;\n\nimport java.util.List;\n\n/**\n * Graphic instance for rendering image labels.\n */\npublic class LabelGraphic extends GraphicOverlay.Graphic {\n\n    private final Paint textPaint;\n    private final Paint bgPaint;\n    private final GraphicOverlay overlay;\n\n    private List<String> labels;\n\n    LabelGraphic(GraphicOverlay overlay, List<String> labels) {\n        super(overlay);\n        this.overlay = overlay;\n        this.labels = labels;\n        textPaint = new Paint();\n        textPaint.setColor(Color.WHITE);\n        textPaint.setTextSize(60.0f);\n        bgPaint = new Paint();\n        bgPaint.setColor(Color.BLACK);\n        bgPaint.setAlpha(50);\n    }\n\n    @Override\n    public synchronized void draw(Canvas canvas) {\n        float x = overlay.getWidth() / 4.0f;\n        float y = overlay.getHeight() / 4.0f;\n\n        for (String label : labels) {\n            drawTextWithBackground(label, x, y, new TextPaint(textPaint), bgPaint, canvas);\n            y = y - 62.0f;\n        }\n    }\n\n    private void drawTextWithBackground(String text, float x, float y, TextPaint paint,\n                                        Paint bgPaint, Canvas canvas) {\n        Paint.FontMetrics fontMetrics = paint.getFontMetrics();\n        canvas.drawRect(new Rect((int) (x), (int) (y + fontMetrics.top),\n                (int) (x + paint.measureText(text)), (int) (y + fontMetrics.bottom)), bgPaint);\n        canvas.drawText(text, x, y, textPaint);\n    }\n}\n"
  },
  {
    "path": "vision/starter/app/src/main/java/com/google/codelab/mlkit/MainActivity.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.codelab.mlkit;\n\nimport android.content.Context;\nimport android.content.res.AssetManager;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.os.Bundle;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport android.util.Pair;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.Spinner;\nimport android.widget.Toast;\n\nimport com.google.mlkit.vision.face.Face;\nimport com.google.mlkit.vision.text.Text;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.PriorityQueue;\n\npublic class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {\n    private static final String TAG = \"MainActivity\";\n    private ImageView mImageView;\n    private Button mTextButton;\n    private Button mFaceButton;\n    private Bitmap mSelectedImage;\n    private GraphicOverlay mGraphicOverlay;\n    // Max width (portrait mode)\n    private Integer mImageMaxWidth;\n    // Max height (portrait mode)\n    private Integer mImageMaxHeight;\n\n    /**\n     * Number of results to show in the UI.\n     */\n    private static final int RESULTS_TO_SHOW = 3;\n    /**\n     * Dimensions of inputs.\n     */\n    private static final int DIM_BATCH_SIZE = 1;\n    private static final int DIM_PIXEL_SIZE = 3;\n    private static final int DIM_IMG_SIZE_X = 224;\n    private static final int DIM_IMG_SIZE_Y = 224;\n\n    private final PriorityQueue<Map.Entry<String, Float>> sortedLabels =\n            new PriorityQueue<>(\n                    RESULTS_TO_SHOW,\n                    new Comparator<Map.Entry<String, Float>>() {\n                        @Override\n                        public int compare(Map.Entry<String, Float> o1, Map.Entry<String, Float>\n                                o2) {\n                            return (o1.getValue()).compareTo(o2.getValue());\n                        }\n                    });\n    /* Preallocated buffers for storing image data. */\n    private final int[] intValues = new int[DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y];\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        mImageView = findViewById(R.id.image_view);\n\n        mTextButton = findViewById(R.id.button_text);\n        mFaceButton = findViewById(R.id.button_face);\n\n        mGraphicOverlay = findViewById(R.id.graphic_overlay);\n        mTextButton.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                runTextRecognition();\n            }\n        });\n        mFaceButton.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                runFaceContourDetection();\n            }\n        });\n        Spinner dropdown = findViewById(R.id.spinner);\n        String[] items = new String[]{\"Test Image 1 (Text)\", \"Test Image 2 (Face)\"};\n        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout\n                .simple_spinner_dropdown_item, items);\n        dropdown.setAdapter(adapter);\n        dropdown.setOnItemSelectedListener(this);\n    }\n\n    private void runTextRecognition() {\n        // Replace with code from the codelab to run text recognition.\n    }\n\n    private void processTextRecognitionResult(Text texts) {\n        // Replace with code from the codelab to process the text recognition result.\n    }\n\n    private void runFaceContourDetection() {\n        // Replace with code from the codelab to run face contour detection.\n    }\n\n    private void processFaceContourDetectionResult(List<Face> faces) {\n        // Replace with code from the codelab to process the face contour detection result.\n    }\n\n    private void showToast(String message) {\n        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();\n    }\n\n    // Functions for loading images from app assets.\n\n    // Returns max image width, always for portrait mode. Caller needs to swap width / height for\n    // landscape mode.\n    private Integer getImageMaxWidth() {\n        if (mImageMaxWidth == null) {\n            // Calculate the max width in portrait mode. This is done lazily since we need to\n            // wait for\n            // a UI layout pass to get the right values. So delay it to first time image\n            // rendering time.\n            mImageMaxWidth = mImageView.getWidth();\n        }\n\n        return mImageMaxWidth;\n    }\n\n    // Returns max image height, always for portrait mode. Caller needs to swap width / height for\n    // landscape mode.\n    private Integer getImageMaxHeight() {\n        if (mImageMaxHeight == null) {\n            // Calculate the max width in portrait mode. This is done lazily since we need to\n            // wait for\n            // a UI layout pass to get the right values. So delay it to first time image\n            // rendering time.\n            mImageMaxHeight =\n                    mImageView.getHeight();\n        }\n\n        return mImageMaxHeight;\n    }\n\n    // Gets the targeted width / height.\n    private Pair<Integer, Integer> getTargetedWidthHeight() {\n        int targetWidth;\n        int targetHeight;\n        int maxWidthForPortraitMode = getImageMaxWidth();\n        int maxHeightForPortraitMode = getImageMaxHeight();\n        targetWidth = maxWidthForPortraitMode;\n        targetHeight = maxHeightForPortraitMode;\n        return new Pair<>(targetWidth, targetHeight);\n    }\n\n    public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {\n        mGraphicOverlay.clear();\n        switch (position) {\n            case 0:\n                mSelectedImage = getBitmapFromAsset(this, \"Please_walk_on_the_grass.jpg\");\n                break;\n            case 1:\n                // Whatever you want to happen when the thrid item gets selected\n                mSelectedImage = getBitmapFromAsset(this, \"grace_hopper.jpg\");\n                break;\n        }\n        if (mSelectedImage != null) {\n            // Get the dimensions of the View\n            Pair<Integer, Integer> targetedSize = getTargetedWidthHeight();\n\n            int targetWidth = targetedSize.first;\n            int maxHeight = targetedSize.second;\n\n            // Determine how much to scale down the image\n            float scaleFactor =\n                    Math.max(\n                            (float) mSelectedImage.getWidth() / (float) targetWidth,\n                            (float) mSelectedImage.getHeight() / (float) maxHeight);\n\n            Bitmap resizedBitmap =\n                    Bitmap.createScaledBitmap(\n                            mSelectedImage,\n                            (int) (mSelectedImage.getWidth() / scaleFactor),\n                            (int) (mSelectedImage.getHeight() / scaleFactor),\n                            true);\n\n            mImageView.setImageBitmap(resizedBitmap);\n            mSelectedImage = resizedBitmap;\n        }\n    }\n\n    @Override\n    public void onNothingSelected(AdapterView<?> parent) {\n        // Do nothing\n    }\n\n    public static Bitmap getBitmapFromAsset(Context context, String filePath) {\n        AssetManager assetManager = context.getAssets();\n\n        InputStream is;\n        Bitmap bitmap = null;\n        try {\n            is = assetManager.open(filePath);\n            bitmap = BitmapFactory.decodeStream(is);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        return bitmap;\n    }\n}\n"
  },
  {
    "path": "vision/starter/app/src/main/java/com/google/codelab/mlkit/TextGraphic.java",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS 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.codelab.mlkit;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport android.util.Log;\n\nimport com.google.codelab.mlkit.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.text.Text;\n\n/**\n * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic\n * overlay view.\n */\npublic class TextGraphic extends Graphic {\n\n    private static final String TAG = \"TextGraphic\";\n    private static final int TEXT_COLOR = Color.RED;\n    private static final float TEXT_SIZE = 54.0f;\n    private static final float STROKE_WIDTH = 4.0f;\n\n    private final Paint rectPaint;\n    private final Paint textPaint;\n    private final Text.Element element;\n\n    TextGraphic(GraphicOverlay overlay, Text.Element element) {\n        super(overlay);\n\n        this.element = element;\n\n        rectPaint = new Paint();\n        rectPaint.setColor(TEXT_COLOR);\n        rectPaint.setStyle(Paint.Style.STROKE);\n        rectPaint.setStrokeWidth(STROKE_WIDTH);\n\n        textPaint = new Paint();\n        textPaint.setColor(TEXT_COLOR);\n        textPaint.setTextSize(TEXT_SIZE);\n        // Redraw the overlay, as this graphic has been added.\n        postInvalidate();\n    }\n\n    /**\n     * Draws the text block annotations for position, size, and raw value on the supplied canvas.\n     */\n    @Override\n    public void draw(Canvas canvas) {\n        Log.d(TAG, \"on draw text graphic\");\n        if (element == null) {\n            throw new IllegalStateException(\"Attempting to draw a null text.\");\n        }\n\n        // Draws the bounding box around the TextBlock.\n        RectF rect = new RectF(element.getBoundingBox());\n        canvas.drawRect(rect, rectPaint);\n\n        // Renders the text at the bottom of the box.\n        canvas.drawText(element.getText(), rect.left, rect.bottom, textPaint);\n    }\n}\n"
  },
  {
    "path": "vision/starter/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillColor=\"#26A69A\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n</vector>\n"
  },
  {
    "path": "vision/starter/app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\" />\n</vector>\n"
  },
  {
    "path": "vision/starter/app/src/main/res/layout/activity_main.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    tools:context=\".MainActivity\">\n\n    <ImageView\n        android:id=\"@+id/image_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"fitStart\"\n        app:layout_constraintTop_toBottomOf=\"parent\"\n        app:layout_constraintBottom_toTopOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        android:contentDescription=\"@string/select_image_for_text_recognition\" />\n    <com.google.codelab.mlkit.GraphicOverlay\n        android:id=\"@+id/graphic_overlay\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        app:layout_constraintTop_toTopOf=\"@id/image_view\"\n        app:layout_constraintBottom_toBottomOf=\"@id/image_view\"\n        app:layout_constraintLeft_toLeftOf=\"@id/image_view\"\n        app:layout_constraintRight_toRightOf=\"@id/image_view\"\n        android:layout_alignParentStart=\"true\" />\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintBottom_toTopOf=\"@id/button_text\"\n        android:background=\"@android:drawable/btn_dropdown\"\n        android:spinnerMode=\"dropdown\"\n        />\n    <Button\n        android:id=\"@+id/button_text\"\n        android:text=\"@string/find_text_button\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"55dp\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toLeftOf=\"@id/button_face\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"/>\n\n    <Button\n        android:id=\"@+id/button_face\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"55dp\"\n        android:text=\"@string/find_face_contour_button\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintLeft_toRightOf=\"@id/button_text\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "vision/starter/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "vision/starter/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "vision/starter/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"texBackgroundColor\">#33000000</color>\n</resources>\n"
  },
  {
    "path": "vision/starter/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">ML Kit Codelab</string>\n    <string name=\"select_image_for_text_recognition\">Select image for text recognition</string>\n    <string name=\"find_text_button\">Find text</string>\n    <string name=\"find_face_contour_button\">Find face contour</string>\n    <string name=\"find_text_cloud_button\">Find text (cloud)</string>\n    <string name=\"find_objects_button\">Find objects</string>\n</resources>\n"
  },
  {
    "path": "vision/starter/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "vision/starter/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n\n    repositories {\n        maven { url rootProject.projectDir.getAbsolutePath() + '/libraries' }\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.4.0'\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        maven { url rootProject.projectDir.getAbsolutePath() + '/libraries' }\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "vision/starter/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Fri May 03 11:00:21 EDT 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.1.1-all.zip\n"
  },
  {
    "path": "vision/starter/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\nandroid.enableJetifier=true\nandroid.useAndroidX=true\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "vision/starter/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\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    which java >/dev/null 2>&1 || 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.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "vision/starter/gradlew.bat",
    "content": "@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\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\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=\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%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\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 init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\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@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 %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"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\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "vision/starter/settings.gradle",
    "content": "include ':app'\n"
  }
]