diff --git a/LICENSE b/LICENSE index 98aa4a86f..157c522fc 100644 --- a/LICENSE +++ b/LICENSE @@ -830,6 +830,624 @@ AndroidX annotation library END OF TERMS AND CONDITIONS +******************************************************************************* +Error Prone +******************************************************************************* + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +Guava JDK5 +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +Guava JDK7 +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ******************************************************************************* JSR 305 ******************************************************************************* @@ -862,6 +1480,212 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +******************************************************************************* +JSpecify +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ******************************************************************************* Kotlin ******************************************************************************* @@ -3412,7 +4236,7 @@ program_image_remapper Apache License Version 2.0, January 2004 - https://www.apache.org/licenses/ + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -3604,7 +4428,7 @@ program_image_remapper you may not use this file except in compliance with the License. You may obtain a copy of the License at - https://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/libraries/include/arcore_c_api.h b/libraries/include/arcore_c_api.h index 81ac07253..05b3a3670 100644 --- a/libraries/include/arcore_c_api.h +++ b/libraries/include/arcore_c_api.h @@ -92,8 +92,9 @@ /// Note: These functions only change the type of a pointer; they do not change /// the reference count of the referenced objects. /// -/// Note: There is no runtime checking that casts are correct. Call -/// @c ::ArTrackable_getType beforehand to figure out the correct cast. +/// Note: There is no runtime checking that casts are correct. When downcasting +/// @c ::ArTrackable, call @c ::ArTrackable_getType beforehand to figure out the +/// correct cast. /// @defgroup ArAnchor ArAnchor /// Describes a fixed location and orientation in the real world, representing @@ -127,6 +128,69 @@ /// Provides information about the physical characteristics of the device /// camera. +/// @defgroup ArFuture ArFuture +/// Futures in ARCore. +/// +/// @section future_concept Futures in ARCore +/// +/// Futures represent the eventual completion of an asynchronous +/// operation. A future has one of three states, @c ::ArFutureState, which can +/// be obtained with @c ::ArFuture_getState: +/// +/// - @c #AR_FUTURE_STATE_PENDING - The operation is still pending. The result +/// of the operation isn't available yet and any associated callback hasn't +/// yet been invoked. +/// - @c #AR_FUTURE_STATE_DONE - The operation is complete, and a result is +/// available. +/// - @c #AR_FUTURE_STATE_CANCELLED - The operation has been cancelled. +/// +/// An @c ::ArFuture starts in the @c #AR_FUTURE_STATE_PENDING state and +/// transitions to @c #AR_FUTURE_STATE_DONE upon completion. If the +/// future is cancelled using @c ::ArFuture_cancel, then its state may become @c +/// #AR_FUTURE_STATE_CANCELLED (see @ref future_cancellation +/// "cancelling a future" for caveats). +/// +/// Futures must eventually be released using @c ::ArFuture_release. +/// (@ref ownership "reference type, long-lived"). +/// +/// @section future_results Obtaining results from a Future +/// +/// There are two ways of obtaining results from an @c ::ArFuture: +/// +/// @subsection future_polling Polling a Future +/// +/// When the @c ::ArFuture is created, its @c ::ArFutureState is set to @c +/// #AR_FUTURE_STATE_PENDING. You may poll the future using @c +/// ::ArFuture_getState to query the state of the asynchronous operation. When +/// its state is @c #AR_FUTURE_STATE_DONE, you can obtain the operation's +/// result. The future must eventually be released using @c ::ArFuture_release. +/// +/// @subsection future_callback Using a callback to obtain Future results +/// +/// The operation's result can be reported via a callback. When providing a +/// callback, ARCore will invoke the given function when the operation is +/// complete, unless the future has been cancelled using @c ::ArFuture_cancel. +/// This callback will be invoked on the main +/// thread. +/// +/// When providing a callback, you may provide a +/// @c context, which will be passed as the first parameter to the callback. +/// It is a best practice to free the memory of @c context at the end of the +/// callback and when @c ::ArFuture_cancel successfully cancels the callback. +/// +/// @section future_cancellation Cancelling a Future +/// +/// You can try to cancel an @c ::ArFuture by calling @c ::ArFuture_cancel. +/// Due to multi-threading, it is possible that the cancel operation is not +/// successful. The @c out_was_cancelled parameter indicates if the cancellation +/// was successful. +/// +/// If the cancellation is successful, then any +/// @ref future_callback "associated callback" will never be called. It is a +/// best practice to free context memory +/// provided to the callback, if any. +/// /// @defgroup ArConfig ArConfig /// Session configuration. /// @@ -201,6 +265,16 @@ /// ::ArEarth_getCameraGeospatialPose. /// +/// @defgroup ArSemantics ArSemantics +/// Scene Semantics API. See the +/// Scene +/// Semantics Developer Guide for more information. + +/// @defgroup ArStreetscapeGeometry ArStreetscapeGeometry +/// ARCore Geospatial Streetscape Geometry APIs. See the Streetscape +/// Geometry Developer Guide for additional information. + /// @defgroup ArFrame ArFrame /// Per-frame state. @@ -285,6 +359,11 @@ /// @defgroup ArSession ArSession /// Session management. +/// @defgroup ArMesh ArMesh +/// Represents a polygon mesh describing geometry. +/// +/// Obtained by @c ::ArStreetscapeGeometry_acquireMesh. + /// @defgroup ArTrackable ArTrackable /// Something that can be tracked and that anchors can be attached to. @@ -294,6 +373,30 @@ /// and tracking accuracy. See @c ::ArSession_checkVpsAvailabilityAsync for more /// details. +/// @defgroup ArHostCloudAnchorFuture ArHostCloudAnchorFuture +/// An asynchronous operation for hosting a Cloud Anchor launched by @c +/// ::ArSession_hostCloudAnchorAsync. See the Cloud +/// Anchors developer guide for more information. + +/// @defgroup ArResolveCloudAnchorFuture ArResolveCloudAnchorFuture +/// An asynchronous operation for resolving a Cloud Anchor launched by @c +/// ::ArSession_resolveCloudAnchorAsync. See the Cloud +/// Anchors developer guide for more information. + +/// @defgroup ArResolveAnchorOnTerrainFuture ArResolveAnchorOnTerrainFuture +/// An asynchronous operation for resolving a terrain anchor launched by +/// @c ::ArEarth_resolveAnchorOnTerrainAsync. See the Terrain +/// anchors developer guide for more information. + +/// @defgroup ArResolveAnchorOnRooftopFuture ArResolveAnchorOnRooftopFuture +/// Handle to an async operation launched by @c +/// ::ArEarth_resolveAnchorOnRooftopAsync. See the Rooftop +/// anchors developer guide for more information. + /// @ingroup ArConfig /// An opaque session configuration object (@ref ownership "value type"). /// @@ -517,6 +620,24 @@ typedef struct ArAugmentedImage_ ArAugmentedImage; /// - Release with: @c ::ArTrackable_release typedef struct ArAugmentedFace_ ArAugmentedFace; +/// @ingroup ArStreetscapeGeometry +/// A Streetscape Geometry trackable (@ref ownership "reference type, +/// long-lived"). +/// +/// Defines geometry such as terrain, buildings, or other structures obtained +/// from the Streetscape Geometry API. See the Streetscape +/// Geometry Developer Guide for additional information. +/// +///

Obtained from a call to @c ::ArSession_getAllTrackables +/// and @c ::ArFrame_getUpdatedTrackables when @c ::ArStreetscapeGeometryMode is +/// set to @c #AR_STREETSCAPE_GEOMETRY_MODE_ENABLED and @c ::ArGeospatialMode is +/// set to @c #AR_GEOSPATIAL_MODE_ENABLED. +/// +/// - Trackable type: @c #AR_TRACKABLE_STREETSCAPE_GEOMETRY +/// - Release with: @c ::ArTrackable_release +typedef struct ArStreetscapeGeometry_ ArStreetscapeGeometry; + // Earth. /// @ingroup ArEarth @@ -580,6 +701,13 @@ typedef struct ArAnchor_ ArAnchor; /// - Release with: @c ::ArAnchorList_destroy typedef struct ArAnchorList_ ArAnchorList; +/// @ingroup ArMesh +/// A triangulated mesh representing a surface reconstruction of the scene. +/// (@ref ownership "reference type, large data"). +/// +/// - Release with: @c ::ArMesh_release +typedef struct ArMesh_ ArMesh; + // Hit result functionality. /// @ingroup ArHitResult @@ -660,6 +788,18 @@ inline ArAugmentedFace *ArAsFace(ArTrackable *trackable) { return reinterpret_cast(trackable); } +/// @ingroup type_conversions +/// Upcasts to @c ::ArTrackable +inline ArTrackable *ArAsTrackable(ArStreetscapeGeometry *streetscape_geometry) { + return reinterpret_cast(streetscape_geometry); +} + +/// @ingroup type_conversions +/// Downcasts to @c ::ArStreetscapeGeometry. +inline ArStreetscapeGeometry *ArAsStreetscapeGeometry(ArTrackable *trackable) { + return reinterpret_cast(trackable); +} + #endif // __cplusplus // If compiling for C++11, use the 'enum underlying type' feature to enforce @@ -699,6 +839,9 @@ AR_DEFINE_ENUM(ArTrackableType){ /// Trackable type for faces. AR_TRACKABLE_FACE = 0x41520105, + /// Trackable type for Streetscape Geometry. + AR_TRACKABLE_STREETSCAPE_GEOMETRY = 0x41520103, + /// Trackable type for @c ::ArEarth. AR_TRACKABLE_EARTH = 0x41520109, @@ -826,8 +969,8 @@ AR_DEFINE_ENUM(ArStatus){ /// have. AR_ERROR_INTERNET_PERMISSION_NOT_GRANTED = -15, - /// @c ::ArSession_hostAndAcquireNewCloudAnchor failed because the anchor is - /// not a type of anchor that is currently supported for hosting. + /// Hosting a Cloud Anchor failed because the anchor is not a type of anchor + /// that is currently supported for hosting. AR_ERROR_ANCHOR_NOT_SUPPORTED_FOR_HOSTING = -16, /// Attempted to add an image with insufficient quality (e.g., too few @@ -961,18 +1104,17 @@ AR_DEFINE_ENUM(ArTrackingFailureReason){ AR_TRACKING_FAILURE_REASON_CAMERA_UNAVAILABLE = 5}; /// @ingroup ArAnchor -/// Describes the current cloud state of an @c ::ArAnchor. +/// Result of a Cloud Anchor hosting or resolving operation. AR_DEFINE_ENUM(ArCloudAnchorState){ - /// The anchor is purely local. It has never been hosted using - /// @c ::ArSession_hostAndAcquireNewCloudAnchor, and has not been resolved - /// using - /// @c ::ArSession_resolveAndAcquireNewCloudAnchor. + /// Not a valid value for a Cloud Anchor operation. AR_CLOUD_ANCHOR_STATE_NONE = 0, /// A hosting/resolving task for the anchor is in progress. Once the task /// completes in the background, the anchor will get a new cloud state after /// the next @c ::ArSession_update call. - AR_CLOUD_ANCHOR_STATE_TASK_IN_PROGRESS = 1, + AR_CLOUD_ANCHOR_STATE_TASK_IN_PROGRESS AR_DEPRECATED( + "Not returned by async cloud anchor APIs - replaced by " + "AR_FUTURE_STATE_PENDING.") = 1, /// A hosting/resolving task for this anchor completed successfully. AR_CLOUD_ANCHOR_STATE_SUCCESS = 2, @@ -1034,7 +1176,6 @@ AR_DEFINE_ENUM(ArCloudAnchorState){ /// might affect the device's ability to connect to the ARCore Cloud Anchor /// service. AR_CLOUD_ANCHOR_STATE_ERROR_HOSTING_SERVICE_UNAVAILABLE = -10, - }; /// @ingroup ArCoreApk @@ -1190,6 +1331,40 @@ AR_DEFINE_ENUM(ArFocusMode){/// Focus is fixed. /// Auto-focus is enabled. AR_FOCUS_MODE_AUTO = 1}; +/// @ingroup ArConfig +/// Describes the behavior of the Electronic Image Stabilization (EIS) API. When +/// enabled, EIS smoothes the camera feed and helps correct video shakes in the +/// camera preview. See the Electronic +/// Image Stabilization Developer Guide for more information. +/// +/// Not all devices support all modes. Use @c +/// ::ArSession_isImageStabilizationModeSupported to detect if a @c +/// ::ArImageStabilizationMode is supported with the selected camera +/// configuration. +/// +/// Attempting to use @c ::ArSession_configure to configure a @c +/// ::ArImageStabilizationMode mode on a device that that isn't supported, @c +/// ::ArSession_configure will return #AR_ERROR_UNSUPPORTED_CONFIGURATION. +/// +/// The default value is #AR_IMAGE_STABILIZATION_MODE_OFF. Use +/// @c ::ArConfig_setImageStabilizationMode to set the desired mode. +AR_DEFINE_ENUM(ArImageStabilizationMode){ + /// Image stabilization is off. + /// + /// This is the default mode. + AR_IMAGE_STABILIZATION_MODE_OFF = 0, + /// Image stabilization is on. @c ::ArFrame_transformCoordinates3d can be + /// use to convert 2D coordinates to @c + /// #AR_COORDINATES_3D_EIS_TEXTURE_NORMALIZED and @c + /// #AR_COORDINATES_3D_EIS_NORMALIZED_DEVICE_COORDINATES. + /// + /// See the Electronic + /// Image Stabilization Developer Guide for more information. + AR_IMAGE_STABILIZATION_MODE_EIS = 1, +}; + /// @ingroup ArConfig /// Selects the desired depth mode. Not all devices support all modes, use /// @c ::ArSession_isDepthModeSupported to find whether the current device and @@ -1233,6 +1408,127 @@ AR_DEFINE_ENUM(ArDepthMode){ AR_DEPTH_MODE_RAW_DEPTH_ONLY = 3, }; +/// @ingroup ArConfig +/// Describes how ARCore will update the camera texture. See Vulkan Rendering +/// developer guide for more information. +/// +/// The default value is @c +/// #AR_TEXTURE_UPDATE_MODE_BIND_TO_TEXTURE_EXTERNAL_OES. Use +/// @c ::ArConfig_setTextureUpdateMode to set the desired mode. +AR_DEFINE_ENUM(ArTextureUpdateMode){ + /// ARCore provides the camera image through the @c GL_TEXTURE_EXTERNAL_OES + /// texture provided to @c ::ArSession_setCameraTextureName or @c + /// ::ArSession_setCameraTextureNames. + /// + /// This is the default mode. + AR_TEXTURE_UPDATE_MODE_BIND_TO_TEXTURE_EXTERNAL_OES = 0, + /// ARCore provides the camera image through an @c AHardwareBuffer. The + /// hardware buffer for an @c ::ArFrame is accessible via + /// @c ::ArFrame_getHardwareBuffer. See documentation on Native + /// Hardware Buffer in the Android NDK. + /// + /// The client app is responsible for binding it to + /// a @c GL_TEXTURE_EXTERNAL_OES (OpenGL ES) or @c VkImage (Vulkan). + /// + /// When a configuration is active with @c + /// #AR_TEXTURE_UPDATE_MODE_EXPOSE_HARDWARE_BUFFER, + /// texture names provided to @c ::ArSession_setCameraTextureName and + /// @c ::ArSession_setCameraTextureNames are ignored. + /// + /// This is only available on Android API levels 27 and above. Using @c + /// ::ArSession_configure to set + /// #AR_TEXTURE_UPDATE_MODE_EXPOSE_HARDWARE_BUFFER on an incompatible + /// device will return @c #AR_ERROR_UNSUPPORTED_CONFIGURATION. + AR_TEXTURE_UPDATE_MODE_EXPOSE_HARDWARE_BUFFER = 1, +}; + +/// @ingroup ArConfig +/// Describes the desired behavior of Scene Semantics. Scene Semantics uses a +/// machine learning model to label each pixel from the camera feed with a @c +/// ::ArSemanticLabel. See the +/// Scene +/// Semantics Developer Guide for more information. +/// +/// The Scene Semantics API is currently able to distinguish +/// between outdoor labels specified by @c ::ArSemanticLabel. Usage indoors is +/// currently unsupported and may yield unreliable results. +/// +/// A small number of ARCore supported devices do not support the Scene +/// Semantics API. Use @c ::ArSession_isSemanticModeSupported to query for +/// support for Scene Semantics. Affected devices are also indicated on the ARCore supported devices +/// page. +/// +/// The default value is @c #AR_SEMANTIC_MODE_DISABLED. Use @c +/// ::ArConfig_setSemanticMode to set the desired mode. +AR_DEFINE_ENUM(ArSemanticMode){ + /// The Scene Semantics API is disabled. Calls to + /// @c ::ArFrame_acquireSemanticImage, + /// @c ::ArFrame_acquireSemanticConfidenceImage, + /// and @c ::ArFrame_getSemanticLabelFraction will not return valid results. + /// + /// This is the default mode. + AR_SEMANTIC_MODE_DISABLED = 0, + /// The Scene Semantics API is enabled. Calls to + /// @c ::ArFrame_acquireSemanticImage, + /// @c ::ArFrame_acquireSemanticConfidenceImage, + /// and @c ::ArFrame_getSemanticLabelFraction will return valid results. + /// + /// Use @c ::ArConfig_setSemanticMode to set this mode. + AR_SEMANTIC_MODE_ENABLED = 1, +}; + +/// @ingroup ArSemantics +/// Defines the labels the Scene Semantics API is able to detect and maps +/// human-readable names to per-pixel semantic labels. See the +/// Scene +/// Semantics Developer Guide for more information. +/// +/// Use @c ::ArFrame_acquireSemanticImage to obtain an image containing these +/// pixels and @c ::ArFrame_getSemanticLabelFraction to query what percentage of +/// the image contains these pixels. +AR_DEFINE_ENUM(ArSemanticLabel){ + /// Pixels with no semantic label available in the API output. + AR_SEMANTIC_LABEL_UNLABELED = 0, + /// Pixels of the open sky, including clouds. Thin electrical wires in front + /// of the sky are included, but leaves/vegetation are not included. + AR_SEMANTIC_LABEL_SKY = 1, + /// Pixels of buildings, including houses, garages, etc. Includes all + /// structures attached to the building, such as signs, solar panels, + /// scaffolding, etc. + AR_SEMANTIC_LABEL_BUILDING = 2, + /// Pixels of non-walkable vegetation, like trees and shrubs. In contrast, + /// 'terrain' specifies walkable vegetation, like grass. + AR_SEMANTIC_LABEL_TREE = 3, + /// Pixels of drivable surfaces for vehicles, including paved, unpaved, dirt, + /// driveways, crosswalks, etc. + AR_SEMANTIC_LABEL_ROAD = 4, + /// Pixels of sidewalks for pedestrians and cyclists, including associated + /// curbs. + AR_SEMANTIC_LABEL_SIDEWALK = 5, + /// Pixels of walkable vegetation areas, including grass, soil, sand, + /// mountains, etc. In contrast, 'tree' specifies non-walkable vegetation, + /// like trees and bushes. + AR_SEMANTIC_LABEL_TERRAIN = 6, + /// Pixels of structures that are not buildings, including fences, guardrails, + /// stand-alone walls, tunnels, bridges, etc. + AR_SEMANTIC_LABEL_STRUCTURE = 7, + /// Pixels of general temporary and permanent objects and obstacles, including + /// street signs, traffic signs, free-standing business signs, billboards, + /// poles, mailboxes, fire hydrants, street lights, phone booths, bus stop + /// enclosures, cones, parking meters, animals, etc. + AR_SEMANTIC_LABEL_OBJECT = 8, + /// Pixels of vehicles, including cars, vans, buses, trucks, motorcycles, + /// bicycles, trains, etc. + AR_SEMANTIC_LABEL_VEHICLE = 9, + /// Pixels of humans, including pedestrians and bicycle/motorcycle riders. + AR_SEMANTIC_LABEL_PERSON = 10, + /// Pixels of ground surfaces covered by water, including lakes, rivers, etc. + AR_SEMANTIC_LABEL_WATER = 11, +}; + /// @ingroup ArPlane /// Simple summary of the normal vector of a plane, for filtering purposes. AR_DEFINE_ENUM(ArPlaneType){ @@ -1295,15 +1591,44 @@ AR_DEFINE_ENUM(ArInstantPlacementPointTrackingMethod){ /// being tracked concurrently. AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING = 2}; -/// @ingroup ArAnchor -/// Indicates the cloud configuration of the @c ::ArSession. +/// @ingroup ArConfig +/// Describes the desired behavior of the ARCore Cloud Anchor API. The Cloud +/// Anchor API uses feature maps to persist an anchor throughout sessions and +/// across devices. See the Cloud +/// Anchors developer guide for more information. +/// +/// The default value is @c #AR_CLOUD_ANCHOR_MODE_DISABLED. Use @c +/// ::ArConfig_setCloudAnchorMode to set the Cloud Anchor API mode and +/// @c ::ArSession_configure to configure the session. AR_DEFINE_ENUM(ArCloudAnchorMode){ - /// Cloud Anchors are disabled. This is the value set in the default - /// @c ::ArConfig. + /// The Cloud Anchor API is disabled. Calling @c + /// ::ArSession_hostCloudAnchorAsync and @c + /// ::ArSession_resolveCloudAnchorAsync will return + /// @c #AR_ERROR_CLOUD_ANCHORS_NOT_CONFIGURED. + /// + /// This is the default value. AR_CLOUD_ANCHOR_MODE_DISABLED = 0, - /// This mode will enable Cloud Anchors. Setting this value and calling - /// @c ::ArSession_configure will require the application to have the Android - /// INTERNET permission. + + /// The Cloud Anchor API is enabled. @c + /// ::ArSession_hostCloudAnchorAsync and @c + /// ::ArSession_resolveCloudAnchorAsync can be used to host and resolve + /// Cloud Anchors. + /// + /// Using this mode requires your app to do the following: + /// + /// - Include the @c + /// ACCESS_INTERNET permission to the app's AndroidManifest; + /// otherwise, @c ::ArSession_configure returns @c + /// #AR_ERROR_INTERNET_PERMISSION_NOT_GRANTED. + /// - Configure Keyless + /// or API Key authorization. + /// + /// Use @c + /// ::ArConfig_setCloudAnchorMode to set the Cloud Anchor API mode and + /// @c ::ArSession_configure to configure the session. AR_CLOUD_ANCHOR_MODE_ENABLED = 1, }; @@ -1334,6 +1659,12 @@ AR_DEFINE_ENUM(ArCloudAnchorMode){ /// href="https://developers.google.com/ar/devices"> ARCore supported devices /// page. /// +/// When the Geospatial API and the Depth API are enabled, output images +/// from the Depth API will include terrain and building geometry when in a +/// location with VPS coverage. See the Geospatial +/// Depth Developer Guide for more information. +/// /// The default value is @c #AR_GEOSPATIAL_MODE_DISABLED. Use @c /// ::ArConfig_setGeospatialMode to set the desired mode. AR_DEFINE_ENUM(ArGeospatialMode){ @@ -1379,6 +1710,12 @@ AR_DEFINE_ENUM(ArGeospatialMode){ /// href="https://developers.google.com/ar/develop/c/geospatial/developer-guide">the /// Geospatial API on Google Developers. /// + /// When the Geospatial API and the Depth API are enabled, output images + /// from the Depth API will include terrain and building geometry when in a + /// location with VPS coverage. See the Geospatial + /// Depth Developer Guide for more information. + /// /// This mode is not compatible with the front-facing /// (selfie) camera. If @c ::ArGeospatialMode is @c /// #AR_GEOSPATIAL_MODE_ENABLED on a session using @@ -1391,6 +1728,72 @@ AR_DEFINE_ENUM(ArGeospatialMode){ AR_GEOSPATIAL_MODE_ENABLED = 2, }; +/// @ingroup ArConfig +/// Describes the desired behavior of the Geospatial Streetscape Geometry API. +/// The Streetscape Geometry API provides polygon meshes of terrain, buildings, +/// and other structures in a radius surrounding the device. See the Streetscape +/// Geometry Developer Guide for additional information. +/// +///

When Streetscape Geometry is enabled, @c ::ArSession_getAllTrackables +/// and @c ::ArFrame_getUpdatedTrackables may additionally return +/// @c ::ArStreetscapeGeometry trackables. +/// +///

The Streetscape Geometry API requires both @c ::ArStreetscapeGeometryMode +/// to be set to @c #AR_STREETSCAPE_GEOMETRY_MODE_ENABLED and @c +/// ::ArGeospatialMode to be set to @c #AR_GEOSPATIAL_MODE_ENABLED. +/// +///

The default value is @c #AR_STREETSCAPE_GEOMETRY_MODE_DISABLED. Use +/// @c ::ArConfig_setStreetscapeGeometryMode to set the desired mode. + +AR_DEFINE_ENUM(ArStreetscapeGeometryMode){ + /// The Streetscape Geometry API is disabled. + /// + /// This is the default mode. + AR_STREETSCAPE_GEOMETRY_MODE_DISABLED = 0, + /// The Streetscape Geometry API is enabled. @c ::ArSession_getAllTrackables + /// and @c ::ArFrame_getUpdatedTrackables may additionally return + /// @c ::ArStreetscapeGeometry trackables. This mode requires @c + /// ::ArGeospatialMode to be set to @c #AR_GEOSPATIAL_MODE_ENABLED. + /// + /// Use @c ::ArConfig_setStreetscapeGeometryMode to set this mode. + AR_STREETSCAPE_GEOMETRY_MODE_ENABLED = 1, +}; + +// === ArStreetscapeGeometry types === + +/// @ingroup ArStreetscapeGeometry +/// Describes the type of a Streetscape Geometry. Obtained by @c +/// ::ArStreetscapeGeometry_getType. +AR_DEFINE_ENUM(ArStreetscapeGeometryType){ + /// This geometry represents the ground or floor. + AR_STREETSCAPE_GEOMETRY_TYPE_TERRAIN = 0, + /// This geometry represents a building or other structure. + AR_STREETSCAPE_GEOMETRY_TYPE_BUILDING = 1, +}; + +/// @ingroup ArStreetscapeGeometry +/// Describes the quality of the mesh data. The values correspond to the levels +/// of detail (LOD) defined by the CityGML 2.0 +/// standard. +/// +/// Obtained by @c ::ArStreetscapeGeometry_getQuality. +AR_DEFINE_ENUM(ArStreetscapeGeometryQuality){ + /// The quality of the geometry is not defined, e.g. when the @c + /// ::ArStreetscapeGeometryType is @c #AR_STREETSCAPE_GEOMETRY_TYPE_TERRAIN. + AR_STREETSCAPE_GEOMETRY_QUALITY_NONE = 0, + /// The @c #AR_STREETSCAPE_GEOMETRY_TYPE_BUILDING geometry is the building + /// footprint extruded up to a single flat top. The building contains empty + /// space above any angled roofs. + AR_STREETSCAPE_GEOMETRY_QUALITY_BUILDING_LOD_1 = 1, + /// The @c #AR_STREETSCAPE_GEOMETRY_TYPE_BUILDING geometry is the building + /// footprint with rough heightmap. The geometry will closely follow simple + /// angled roofs. Chimneys and roof vents on top of roofs will poke outside + /// of the Streetscape Geometry. + AR_STREETSCAPE_GEOMETRY_QUALITY_BUILDING_LOD_2 = 2, +}; + /// @ingroup ArInstantPlacementPoint /// Used in @c ::ArConfig to indicate whether Instant Placement should be /// enabled or disabled. Default value is @c @@ -1444,8 +1847,8 @@ AR_DEFINE_ENUM(ArCoordinates2dType){ AR_COORDINATES_2D_IMAGE_PIXELS = 2, /// CPU image, (x,y) normalized to [0.0f, 1.0f] range. AR_COORDINATES_2D_IMAGE_NORMALIZED = 3, - /// OpenGL Normalized Device Coordinates, display-rotated, - /// (x,y) normalized to [-1.0f, 1.0f] range. + /// OpenGL Normalized Device Coordinates, display-rotated, (x,y) normalized + /// to [-1.0f, 1.0f] range. AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES = 6, /// Android view, display-rotated, (x,y) in pixels. AR_COORDINATES_2D_VIEW = 7, @@ -1454,6 +1857,25 @@ AR_DEFINE_ENUM(ArCoordinates2dType){ }; +/// @ingroup ArFrame +/// 3d coordinate systems supported by ARCore. +AR_DEFINE_ENUM(ArCoordinates3dType){ + /// GPU texture coordinates, using the Z component to compensate for + /// perspective shift when using Electronic Image Stabilization (EIS). + /// + ///

Use with @c ::ArFrame_transformCoordinates3d. See the Electronic + /// Image Stabilization developer guide for more information. + AR_COORDINATES_3D_EIS_TEXTURE_NORMALIZED = 0, + /// Normalized Device Coordinates (NDC), display-rotated, (x,y) normalized to + /// [-1.0f, 1.0f] range to compensate for perspective shift for EIS. + /// + ///

Use with @c ::ArFrame_transformCoordinates3d. See the Electronic + /// Image Stabilization developer guide for more information. + AR_COORDINATES_3D_EIS_NORMALIZED_DEVICE_COORDINATES = 1, +}; + /// @ingroup ArCameraConfig /// Describes the direction a camera is facing relative to the device. Used by /// @c ::ArCameraConfig_getFacingDirection. @@ -1488,6 +1910,98 @@ AR_DEFINE_ENUM(ArCameraConfigFacingDirection){ /// Lighting Estimation mode. AR_CAMERA_CONFIG_FACING_DIRECTION_FRONT = 1}; +/// @ingroup ArFuture +/// Base type for asynchronous operations. See +/// @ref future_concept "Futures in ARCore" for more details. +/// +/// An acquired future must eventually be released using @c ::ArFuture_release. +/// (@ref ownership "reference type, long-lived"). +typedef struct ArFuture_ ArFuture; + +/// @ingroup ArFuture +/// The state of an asynchronous operation. +AR_DEFINE_ENUM(ArFutureState){ + /// The operation is still pending. The result of the operation isn't + /// available yet and any associated callback hasn't yet been dispatched or + /// invoked. Do not use this to check if the operation can be cancelled as + /// the state can change from another thread between the calls to + /// @c ::ArFuture_getState and @c ::ArFuture_cancel. + AR_FUTURE_STATE_PENDING = 0, + + /// The operation has been cancelled. Any associated callback will never be + /// invoked. + AR_FUTURE_STATE_CANCELLED = 1, + + /// The operation is complete and the result is available. If a callback was + /// associated with this future, it will soon be invoked with the result on + /// the main thread, if it hasn't been invoked already. + AR_FUTURE_STATE_DONE = 2, +}; + +/// @ingroup ArHostCloudAnchorFuture +/// Handle to an asynchronous operation launched by +/// @c ::ArSession_hostCloudAnchorAsync. See the Cloud +/// Anchors developer guide for more information. +/// +/// Release with @c ::ArFuture_release. +/// (@ref ownership "reference type, long-lived"). +typedef struct ArHostCloudAnchorFuture_ ArHostCloudAnchorFuture; + +#ifdef __cplusplus +/// @ingroup type_conversions +/// Upcasts to @c ::ArFuture +inline ArFuture *ArAsFuture(ArHostCloudAnchorFuture *future) { + return reinterpret_cast(future); +} +#endif // __cplusplus + +/// @ingroup ArResolveCloudAnchorFuture +/// Handle to an asynchronous operation launched by +/// @c ::ArSession_resolveCloudAnchorAsync. +/// Release with @c ::ArFuture_release. +/// (@ref ownership "reference type, long-lived"). +typedef struct ArResolveCloudAnchorFuture_ ArResolveCloudAnchorFuture; + +#ifdef __cplusplus +/// @ingroup type_conversions +/// Upcasts to @c ::ArFuture +inline ArFuture *ArAsFuture(ArResolveCloudAnchorFuture *future) { + return reinterpret_cast(future); +} +#endif // __cplusplus + +/// @ingroup ArResolveAnchorOnTerrainFuture +/// Handle to an asynchronous operation launched by +/// @c ::ArEarth_resolveAnchorOnTerrainAsync. +/// +/// Release with @c ::ArFuture_release. +/// (@ref ownership "reference type, long-lived"). +typedef struct ArResolveAnchorOnTerrainFuture_ ArResolveAnchorOnTerrainFuture; + +#ifdef __cplusplus +/// @ingroup type_conversions +/// Upcasts to @c ::ArFuture +inline ArFuture *ArAsFuture(ArResolveAnchorOnTerrainFuture *future) { + return reinterpret_cast(future); +} +#endif // __cplusplus + +/// @ingroup ArResolveAnchorOnRooftopFuture +/// Handle to an asynchronous operation launched by +/// @c ::ArEarth_resolveAnchorOnRooftopAsync. +/// Release with @c ::ArFuture_release. +/// (@ref ownership "reference type, long-lived"). +typedef struct ArResolveAnchorOnRooftopFuture_ ArResolveAnchorOnRooftopFuture; + +#ifdef __cplusplus +/// @ingroup type_conversions +/// Upcasts to @c ::ArFuture +inline ArFuture *ArAsFuture(ArResolveAnchorOnRooftopFuture *future) { + return reinterpret_cast(future); +} +#endif // __cplusplus + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -1522,6 +2036,51 @@ void ArCoreApk_checkAvailability(void *env, void *context, ArAvailability *out_availability); +/// @ingroup ArCoreApk +/// Callback definition for @c ::ArCoreApk_checkAvailabilityAsync. The +/// @p callback_context argument will be the same as that passed to +/// @c ::ArCoreApk_checkAvailabilityAsync. +/// +/// It is a best practice to free @c callback_context memory provided to +/// @c ::ArCoreApk_checkAvailabilityAsync at the end of the callback +/// implementation. +typedef void (*ArAvailabilityCallback)(void *callback_context, + ArAvailability availability); + +/// @ingroup ArCoreApk +/// Asynchronously determines if ARCore is supported on this device. This may +/// initiate a query with a remote service to determine if the device is +/// compatible. +/// +/// The callback will be invoked asynchronously on the Main thread. +/// Unlike the synchronous function @c ::ArCoreApk_checkAvailability, the result +/// will never be @c #AR_AVAILABILITY_UNKNOWN_CHECKING. +/// +/// For ARCore-required apps (as indicated by the manifest +/// @c meta-data ) this function will assume device compatibility and the +/// callback will be asynchronously invoked on the Main thread with one of +/// @c #AR_AVAILABILITY_SUPPORTED_INSTALLED, +/// @c #AR_AVAILABILITY_SUPPORTED_APK_TOO_OLD, or +/// @c #AR_AVAILABILITY_SUPPORTED_NOT_INSTALLED. +/// +/// Note: A result @c #AR_AVAILABILITY_SUPPORTED_INSTALLED only indicates +/// presence of a suitably versioned ARCore APK. Session creation may still fail +/// if the ARCore APK has been side-loaded onto an unsupported device. +/// +/// May be called prior to @c ::ArSession_create. +/// +/// @param[in] env The current thread's @c JNIEnv object +/// @param[in] application_context A @c JOBject for an Android @c Context. +/// @param[in] callback_context An arbitrary pointer which will be passed as the +/// first argument to the callback. +/// @param[in] callback The callback to invoke with the result on the Main +/// thread. Must not be @c NULL. +void ArCoreApk_checkAvailabilityAsync(void *env, + void *application_context, + void *callback_context, + ArAvailabilityCallback callback); + /// @ingroup ArCoreApk /// On supported devices initiates download and installation of /// Google Play Services for AR (ARCore) and ARCore device profile data, see @@ -1708,6 +2267,40 @@ ArStatus ArSession_createWithFeatures(void *env, const ArSessionFeature *features, ArSession **out_session_pointer); +// === ArFuture functions === + +/// @ingroup ArFuture +/// Gets the state of an asynchronous operation. See @c ::ArFutureState and +/// @ref future_concept "Futures in ARCore" for more details. +/// +/// @param[in] session The ARCore session. +/// @param[in] future The handle for the asynchronous operation. +/// @param[out] out_state The state of the operation. +void ArFuture_getState(const ArSession *session, + const ArFuture *future, + ArFutureState *out_state); + +/// @ingroup ArFuture +/// Tries to cancel execution of this operation. @p out_was_cancelled will be +/// set to 1 if the operation was cancelled by this invocation, and in that case +/// it is a best practice to free @c context memory provided to the +/// @ref future_callback "callback", if any. +/// +/// @param[in] session The ARCore session. +/// @param[in] future The handle for the asynchronous operation. +/// @param[out] out_was_cancelled Set to 1 if this invocation successfully +/// cancelled the operation, 0 otherwise. You may pass @c NULL. +void ArFuture_cancel(const ArSession *session, + ArFuture *future, + int32_t *out_was_cancelled); + +/// @ingroup ArFuture +/// Releases a reference to a future. This does not mean that the operation will +/// be terminated - see @ref future_cancellation "cancelling a future". +/// +/// This function may safely be called with @c NULL - it will do nothing. +void ArFuture_release(ArFuture *future); + // === ArConfig functions === /// @ingroup ArConfig @@ -1805,6 +2398,25 @@ void ArConfig_getAugmentedImageDatabase( const ArConfig *config, ArAugmentedImageDatabase *out_augmented_image_database); +/// @ingroup ArConfig +/// Stores the desired texture update mode from the given @p config into +/// @p out_texture_update_mode. +void ArConfig_getTextureUpdateMode( + const ArSession *session, + const ArConfig *config, + ArTextureUpdateMode *out_texture_update_mode); + +/// @ingroup ArConfig +/// Sets the desired texture update mode. See @c ::ArTextureUpdateMode for +/// available options. +/// +/// Some values for @p texture_update_mode may not be supported on the current +/// device. If an unsupported value is set, @c ::ArSession_configure will throw +/// @c #AR_ERROR_UNSUPPORTED_CONFIGURATION. +void ArConfig_setTextureUpdateMode(const ArSession *session, + ArConfig *config, + ArTextureUpdateMode texture_update_mode); + /// @ingroup ArConfig /// Stores the currently configured augmented face mode into /// @p *augmented_face_mode. @@ -1857,6 +2469,33 @@ void ArConfig_getFocusMode(const ArSession *session, ArConfig *config, ArFocusMode *focus_mode); +/// @ingroup ArConfig +/// Gets the camera image stabilization mode set on this config +/// object. +/// +/// @param[in] session The ARCore session. +/// @param[in] config The configuration object. +/// @param[inout] out_image_stabilization_mode The current EIS mode. +void ArConfig_getImageStabilizationMode( + const ArSession *session, + const ArConfig *config, + ArImageStabilizationMode *out_image_stabilization_mode); + +/// @ingroup ArConfig +/// Sets the camera image stabilization mode. +/// +/// See @c ::ArImageStabilizationMode for available options. Currently, the +/// default image stabilization mode is @c #AR_IMAGE_STABILIZATION_MODE_OFF. +/// +/// @param[in] session The ARCore session. +/// @param[in] config The configuration object. +/// @param[in] image_stabilization_mode The desired camera image +/// stabilization mode. +void ArConfig_setImageStabilizationMode( + const ArSession *session, + ArConfig *config, + ArImageStabilizationMode image_stabilization_mode); + /// @ingroup ArConfig /// Sets the Geospatial mode. See @c ::ArGeospatialMode for available options. void ArConfig_setGeospatialMode(const ArSession *session, @@ -1874,12 +2513,38 @@ void ArConfig_getGeospatialMode(const ArSession *session, const ArConfig *config, ArGeospatialMode *out_geospatial_mode); +/// @ingroup ArConfig +/// Sets the desired configuration for the Streetscape Geometry API. See @c +/// ::ArStreetscapeGeometryMode for available options and usage information. +void ArConfig_setStreetscapeGeometryMode( + const ArSession *session, + ArConfig *config, + ArStreetscapeGeometryMode streetscape_geometry_mode); + +/// @ingroup ArConfig +/// Gets the current Streetscape Geometry mode set on the configuration. +/// +/// @param[in] session The ARCore session. +/// @param[in] config The configuration object. +/// @param[out] out_streetscape_geometry_mode The current @c +/// ::ArStreetscapeGeometry mode set on the config. +void ArConfig_getStreetscapeGeometryMode( + const ArSession *session, + const ArConfig *config, + ArStreetscapeGeometryMode *out_streetscape_geometry_mode); + /// @ingroup ArConfig /// Gets the currently configured desired @c ::ArDepthMode. void ArConfig_getDepthMode(const ArSession *session, const ArConfig *config, ArDepthMode *out_depth_mode); +/// @ingroup ArConfig +/// Gets the currently configured @c ::ArSemanticMode. +void ArConfig_getSemanticMode(const ArSession *session, + const ArConfig *config, + ArSemanticMode *out_semantic_mode); + /// @ingroup ArConfig /// Sets the desired @c ::ArDepthMode. /// @@ -1898,6 +2563,17 @@ void ArConfig_setDepthMode(const ArSession *session, ArConfig *config, ArDepthMode mode); +/// @ingroup ArConfig +/// Sets the desired configuration for the Scene Semantics API. See +/// @c ::ArSemanticMode for available options and usage information. +/// +/// Not all devices support all modes. Use +/// @c ::ArSession_isSemanticModeSupported to determine whether the current +/// device and the selected camera support a particular semantic mode. +void ArConfig_setSemanticMode(const ArSession *session, + ArConfig *config, + ArSemanticMode semantic_mode); + /// @ingroup ArConfig /// Sets the current Instant Placement mode from the @c ::ArConfig. void ArConfig_setInstantPlacementMode( @@ -2470,6 +3146,8 @@ ArStatus ArSession_checkSupported(const ArSession *session, /// - @c #AR_CLOUD_ANCHOR_MODE_ENABLED. /// - @c #AR_LIGHT_ESTIMATION_MODE_ENVIRONMENTAL_HDR. /// - @c #AR_GEOSPATIAL_MODE_ENABLED. +/// - When on an Android device with API level 26 or below: +/// - @c #AR_TEXTURE_UPDATE_MODE_EXPOSE_HARDWARE_BUFFER. /// /// @param[in] session The ARCore session. /// @param[in] config The new configuration setting for the session. @@ -2559,6 +3237,10 @@ ArStatus ArSession_pause(ArSession *session); /// Note: this function doesn't fail. If given invalid input, it logs an error /// without setting the texture names. /// +/// When a configuration is active using @c +/// #AR_TEXTURE_UPDATE_MODE_EXPOSE_HARDWARE_BUFFER, values provided to this +/// function are ignored. +/// /// @param[in] session The ARCore session /// @param[in] number_of_textures The number of textures being passed. This /// must always be at least 1. @@ -2577,6 +3259,10 @@ void ArSession_setCameraTextureNames(ArSession *session, /// to @c ::ArSession_setCameraTextureName or /// @c ::ArSession_setCameraTextureNames, and additionally are not guaranteed to /// remain valid after a call to @c ::ArSession_pause or @c ::ArSession_destroy. +/// +/// When a configuration is active using @c +/// #AR_TEXTURE_UPDATE_MODE_EXPOSE_HARDWARE_BUFFER, values provided to this +/// function are ignored. void ArSession_setCameraTextureName(ArSession *session, uint32_t texture_id); /// @ingroup ArSession @@ -2684,34 +3370,32 @@ void ArSession_getAllTrackables(const ArSession *session, /// few seconds and visible from a desired camera @c ::ArPose. A higher quality /// indicates a Cloud Anchor hosted at the current time with the current set of /// recently seen features will generally be easier to resolve more accurately. -/// For more details, see -/// https://developers.google.com/ar/develop/c/cloud-anchors/overview-c +/// See the Cloud +/// Anchors developer guide for more information. AR_DEFINE_ENUM(ArFeatureMapQuality){ /// The quality of features seen from the pose in the preceding /// seconds is low. This state indicates that ARCore will likely have more - /// difficulty resolving (@c ::ArSession_resolveAndAcquireNewCloudAnchor) - /// the Cloud Anchor. Encourage the user to move the device, so that the - /// desired position of the Cloud Anchor to be hosted is seen from different - /// angles. + /// difficulty resolving the Cloud Anchor. Encourage the user to move the + /// device, so that the desired position of the Cloud Anchor to be hosted is + /// seen from different angles. AR_FEATURE_MAP_QUALITY_INSUFFICIENT = 0, /// The quality of features seen from the pose in the preceding few - /// seconds is likely sufficient for ARCore to successfully resolve - /// (@c ::ArSession_resolveAndAcquireNewCloudAnchor) a Cloud Anchor, - /// although the accuracy of the resolved pose will likely be reduced. - /// Encourage the user to move the device, so that the desired position of - /// the Cloud - /// Anchor to be hosted is seen from different angles. + /// seconds is likely sufficient for ARCore to successfully resolve a Cloud + /// Anchor, although the accuracy of the resolved pose will likely be + /// reduced. Encourage the user to move the device, so that the desired + /// position of the Cloud Anchor to be hosted is seen from different angles. AR_FEATURE_MAP_QUALITY_SUFFICIENT = 1, /// The quality of features seen from the pose in the preceding few - /// seconds is likely sufficient for ARCore to successfully resolve - /// (@c ::ArSession_resolveAndAcquireNewCloudAnchor) a Cloud Anchor with a - /// high degree of accuracy. + /// seconds is likely sufficient for ARCore to successfully resolve a Cloud + /// Anchor with a high degree of accuracy. AR_FEATURE_MAP_QUALITY_GOOD = 2, }; /// @ingroup ArSession /// Estimates the quality of the visual features seen by ARCore in the /// preceding few seconds and visible from the provided camera pose. +/// /// Cloud Anchors hosted using higher quality features will generally result /// in easier and more accurately resolved Cloud Anchor poses. /// @@ -2750,9 +3434,13 @@ ArStatus ArSession_estimateFeatureMapQualityForHosting( /// - @c #AR_ERROR_CLOUD_ANCHORS_NOT_CONFIGURED /// - @c #AR_ERROR_RESOURCE_EXHAUSTED /// - @c #AR_ERROR_ANCHOR_NOT_SUPPORTED_FOR_HOSTING +/// @deprecated Use @c ::ArSession_hostCloudAnchorAsync with @c ttl_days = 1 +/// instead. ArStatus ArSession_hostAndAcquireNewCloudAnchor(ArSession *session, const ArAnchor *anchor, - ArAnchor **out_cloud_anchor); + ArAnchor **out_cloud_anchor) + AR_DEPRECATED( + "Use ArSession_hostCloudAnchorAsync with ttl_days = 1 instead."); /// @ingroup ArSession /// This creates a new Cloud Anchor and schedules a task to resolve the anchor's @@ -2777,9 +3465,11 @@ ArStatus ArSession_hostAndAcquireNewCloudAnchor(ArSession *session, /// - @c #AR_ERROR_SESSION_PAUSED /// - @c #AR_ERROR_CLOUD_ANCHORS_NOT_CONFIGURED /// - @c #AR_ERROR_RESOURCE_EXHAUSTED +/// @deprecated Use @c ::ArSession_resolveCloudAnchorAsync instead. ArStatus ArSession_resolveAndAcquireNewCloudAnchor(ArSession *session, const char *cloud_anchor_id, - ArAnchor **out_cloud_anchor); + ArAnchor **out_cloud_anchor) + AR_DEPRECATED("Use @c ::ArSession_resolveCloudAnchorAsync instead."); /// @ingroup ArSession /// This creates a new Cloud Anchor with a given lifetime in days, using the @@ -2811,11 +3501,204 @@ ArStatus ArSession_resolveAndAcquireNewCloudAnchor(ArSession *session, /// - @c #AR_ERROR_CLOUD_ANCHORS_NOT_CONFIGURED /// - @c #AR_ERROR_RESOURCE_EXHAUSTED /// - @c #AR_ERROR_ANCHOR_NOT_SUPPORTED_FOR_HOSTING +/// @deprecated Use @c ::ArSession_hostCloudAnchorAsync with @c ttl_days = 1 +/// instead. ArStatus ArSession_hostAndAcquireNewCloudAnchorWithTtl( ArSession *session, const ArAnchor *anchor, int32_t ttl_days, - ArAnchor **out_cloud_anchor); + ArAnchor **out_cloud_anchor) + AR_DEPRECATED( + "Use ArSession_hostCloudAnchorAsync with ttl_days = 1 instead."); + +/// @ingroup ArHostCloudAnchorFuture +/// Gets the Cloud Anchor ID of the hosted anchor. If the operation isn't done +/// yet or the operation failed, this will be @c NULL. The caller must release +/// the string using @c ::ArString_release. +/// +/// @param[in] session The ARCore session. +/// @param[in] future The handle for the asynchronous operation. +/// @param[out] out_cloud_anchor_id The Cloud Anchor ID. +void ArHostCloudAnchorFuture_acquireResultCloudAnchorId( + const ArSession *session, + const ArHostCloudAnchorFuture *future, + char **out_cloud_anchor_id); + +/// @ingroup ArHostCloudAnchorFuture +/// Gets the result status of the hosting operation, if the operation is done. +/// +/// @param[in] session The ARCore session. +/// @param[in] future The handle for the asynchronous operation. +/// @param[out] out_cloud_anchor_state The result status. +void ArHostCloudAnchorFuture_getResultCloudAnchorState( + const ArSession *session, + const ArHostCloudAnchorFuture *future, + ArCloudAnchorState *out_cloud_anchor_state); + +/// @ingroup ArHostCloudAnchorFuture +/// Callback definition for @c ::ArSession_hostCloudAnchorAsync. The +/// @p context argument will be the same as that passed to +/// @c ::ArSession_hostCloudAnchorAsync. The @p cloud_anchor_id argument +/// will contain the same value as that returned by +/// @c ::ArHostCloudAnchorFuture_acquireResultCloudAnchorId and must be released +/// using @c ::ArString_release. The @p cloud_anchor_state argument will be the +/// same as that returned by +/// @c ::ArHostCloudAnchorFuture_getResultCloudAnchorState. +/// +/// It is a best practice to free @c context memory provided to +/// @c ::ArSession_hostCloudAnchorAsync at the end of the callback +/// implementation. +typedef void (*ArHostCloudAnchorCallback)( + void *context, + char *cloud_anchor_id, + ArCloudAnchorState cloud_anchor_state); + +/// @ingroup ArSession +/// Uses the pose and other data from @p anchor to host a new Cloud Anchor. +/// A Cloud Anchor is assigned an identifier that can be used to create an +/// @c ::ArAnchor in the same position in subsequent sessions across devices +/// using @c ::ArSession_resolveCloudAnchorAsync. See the Cloud +/// Anchors developer guide for more information. +/// +/// The duration that a Cloud Anchor can be resolved for is specified by +/// @p ttl_days. When using Keyless +/// authorization, the maximum allowed value is 365 days. When using an API +/// Key to authenticate with the ARCore API, the maximum allowed value is 1 +/// day. +/// +/// This launches an asynchronous operation used to query the Google Cloud +/// ARCore API. See @c ::ArFuture for information on obtaining results and +/// cancelling the operation. +/// +/// Cloud Anchors requires a @c ::ArConfig with @c +/// #AR_CLOUD_ANCHOR_MODE_ENABLED set on this session. Use @c +/// ::ArConfig_setCloudAnchorMode to set the Cloud Anchor API mode and +/// @c ::ArSession_configure to configure the session. +/// +/// Hosting a Cloud Anchor works best when ARCore is able to create a good +/// feature map around the @c ::ArAnchor. Use @c +/// ::ArSession_estimateFeatureMapQualityForHosting to determine the quality of +/// visual features seen by ARCore in the preceding few seconds. Cloud Anchors +/// hosted using higher quality features will generally result in quicker and +/// more accurately resolved Cloud Anchor poses. +/// +/// ARCore can have up to 40 simultaneous Cloud Anchor operations, including +/// resolved anchors and active hosting operations. +/// +/// @param[in] session The ARCore session. +/// @param[in] anchor The anchor with the desired pose to be used to host a +/// Cloud Anchor. +/// @param[in] ttl_days The lifetime of the anchor in days. Must be positive. +/// @param[in] context An optional void pointer passed when using a @ref +/// future_callback "callback". +/// @param[in] callback A @ref future_callback "callback function". +/// @param[out] out_future An optional @c ::ArFuture which can be @ref +/// future_polling "polled". +/// @return @c #AR_SUCCESS or any of: +/// - @c #AR_ERROR_INVALID_ARGUMENT if any of the provided arguments are +/// invalid, +/// - @c #AR_ERROR_NOT_TRACKING if the camera is not currently tracking, +/// - @c #AR_ERROR_SESSION_PAUSED if the session is currently paused, +/// - @c #AR_ERROR_CLOUD_ANCHORS_NOT_CONFIGURED if the Cloud Anchor API has not +/// been enabled in the session configuration, +/// - @c #AR_ERROR_RESOURCE_EXHAUSTED if too many Cloud Anchors operations are +/// ongoing. +/// - @c #AR_ERROR_ANCHOR_NOT_SUPPORTED_FOR_HOSTING if the anchor is not +/// supported for hosting. +ArStatus ArSession_hostCloudAnchorAsync(ArSession *session, + const ArAnchor *anchor, + int32_t ttl_days, + void *context, + ArHostCloudAnchorCallback callback, + ArHostCloudAnchorFuture **out_future); + +/// @ingroup ArResolveCloudAnchorFuture +/// Gets the resolved Cloud Anchor. If the operation isn't done yet or the +/// operation failed, this will be @c NULL. The caller must release the anchor +/// using @c ::ArAnchor_release. +/// +/// @param[in] session The ARCore session. +/// @param[in] future The handle for the asynchronous operation. +/// @param[out] out_anchor The anchor. +void ArResolveCloudAnchorFuture_acquireResultAnchor( + const ArSession *session, + const ArResolveCloudAnchorFuture *future, + ArAnchor **out_anchor); + +/// @ingroup ArResolveCloudAnchorFuture +/// Gets the result status of the resolving operation, if the operation is done. +/// +/// @param[in] session The ARCore session. +/// @param[in] future The handle for the asynchronous operation. +/// @param[out] out_cloud_anchor_state The result status. +void ArResolveCloudAnchorFuture_getResultCloudAnchorState( + const ArSession *session, + const ArResolveCloudAnchorFuture *future, + ArCloudAnchorState *out_cloud_anchor_state); + +/// @ingroup ArResolveCloudAnchorFuture +/// Callback definition for @c ::ArSession_resolveCloudAnchorAsync. The +/// @p context argument will be the same as that passed to +/// @c ::ArSession_resolveCloudAnchorAsync. The @p anchor argument will be the +/// same as that returned by +/// @c ::ArResolveCloudAnchorFuture_acquireResultAnchor and must be released +/// using @c ::ArAnchor_release. The @p cloud_anchor_state argument will be the +/// same as that returned by +/// @c ::ArResolveCloudAnchorFuture_getResultCloudAnchorState. +/// +/// It is a best practice to free @c context memory provided to +/// @c ::ArSession_resolveCloudAnchorAsync at the end of the callback +/// implementation. +typedef void (*ArResolveCloudAnchorCallback)( + void *context, ArAnchor *anchor, ArCloudAnchorState cloud_anchor_state); + +/// @ingroup ArSession +/// Attempts to resolve a Cloud Anchor using the provided @p cloud_anchor_id. +/// The Cloud Anchor must previously have been hosted by @c +/// ::ArSession_hostCloudAnchorAsync or another Cloud Anchor hosting method +/// within the allotted @c ttl_days. See the Cloud +/// Anchors developer guide for more information. +/// +/// This launches an asynchronous operation used to query the Google Cloud +/// ARCore API. See @c ::ArFuture for information on obtaining results and +/// cancelling the operation. +/// +/// When resolving a Cloud Anchor, the ARCore API periodically compares visual +/// features from the scene against the anchor's 3D feature map to pinpoint the +/// user's position and orientation relative to the anchor. When it finds a +/// match, the task completes. +/// +/// Cloud Anchors requires a @c ::ArConfig with @c +/// #AR_CLOUD_ANCHOR_MODE_ENABLED set on this session. Use @c +/// ::ArConfig_setCloudAnchorMode to set the Cloud Anchor API mode and +/// @c ::ArSession_configure to configure the session. +/// +/// ARCore can have up to 40 simultaneous Cloud Anchor operations, including +/// resolved anchors and active hosting operations. +/// +/// @param[in] session The ARCore session +/// @param[in] cloud_anchor_id The cloud ID of the anchor to be resolved. +/// @param[in] context An optional void pointer passed when using a @ref +/// future_callback "callback". +/// @param[in] callback A @ref future_callback "callback function". +/// @param[out] out_future An optional @c ::ArFuture which can be @ref +/// future_polling "polled". +/// @return @c #AR_SUCCESS or any of: +/// - @c #AR_ERROR_INVALID_ARGUMENT +/// - @c #AR_ERROR_SESSION_PAUSED +/// - @c #AR_ERROR_CLOUD_ANCHORS_NOT_CONFIGURED +/// - @c #AR_ERROR_RESOURCE_EXHAUSTED if too many Cloud Anchors operations are +/// ongoing. +ArStatus ArSession_resolveCloudAnchorAsync( + ArSession *session, + const char *cloud_anchor_id, + void *context, + ArResolveCloudAnchorCallback callback, + ArResolveCloudAnchorFuture **out_future); /// @ingroup ArSession /// Gets a list of camera configs supported by the camera being used by the @@ -3168,19 +4051,50 @@ ArStatus ArFrame_recordTrackData(ArSession *session, size_t payload_size); /// @ingroup ArSession -/// Checks whether the provided @c ::ArDepthMode is supported on this device +/// Checks whether the provided @c ::ArDepthMode is supported on this device +/// with the selected camera configuration. The current list of supported +/// devices is documented on the ARCore +/// supported devices page. +/// +/// @param[in] session The ARCore session. +/// @param[in] depth_mode The desired depth mode to check. +/// @param[out] out_is_supported Non zero if the depth mode is supported on this +/// device. +void ArSession_isDepthModeSupported(const ArSession *session, + ArDepthMode depth_mode, + int32_t *out_is_supported); + +/// @ingroup ArSession +/// Checks whether the provided @c ::ArImageStabilizationMode is supported on +/// this device with the selected camera configuration. See Enabling +/// Electronic Image Stabilization for more information. +/// +/// @param[in] session The ARCore session. +/// @param[in] image_stabilization_mode The desired image stabilization mode to +/// check. +/// @param[out] out_is_supported Non zero if given @c ::ArImageStabilizationMode +/// is supported on this device. +void ArSession_isImageStabilizationModeSupported( + const ArSession *session, + ArImageStabilizationMode image_stabilization_mode, + int32_t *out_is_supported); + +/// @ingroup ArSession +/// Checks whether the provided @c ::ArSemanticMode is supported on this device /// with the selected camera configuration. The current list of supported /// devices is documented on the ARCore /// supported devices page. /// /// @param[in] session The ARCore session. -/// @param[in] depth_mode The desired depth mode to check. -/// @param[out] out_is_supported Non zero if the depth mode is supported on this -/// device. -void ArSession_isDepthModeSupported(const ArSession *session, - ArDepthMode depth_mode, - int32_t *out_is_supported); +/// @param[in] semantic_mode The desired semantic mode to check. +/// @param[out] out_is_supported Non zero if the semantic mode is supported on +/// this device. +void ArSession_isSemanticModeSupported(const ArSession *session, + ArSemanticMode semantic_mode, + int32_t *out_is_supported); /// @ingroup ArSession /// Checks whether the provided @c ::ArGeospatialMode is supported on this @@ -3573,6 +4487,44 @@ void ArFrame_transformCoordinates2d(const ArSession *session, ArCoordinates2dType output_coordinates, float *out_vertices_2d); +/// @ingroup ArFrame +/// Transforms a list of 2D coordinates from one 2D coordinate space to 3D +/// coordinate space. See the Electronic +/// Image Stabilization Developer Guide for more information. +/// +/// The view information is taken from the most recent call to @c +/// ::ArSession_setDisplayGeometry. +/// +/// If Electronic Image Stabilization is off, the device coordinates return (-1, +/// -1, 0) -> (1, 1, 0) and texture coordinates return the same coordinates as +/// @c ::ArFrame_transformCoordinates2d with the Z component set to 1.0f. +/// +/// In order to use EIS, your app should use EIS compensated screen coordinates +/// and camera texture coordinates to pass on to shaders. Use the 2D NDC space +/// coordinates as input to obtain EIS compensated 3D screen coordinates and +/// matching camera texture coordinates. +/// +/// @param[in] session The ARCore session. +/// @param[in] frame The current frame. +/// @param[in] input_coordinates The coordinate system used by @p vectors2d_in. +/// @param[in] number_of_vertices The number of 2D vertices to transform. +/// @p vertices_2d must +/// point to arrays of size at least +/// @p number_of_vertices * 2. And @p +/// out_vertices_2d must point to arrays of size at +/// least @p number_of_vertices * 3. +/// @param[in] vertices_2d Input 2D vertices to transform. +/// @param[in] output_coordinates The 3D coordinate system to convert to. +/// @param[out] out_vertices_3d Transformed 3d vertices. +void ArFrame_transformCoordinates3d(const ArSession *session, + const ArFrame *frame, + ArCoordinates2dType input_coordinates, + int32_t number_of_vertices, + const float *vertices_2d, + ArCoordinates3dType output_coordinates, + float *out_vertices_3d); + /// @ingroup ArFrame /// Performs a ray cast from the user's device in the direction of the given /// location in the camera view. Intersections with detected scene geometry are @@ -3999,6 +4951,12 @@ ArStatus ArFrame_acquireDepthImage(const ArSession *session, /// This is expected only to occur on compute-constrained devices. An up-to-date /// depth image should typically become available again within a few frames. /// +/// When the Geospatial API and the Depth API are enabled, output images +/// from the Depth API will include terrain and building geometry when in a +/// location with VPS coverage. See the Geospatial +/// Depth Developer Guide for more information. +/// /// The image must be released with @c ::ArImage_release once it is no /// longer needed. /// @@ -4170,6 +5128,12 @@ ArStatus ArFrame_acquireRawDepthImage(const ArSession *session, /// ::ArImage_getTimestamp, with the previously recorded raw depth image /// timestamp. If they are different, the depth image contains new information. /// +/// When the Geospatial API and the Depth API are enabled, output images +/// from the Depth API will include terrain and building geometry when in a +/// location with VPS coverage. See the Geospatial +/// Depth Developer Guide for more information. +/// /// The image must be released via @c ::ArImage_release once it is no longer /// needed. /// @@ -4254,6 +5218,143 @@ ArStatus ArFrame_acquireRawDepthConfidenceImage(const ArSession *session, const ArFrame *frame, ArImage **out_confidence_image); +/// @ingroup ArFrame +/// Attempts to acquire the semantic image corresponding to the current frame. +/// Each pixel in the image is an 8-bit unsigned integer representing a semantic +/// class label: see @c ::ArSemanticLabel for a list of pixel labels and the +/// Scene +/// Semantics Developer Guide for more information. +/// +/// The image must be released via @c ::ArImage_release once it is no longer +/// needed. +/// +/// In order to obtain a valid result from this function, you must set the +/// session's @c ::ArSemanticMode to @c #AR_SEMANTIC_MODE_ENABLED. Use +/// @c ::ArSession_isSemanticModeSupported to query for support for Scene +/// Semantics. +/// +/// The width of the semantic image is currently 256 pixels. The height of the +/// image depends on the device and will match its display aspect ratio. +/// +/// @param[in] session The ARCore session. +/// @param[in] frame The current frame. +/// @param[out] out_semantic_image On successful return, this is filled out +/// with a pointer to an @c ::ArImage formatted as UINT8, where each pixel +/// denotes the semantic class. On error return, this is filled out +/// with @c NULL. +/// @return @c #AR_SUCCESS or any of: +/// - @c #AR_ERROR_INVALID_ARGUMENT if the @p session, @p frame, or +/// @p out_semantic_image arguments are invalid. +/// - @c #AR_ERROR_NOT_YET_AVAILABLE if no semantic image is available +/// that corresponds to the frame. +/// - @c #AR_ERROR_RESOURCE_EXHAUSTED if the caller app has exceeded maximum +/// number of images that it can hold without releasing. +/// - @c #AR_ERROR_DEADLINE_EXCEEDED if the provided @c ::ArFrame is not the +/// current one. +ArStatus ArFrame_acquireSemanticImage(const ArSession *session, + const ArFrame *frame, + ArImage **out_semantic_image); + +/// @ingroup ArFrame +/// Attempts to acquire the semantic confidence image corresponding to the +/// current frame. Each pixel is an 8-bit integer representing the estimated +/// confidence of the corresponding pixel in the semantic image. See the +/// Scene +/// Semantics Developer Guide for more information. +/// +/// The confidence value is between 0 and 255, inclusive, with 0 representing +/// the lowest confidence and 255 representing the highest confidence in the +/// semantic class prediction (see @c ::ArFrame_acquireSemanticImage). +/// +/// The image must be released via @c ::ArImage_release once it is no longer +/// needed. +/// +/// In order to obtain a valid result from this function, you must set the +/// session's @c ::ArSemanticMode to @c #AR_SEMANTIC_MODE_ENABLED. Use +/// @c ::ArSession_isSemanticModeSupported to query for support for Scene +/// Semantics. +/// +/// The size of the semantic confidence image is the same size as the image +/// obtained by @c ::ArFrame_acquireSemanticImage. +/// +/// @param[in] session The ARCore session. +/// @param[in] frame The current frame. +/// @param[out] out_semantic_confidence_image On successful return, this is +/// filled out with a pointer to an @c ::ArImage, where each pixel denotes the +/// confidence corresponding to the semantic label. On error return, this is +/// filled out with @c nullptr. +/// @return @c #AR_SUCCESS or any of: +/// - @c #AR_ERROR_INVALID_ARGUMENT if the @p session, @p frame, or +/// @p out_semantic_confidence_image arguments are invalid. +/// - @c #AR_ERROR_NOT_YET_AVAILABLE if no semantic image is available +/// that corresponds to the frame. +/// - @c #AR_ERROR_RESOURCE_EXHAUSTED if the caller app has exceeded maximum +/// number of images that it can hold without releasing. +/// - @c #AR_ERROR_DEADLINE_EXCEEDED if the provided @c ::ArFrame is not the +/// current one. +ArStatus ArFrame_acquireSemanticConfidenceImage( + const ArSession *session, + const ArFrame *frame, + ArImage **out_semantic_confidence_image); + +/// @ingroup ArFrame +/// Retrieves the fraction of the most recent semantics frame that are @p +/// query_label. +/// +/// Queries the semantic image provided by @c ::ArFrame_acquireSemanticImage for +/// pixels labeled by @p query_label. This call is more efficient than +/// retrieving the @c ArImage and performing a pixel-wise search for the +/// detected labels. +/// +/// @param[in] session The ARCore session. +/// @param[in] frame The current frame. +/// @param[in] query_label The label to search for within +/// the semantic image for this frame. +/// @param[out] out_fraction The fraction of pixels in the +/// most recent semantic image that contain the query label. This value is in +/// the range 0 to 1. If no pixels are present with that label, or if an +/// invalid label is provided, this call returns 0. +/// @return @c #AR_SUCCESS or any of: +/// - @c #AR_ERROR_INVALID_ARGUMENT if @p session, @p frame, or @p query_label +/// are invalid. +/// - @c #AR_ERROR_NOT_YET_AVAILABLE if no semantic image has been generated +/// yet. +ArStatus ArFrame_getSemanticLabelFraction(const ArSession *session, + const ArFrame *frame, + ArSemanticLabel query_label, + float *out_fraction); + +/// @ingroup ArFrame +/// Gets the @c +/// AHardwareBuffer for this frame. See Vulkan Rendering +/// developer guide for more information. +/// +/// The result in @p out_hardware_buffer is +/// only valid when a configuration is active that uses @c +/// #AR_TEXTURE_UPDATE_MODE_EXPOSE_HARDWARE_BUFFER. +/// +/// This hardware buffer is only guaranteed to be valid until the next call to +/// @c ::ArSession_update(). If you want to use the hardware buffer beyond that, +/// such as for rendering, you must call @c +/// AHardwareBuffer_acquire and then call @c +/// AHardwareBuffer_release after your rendering is complete. +/// +/// @param[in] session The ARCore session. +/// @param[in] frame The current frame. +/// @param[out] out_hardware_buffer The destination @c AHardwareBuffer +/// representing a memory chunk of a camera image. +/// @return @c #AR_SUCCESS or any of: +/// - @c #AR_ERROR_INVALID_ARGUMENT - one or more input arguments are invalid. +/// - @c #AR_ERROR_DEADLINE_EXCEEDED - the input frame is not the current frame. +/// - @c #AR_ERROR_NOT_YET_AVAILABLE - the camera failed to produce the image. +ArStatus ArFrame_getHardwareBuffer(const ArSession *session, + const ArFrame *frame, + void **out_hardware_buffer); + /// @ingroup ArFrame /// Returns the OpenGL ES camera texture name (ID) associated with this frame. /// This is guaranteed to be one of the texture names previously set via @@ -4268,6 +5369,75 @@ void ArFrame_getCameraTextureName(const ArSession *session, const ArFrame *frame, uint32_t *out_texture_id); +/// @ingroup ArMesh +/// Releases a reference to the Mesh. +/// This must match a call to @c ::ArStreetscapeGeometry_acquireMesh. +/// +/// This function may safely be called with @c NULL - it will do nothing. +void ArMesh_release(ArMesh *mesh); + +/// @ingroup ArMesh +/// Retrieves the number of vertices in this mesh. +/// +/// @param[in] session The ARCore session. +/// @param[in] mesh The mesh object to query. +/// @param[out] out_num_vertices The number of vertices in this mesh. +void ArMesh_getVertexListSize(const ArSession *session, + const ArMesh *mesh, + int32_t *out_num_vertices); + +/// @ingroup ArMesh +/// Retrieves the vertex coordinate data for this mesh. Each vertex is three +/// @c float values, stored in XYZ order. The total number of @c float values in +/// @p out_vertex_positions_xyz is 3 * @c ::ArMesh_getVertexListSize. +/// +/// The array returned in @p out_vertex_positions_xyz will only remain valid as +/// long as @p mesh is valid. +/// +/// @param[in] session The ARCore session. +/// @param[in] mesh The mesh object to query. +/// @param[out] out_vertex_positions_xyz Where to store the vertex positions +/// positions. +void ArMesh_getVertexList(const ArSession *session, + const ArMesh *mesh, + const float **out_vertex_positions_xyz); + +/// @ingroup ArMesh +/// Retrieves the number of triangle indices (represented by @c +/// ::ArMesh_getIndexList) in this mesh. The indices should always be used as a +/// triangle list, with three indices per triangle. The result can be passed as +/// the @c indices parameter to @c +/// glDrawElements or copied into a buffer bound via @c +/// vkCmdDrawIndexed . +/// +/// @param[in] session The ARCore session. +/// @param[in] mesh The mesh object to query. +/// @param[out] out_num_indices The number of indices in this mesh. This +/// will always be a multiple of 3. +void ArMesh_getIndexListSize(const ArSession *session, + const ArMesh *mesh, + int32_t *out_num_indices); + +/// @ingroup ArMesh +/// Retrieves the triangle data for this mesh in an array of length @c +/// ::ArMesh_getIndexListSize. Each face is a triplet of indices into the +/// vertices array. The indices should always be used as a triangle list, with +/// three indices per triangle. The result can be passed as the "indices" +/// parameter to @c glDrawElements or copied into a buffer bound via +/// @c vkCmdBindIndexBuffer. +/// +/// @param[in] session The ARCore session. +/// @param[in] mesh The mesh object to query. +/// @param[out] out_indices Where to store the concatenated indices +/// of mesh vertices that correspond to each +/// face. This length is @c out_num_indices +/// from @c ::ArMesh_getIndexListSize(). +void ArMesh_getIndexList(const ArSession *session, + const ArMesh *mesh, + const uint32_t **out_indices); + // === ArPointCloud functions === /// @ingroup ArPointCloud @@ -4724,9 +5894,19 @@ void ArAnchor_release(ArAnchor *anchor); /// @param[in] session The ARCore session. /// @param[in] anchor The anchor to retrieve the cloud ID of. /// @param[inout] out_cloud_anchor_id A pointer to the acquired ID string. +/// @deprecated Use @c ::ArHostCloudAnchorFuture_acquireResultCloudAnchorId +/// instead. void ArAnchor_acquireCloudAnchorId(ArSession *session, ArAnchor *anchor, - char **out_cloud_anchor_id); + char **out_cloud_anchor_id) + AR_DEPRECATED( + "For anchors hosted using ArSession_hostCloudAnchorAsync, the cloud " + "anchor ID can be obtained from the callback or future object. This " + "function will always return the empty string except for anchors " + "created using the deprecated functions " + "ArSession_resolveAndAcquireNewCloudAnchor, " + "ArSession_hostAndAcquireNewCloudAnchor, and " + "ArSession_hostAndAcquireNewCloudAnchorWithTtl."); /// @ingroup ArAnchor /// Gets the current Cloud Anchor state of the anchor. This state is guaranteed @@ -4735,9 +5915,19 @@ void ArAnchor_acquireCloudAnchorId(ArSession *session, /// @param[in] session The ARCore session. /// @param[in] anchor The anchor to retrieve the cloud state of. /// @param[inout] out_state The current cloud state of the anchor. +/// @deprecated Use @c ::ArHostCloudAnchorFuture_getResultCloudAnchorState or +/// @c ::ArResolveCloudAnchorFuture_getResultCloudAnchorState instead. void ArAnchor_getCloudAnchorState(const ArSession *session, const ArAnchor *anchor, - ArCloudAnchorState *out_state); + ArCloudAnchorState *out_state) + AR_DEPRECATED( + "For anchors hosted or resolved using async cloud anchor APIs, the " + "state can be obtained from the callback or future object. This " + "function will always return AR_CLOUD_ANCHOR_STATE_NONE except for " + "anchors created using the deprecated functions " + "ArSession_resolveAndAcquireNewCloudAnchor, " + "ArSession_hostAndAcquireNewCloudAnchor, and " + "ArSession_hostAndAcquireNewCloudAnchorWithTtl."); // === ArTrackableList functions === @@ -5699,6 +6889,7 @@ ArStatus ArEarth_acquireNewAnchor(ArSession *session, /// NULL. /// - @c #AR_ERROR_RESOURCE_EXHAUSTED if too many terrain anchors are currently /// held. +/// @deprecated Use @c ::ArEarth_resolveAnchorOnTerrainAsync instead. ArStatus ArEarth_resolveAndAcquireNewAnchorOnTerrain( ArSession *session, ArEarth *earth, @@ -5706,24 +6897,21 @@ ArStatus ArEarth_resolveAndAcquireNewAnchorOnTerrain( double longitude, double altitude_above_terrain, const float *eus_quaternion_4, - ArAnchor **out_anchor); + ArAnchor **out_anchor) + AR_DEPRECATED("Use ArEarth_resolveAnchorOnTerrainAsync instead."); /// @ingroup ArAnchor -/// Describes the current Terrain anchor state of an @c ::ArAnchor. Obtained by -/// @c ::ArAnchor_getTerrainAnchorState. +/// Describes the result of a Terrain anchor resolving operation. AR_DEFINE_ENUM(ArTerrainAnchorState){ - /// This is not a Terrain anchor, or the Terrain anchor has become invalid - /// due to @c ::ArEarth having @c #AR_TRACKING_STATE_STOPPED - /// due to @c #AR_GEOSPATIAL_MODE_DISABLED being set on the @c ::ArSession. - /// All Terrain anchors transition to @c #AR_TERRAIN_ANCHOR_STATE_NONE - /// when @c #AR_GEOSPATIAL_MODE_DISABLED becomes active on the @c - /// ::ArSession. + /// Not a valid value for a terrain anchor operation. AR_TERRAIN_ANCHOR_STATE_NONE = 0, /// Resolving the Terrain anchor is in progress. Once the task completes in /// the background, the anchor will get a new state after the next @c /// ::ArSession_update call. - AR_TERRAIN_ANCHOR_STATE_TASK_IN_PROGRESS = 1, + AR_TERRAIN_ANCHOR_STATE_TASK_IN_PROGRESS AR_DEPRECATED( + "Not returned by async APIs - replaced by " + "AR_FUTURE_STATE_PENDING.") = 1, /// A resolving task for this anchor has been successfully resolved. AR_TERRAIN_ANCHOR_STATE_SUCCESS = 2, @@ -5759,14 +6947,287 @@ AR_DEFINE_ENUM(ArTerrainAnchorState){ /// @param[inout] out_state The current terrain anchor state of the anchor. /// Non-terrain anchors will always be in /// @c #AR_TERRAIN_ANCHOR_STATE_NONE state. +/// @deprecated Use @c +/// ::ArResolveAnchorOnTerrainFuture_getResultTerrainAnchorState. void ArAnchor_getTerrainAnchorState(const ArSession *session, const ArAnchor *anchor, - ArTerrainAnchorState *out_state); + ArTerrainAnchorState *out_state) + AR_DEPRECATED( + "For anchors resolved using async terrain anchor APIs, the state can " + "be obtained from the callback or future object."); + +/// @ingroup ArResolveAnchorOnTerrainFuture +/// Gets the resolved Terrain anchor. If the operation isn't done yet or the +/// operation failed, this will be @c NULL. The caller must release the anchor +/// using @c ::ArAnchor_release. +/// +/// @param[in] session The ARCore session. +/// @param[in] future The handle for the asynchronous operation. +/// @param[out] out_anchor The anchor. +void ArResolveAnchorOnTerrainFuture_acquireResultAnchor( + const ArSession *session, + const ArResolveAnchorOnTerrainFuture *future, + ArAnchor **out_anchor); + +/// @ingroup ArResolveAnchorOnTerrainFuture +/// Gets the result status of the resolving operation, if the operation is done. +/// +/// @param[in] session The ARCore session. +/// @param[in] future The handle for the asynchronous operation. +/// @param[out] out_terrain_anchor_state The result status. +void ArResolveAnchorOnTerrainFuture_getResultTerrainAnchorState( + const ArSession *session, + const ArResolveAnchorOnTerrainFuture *future, + ArTerrainAnchorState *out_terrain_anchor_state); + +/// @ingroup ArResolveAnchorOnTerrainFuture +/// Callback definition for @c ::ArEarth_resolveAnchorOnTerrainAsync. The +/// @p context argument will be the same as that passed to +/// @c ::ArEarth_resolveAnchorOnTerrainAsync. The @p anchor argument will be the +/// same as that returned by +/// @c ::ArResolveAnchorOnTerrainFuture_acquireResultAnchor and must be released +/// using @c ::ArAnchor_release. The @p terrain_anchor_state argument will be +/// the same as that returned by +/// @c ::ArResolveAnchorOnTerrainFuture_getResultTerrainAnchorState. +/// +/// It is a best practice to free @c context memory provided to +/// @c ::ArEarth_resolveAnchorOnTerrainAsync at the end of the callback +/// implementation. +typedef void (*ArResolveAnchorOnTerrainCallback)( + void *context, ArAnchor *anchor, ArTerrainAnchorState terrain_anchor_state); + +/// @ingroup ArEarth +/// Asynchronously creates an anchor at a specified horizontal position and +/// altitude relative to the horizontal position’s terrain. See the Terrain +/// anchors developer guide for more information. +/// +/// The specified altitude is interpreted to be relative to the Earth's terrain +/// (or floor) at the specified latitude/longitude geodetic coordinates, rather +/// than relative to the WGS-84 ellipsoid. Specifying an altitude of 0 will +/// position the anchor directly on the terrain (or floor) whereas specifying a +/// positive altitude will position the anchor above the terrain (or floor), +/// against the direction of gravity. +/// +/// This launches an asynchronous operation used to query the Google Cloud +/// ARCore API. See @c ::ArFuture for information on obtaining results and +/// cancelling the operation. +/// +/// You may resolve multiple anchors at a time, but a session cannot +/// be tracking more than 100 Terrain and Rooftop anchors at time. Attempting to +/// resolve more than 100 Terrain or Rooftop anchors will result in resolve +/// calls returning status @c #AR_ERROR_RESOURCE_EXHAUSTED. +/// +/// Creating a terrain anchor requires an active @c ::ArEarth for which the @c +/// ::ArEarthState is @c #AR_EARTH_STATE_ENABLED and @c ::ArTrackingState is @c +/// #AR_TRACKING_STATE_TRACKING. If it is not, then this function returns @c +/// #AR_ERROR_ILLEGAL_STATE. This call also requires a working internet +/// connection to communicate with the ARCore API on Google Cloud. ARCore will +/// continue to retry if it is unable to establish a connection to the ARCore +/// service. +/// +/// Latitude and longitude are defined by the +/// WGS84 +/// specification. +/// +/// The rotation provided by @p eus_quaternion_4 is a rotation with respect to +/// an east-up-south coordinate frame. An identity rotation will have the anchor +/// oriented such that X+ points to the east, Y+ points up away from the center +/// of the earth, and Z+ points to the south. +/// +/// @param[in] session The ARCore session. +/// @param[in] earth The @c ::ArEarth handle. +/// @param[in] latitude The latitude of the anchor relative to the +/// WGS-84 ellipsoid. +/// @param[in] longitude The longitude of the anchor relative to the +/// WGS-84 ellipsoid. +/// @param[in] altitude_above_terrain The altitude of the anchor above the +/// Earth's terrain (or floor). +/// @param[in] eus_quaternion_4 The rotation quaternion as {qx, qy, qx, qw}. +/// @param[in] context An optional void pointer passed when using a @ref +/// future_callback "callback". +/// @param[in] callback A @ref future_callback "callback function". +/// @param[out] out_future An optional @c ::ArFuture which can be @ref +/// future_polling "polled". +/// @return @c #AR_SUCCESS or any of: +/// - @c #AR_ERROR_ILLEGAL_STATE if @c ::ArEarthState is not +/// @c #AR_EARTH_STATE_ENABLED. +/// - @c #AR_ERROR_INVALID_ARGUMENT if @p latitude is outside the allowable +/// range, or if either @p session, @p earth, or @p eus_quaternion_4 is @c +/// NULL, or both @p callback and @p out_future are @c NULL. +/// - @c #AR_ERROR_RESOURCE_EXHAUSTED if too many anchors (counting both Terrain +/// and Rooftop anchors) are currently held or are being resolved. +ArStatus ArEarth_resolveAnchorOnTerrainAsync( + ArSession *session, + ArEarth *earth, + double latitude, + double longitude, + double altitude_above_terrain, + const float *eus_quaternion_4, + void *context, + ArResolveAnchorOnTerrainCallback callback, + ArResolveAnchorOnTerrainFuture **out_future); + +/// @ingroup ArAnchor +/// Describes the current Rooftop anchor state of an @c ::ArAnchor. Obtained by +/// @c ::ArResolveAnchorOnRooftopFuture_getResultRooftopAnchorState or as a +/// parameter to the callback. +AR_DEFINE_ENUM(ArRooftopAnchorState){ + /// Not a valid value for a Rooftop anchor operation. + AR_ROOFTOP_ANCHOR_STATE_NONE = 0, + /// A resolving task for this anchor has been successfully resolved. + AR_ROOFTOP_ANCHOR_STATE_SUCCESS = 1, + + /// Resolving task for this anchor finished with an internal + /// error. The app should not attempt to recover from this error. + AR_ROOFTOP_ANCHOR_STATE_ERROR_INTERNAL = -1, + + /// The authorization provided by the application is not valid. + /// - The Google Cloud project may not have enabled the ARCore API. + /// - When using API key authentication, this will happen if the API key in + /// the manifest is invalid or unauthorized. It may also fail if the API + /// key is restricted to a set of apps not including the current one. + /// - When using keyless authentication, this may happen when no OAuth + /// client has been created, or when the signing key and package name + /// combination does not match the values used in the Google Cloud + /// project. It may also fail if Google Play Services isn't installed, + /// is too old, or is malfunctioning for some reason (e.g. killed + /// due to memory pressure). + AR_ROOFTOP_ANCHOR_STATE_ERROR_NOT_AUTHORIZED = -2, + + /// There is no rooftop or terrain info at this location, such as the center + /// of the ocean. + AR_ROOFTOP_ANCHOR_STATE_ERROR_UNSUPPORTED_LOCATION = -3, +}; + +/// @ingroup ArResolveAnchorOnRooftopFuture +/// Gets the resolved Rooftop anchor. If the operation isn't done yet or the +/// operation failed, this will be @c NULL. The caller must release the anchor +/// using @c ::ArAnchor_release. +/// +/// @param[in] session The ARCore session. +/// @param[in] future The handle for the asynchronous operation. +/// @param[out] out_anchor The anchor. +void ArResolveAnchorOnRooftopFuture_acquireResultAnchor( + const ArSession *session, + const ArResolveAnchorOnRooftopFuture *future, + ArAnchor **out_anchor); + +/// @ingroup ArResolveAnchorOnRooftopFuture +/// Gets the result status of the resolving operation, if the operation is done. +/// +/// @param[in] session The ARCore session. +/// @param[in] future The handle for the asynchronous operation. +/// @param[out] out_rooftop_anchor_state The result status. +void ArResolveAnchorOnRooftopFuture_getResultRooftopAnchorState( + const ArSession *session, + const ArResolveAnchorOnRooftopFuture *future, + ArRooftopAnchorState *out_rooftop_anchor_state); + +/// @ingroup ArResolveAnchorOnRooftopFuture +/// Callback definition for @c ::ArEarth_resolveAnchorOnRooftopAsync. +/// The @p context argument will be the same as that passed to +/// @c ::ArEarth_resolveAnchorOnRooftopAsync. The @p anchor argument +/// will be the same as that returned by +/// @c ::ArResolveAnchorOnRooftopFuture_acquireResultAnchor and must be +/// released using @c ::ArAnchor_release. The @p rooftop_anchor_state argument +/// will be the same as that returned by @c +/// ::ArResolveAnchorOnRooftopFuture_getResultRooftopAnchorState. +/// +/// It is a best practice to free @c context memory provided to +/// @c ::ArEarth_resolveAnchorOnRooftopAsync at the end of the callback +/// implementation. +typedef void (*ArResolveAnchorOnRooftopCallback)( + void *context, ArAnchor *anchor, ArRooftopAnchorState rooftop_anchor_state); + +/// @ingroup ArEarth +/// Asynchronously creates an anchor at a specified horizontal position and +/// altitude relative to the horizontal position’s rooftop. See the Rooftop +/// anchors developer guide for more information. +/// +/// The specified @p altitude_above_rooftop is interpreted to be relative to the +/// top of a building at the given horizontal location, rather than relative to +/// the WGS84 ellipsoid. If there is no building at the given location, then the +/// altitude is interpreted to be relative to the terrain instead. Specifying an +/// altitude of 0 will position the anchor directly on the rooftop whereas +/// specifying a positive altitude will position the anchor above the rooftop, +/// against the direction of gravity. +/// +/// This launches an asynchronous operation used to query the Google Cloud +/// ARCore API. See @c ::ArFuture for information on obtaining results and +/// cancelling the operation. +/// +/// You may resolve multiple anchors at a time, but a session cannot +/// be tracking more than 100 Terrain and Rooftop anchors at time. Attempting to +/// resolve more than 100 Terrain or Rooftop anchors will result in resolve +/// calls returning status @c #AR_ERROR_RESOURCE_EXHAUSTED. +/// +/// Creating a Rooftop anchor requires an active @c ::ArEarth for which the @c +/// ::ArEarthState is @c #AR_EARTH_STATE_ENABLED and @c ::ArTrackingState is @c +/// #AR_TRACKING_STATE_TRACKING. If it is not, then this function returns @c +/// #AR_ERROR_ILLEGAL_STATE. This call also requires a working internet +/// connection to communicate with the ARCore API on Google Cloud. ARCore will +/// continue to retry if it is unable to establish a connection to the ARCore +/// service. +/// +/// Latitude and longitude are defined by the +/// WGS84 +/// specification. +/// +/// The rotation provided by @p eus_quaternion_4 is a rotation with respect to +/// an east-up-south coordinate frame. An identity rotation will have the anchor +/// oriented such that X+ points to the east, Y+ points up away from the center +/// of the earth, and Z+ points to the south. +/// +/// To create an anchor that has the +Z axis pointing in the same direction as +/// heading obtained from @c ::ArGeospatialPose, use the following formula: +/// +/// \code +/// {qx, qy, qz, qw} = {0, sin((pi - heading * M_PI / 180.0) / 2), 0, cos((pi - +/// heading * M_PI / 180.0) / 2)}}. +/// \endcode +/// +/// @param[in] session The ARCore session. +/// @param[in] earth The @c ::ArEarth handle. +/// @param[in] latitude The latitude of the anchor relative to the +/// WGS-84 ellipsoid. +/// @param[in] longitude The longitude of the anchor relative to the +/// WGS-84 ellipsoid. +/// @param[in] altitude_above_rooftop The altitude of the anchor above the +/// Earth's rooftop. +/// @param[in] eus_quaternion_4 The rotation quaternion as {qx, qy, qx, qw}. +/// @param[in] context An optional void pointer passed when using a @ref +/// future_callback "callback". +/// @param[in] callback A @ref future_callback "callback function". +/// @param[out] out_future An optional @c ::ArFuture which can be @ref +/// future_polling "polled". +/// @return @c #AR_SUCCESS or any of: +/// - @c #AR_ERROR_ILLEGAL_STATE if @p earth is @c #AR_TRACKING_STATE_STOPPED +/// and +/// @c ::ArEarthState is not AR_EARTH_STATE_ENABLED due to @c +/// #AR_GEOSPATIAL_MODE_DISABLED configured on the @c ::ArSession. +/// Reacquire @c ::ArEarth if geospatial mode was reenabled. +/// - @c #AR_ERROR_INVALID_ARGUMENT if @p latitude is outside the allowable +/// range, or if either @p session, @p earth, or @p eus_quaternion_4 is @c +/// NULL, or both @p callback and @p out_future are null. +/// - @c #AR_ERROR_RESOURCE_EXHAUSTED if too many Rooftop and Terrain anchors +/// are currently held. +ArStatus ArEarth_resolveAnchorOnRooftopAsync( + ArSession *session, + ArEarth *earth, + double latitude, + double longitude, + double altitude_above_rooftop, + const float *eus_quaternion_4, + void *context, + ArResolveAnchorOnRooftopCallback callback, + ArResolveAnchorOnRooftopFuture **out_future); /// @ingroup ArVpsAvailabilityFuture /// The result of @c ::ArSession_checkVpsAvailabilityAsync, obtained by @c /// ::ArVpsAvailabilityFuture_getResult or from an invocation of an @c -/// #ArCheckVpsAvailabilityCallback. +/// #ArVpsAvailabilityCallback. AR_DEFINE_ENUM(ArVpsAvailability){ /// The request to the remote service is not yet completed, so the /// availability is not yet known. @@ -5799,68 +7260,59 @@ AR_DEFINE_ENUM(ArVpsAvailability){ /// It is a best practice to free @c context memory provided to @c /// ::ArSession_checkVpsAvailabilityAsync at the end of the callback /// implementation. -typedef void (*ArCheckVpsAvailabilityCallback)(void *context, - ArVpsAvailability availability); +typedef void (*ArVpsAvailabilityCallback)(void *context, + ArVpsAvailability availability); + +/// @ingroup ArVpsAvailabilityFuture +/// Deprecated alias of @c ::ArVpsAvailabilityCallback. +/// +/// @deprecated Deprecated in release 1.37.0. Use @c ::ArVpsAvailabilityCallback +/// instead. +typedef ArVpsAvailabilityCallback ArCheckVpsAvailabilityCallback AR_DEPRECATED( + "Deprecated in release 1.37. " + "Use ArVpsAvailabilityCallback instead."); /// @ingroup ArVpsAvailabilityFuture /// Handle to an asynchronous operation launched by /// @c ::ArSession_checkVpsAvailabilityAsync. -/// Release with @c ::ArVpsAvailabilityFuture_release. +/// Release with @c ::ArFuture_release. /// (@ref ownership "reference type, long-lived"). typedef struct ArVpsAvailabilityFuture_ ArVpsAvailabilityFuture; +#ifdef __cplusplus +/// @ingroup type_conversions +/// Upcasts to @c ::ArFuture +inline ArFuture *ArAsFuture(ArVpsAvailabilityFuture *future) { + return reinterpret_cast(future); +} +#endif // __cplusplus + /// @ingroup ArSession /// Gets the availability of the Visual Positioning System (VPS) at a specified /// horizontal position. The availability of VPS in a given location helps to -/// improve the quality of Geospatial localization and tracking accuracy. +/// improve the quality of Geospatial localization and tracking accuracy. See Check +/// VPS Availability for more details. /// /// This launches an asynchronous operation used to query the Google Cloud -/// ARCore API. This may be called without first calling @c ::ArSession_resume +/// ARCore API. See @c ::ArFuture for information on obtaining results and +/// cancelling the operation. +/// +/// This may be called without first calling @c ::ArSession_resume /// or @c ::ArSession_configure, for example to present an "Enter AR" button /// only when VPS is available. /// -/// The asynchronicity of this operation must be handled in one or -/// both of the following ways: -/// - The operation can be continually polled using @p out_future. When the -/// future is created, its @c #ArFutureState will be set to @c -/// #AR_FUTURE_STATE_PENDING. -/// Use @c ::ArVpsAvailabilityFuture_getState to query the state of the -/// operation. When its state is @c #AR_FUTURE_STATE_DONE, @c -/// ::ArVpsAvailabilityFuture_getResult can be used to obtain the operation's -/// result. The future must eventually be released using @c -/// ::ArVpsAvailabilityFuture_release. -/// - The operation's result can be reported via a callback. When providing a @p -/// callback, ARCore will invoke the given function when the operation is -/// complete, unless the future has been cancelled using @c -/// ::ArVpsAvailabilityFuture_cancel on @p out_future. This callback will be -/// invoked on the main -/// thread. When providing a callback, you may provide a -/// @p context, which will be passed as the first parameter to the callback. -/// It is a best practice to free the memory of @p context at the end of the -/// callback or when @c ::ArVpsAvailabilityFuture_cancel successfully cancels -/// the callback. -/// /// Your app must be properly set up to communicate with the Google Cloud ARCore -/// API in order to obtain a result from this call. See Check -/// VPS Availability for more details on setup steps and usage examples. +/// API in order to obtain a result from this call. /// /// @param[in] session The ARCore session. /// @param[in] latitude_degrees The latitude to query, in degrees. /// @param[in] longitude_degrees The longitude to query, in degrees. -/// @param[in] context An optional void pointer which is passed as the first -/// parameter to an invocation of @p callback. The app must ensure that the -/// memory remains valid until the callback has run, or the operation has -/// been cancelled. This may be null. -/// @param[in] callback An optional callback function. When the asynchronous -/// operation is complete this callback will be invoked unless the -/// operation has been cancelled. This may be null if no callback is -/// desired, but one of @p callback and @p out_future must be non-null. -/// @param[out] out_future A optional handler that can be used to poll and -/// cancel the asynchronous operation. This argument may be null if no -/// handler is desired, but one of @p callback and @p out_future must be -/// non-null. +/// @param[in] context An optional void pointer passed when using a @ref +/// future_callback "callback". +/// @param[in] callback A @ref future_callback "callback function". +/// @param[out] out_future An optional @c ::ArFuture which can be @ref +/// future_polling "polled". /// @return @c #AR_SUCCESS, or any of: /// - @c #AR_ERROR_INTERNET_PERMISSION_NOT_GRANTED if the @c INTERNET permission /// has not been granted. @@ -5871,33 +7323,9 @@ ArStatus ArSession_checkVpsAvailabilityAsync( double latitude_degrees, double longitude_degrees, void *context, - ArCheckVpsAvailabilityCallback callback, + ArVpsAvailabilityCallback callback, ArVpsAvailabilityFuture **out_future); -/// @ingroup ArVpsAvailabilityFuture -/// The state of an asynchronous operation. -AR_DEFINE_ENUM(ArFutureState){ - /// The operation is still pending. The result of the operation isn't - /// available yet and any associated callback hasn't yet been dispatched or - /// invoked. - /// - /// Do not use this to check if the operation can be cancelled as the state - /// can change from another thread between the call to - /// @c ::ArVpsAvailabilityFuture_getState and @c - /// ::ArVpsAvailabilityFuture_cancel. - AR_FUTURE_STATE_PENDING = 0, - - /// The operation has been cancelled. Any associated callback will never be - /// invoked. - AR_FUTURE_STATE_CANCELLED = 1, - - /// The operation is complete and the result is available. If a callback was - /// associated with this future, it will soon be invoked with the result on - /// the main thread, if - /// it hasn't been invoked already. - AR_FUTURE_STATE_DONE = 2, -}; - /// @ingroup ArVpsAvailabilityFuture /// Gets the state of an asynchronous operation. /// @@ -5906,12 +7334,12 @@ AR_DEFINE_ENUM(ArFutureState){ /// @param[out] out_state The state of the operation. void ArVpsAvailabilityFuture_getState(const ArSession *session, const ArVpsAvailabilityFuture *future, - ArFutureState *out_state); + ArFutureState *out_state) + AR_DEPRECATED("Deprecated in release 1.37. Use ArFuture_getState instead."); /// @ingroup ArVpsAvailabilityFuture /// Returns the result of an asynchronous operation. The returned result is only -/// valid when @c ::ArVpsAvailabilityFuture_getState returns @c -/// #AR_FUTURE_STATE_DONE. +/// valid when @c ::ArFuture_getState returns @c #AR_FUTURE_STATE_DONE. /// /// @param[in] session The ARCore session. /// @param[in] future The handle for the asynchronous operation. @@ -5934,14 +7362,16 @@ void ArVpsAvailabilityFuture_getResult( /// cancelled the operation, 0 otherwise. This may be null. void ArVpsAvailabilityFuture_cancel(const ArSession *session, ArVpsAvailabilityFuture *future, - int32_t *out_was_cancelled); + int32_t *out_was_cancelled) + AR_DEPRECATED("Deprecated in release 1.37. Use ArFuture_cancel instead."); /// @ingroup ArVpsAvailabilityFuture /// Releases a reference to a future. This does not mean that the operation will -/// be terminated - see @c ::ArVpsAvailabilityFuture_cancel. +/// be terminated - see @c ::ArFuture_cancel. /// /// This function may safely be called with @c NULL - it will do nothing. -void ArVpsAvailabilityFuture_release(ArVpsAvailabilityFuture *future); +void ArVpsAvailabilityFuture_release(ArVpsAvailabilityFuture *future) + AR_DEPRECATED("Deprecated in release 1.37. Use ArFuture_release instead."); // === ArGeospatialPose functions === @@ -6153,6 +7583,42 @@ void ArGeospatialPose_getOrientationYawAccuracy( const ArGeospatialPose *geospatial_pose, double *out_orientation_yaw_accuracy_degrees); +// === ArStreetscapeGeometry functions === + +/// @ingroup ArStreetscapeGeometry +/// Gets the origin pose of the @p streetscape_geometry. This pose +/// should be applied to all the points in the geometry from @c +/// ::ArStreetscapeGeometry_acquireMesh. +void ArStreetscapeGeometry_getMeshPose( + const ArSession *session, + const ArStreetscapeGeometry *streetscape_geometry, + ArPose *out_pose); + +/// @ingroup ArStreetscapeGeometry +/// Gets the @c ::ArStreetscapeGeometryType corresponding to this geometry. +void ArStreetscapeGeometry_getType( + const ArSession *session, + const ArStreetscapeGeometry *streetscape_geometry, + ArStreetscapeGeometryType *out_type); + +/// @ingroup ArStreetscapeGeometry +/// Gets the @c ::ArStreetscapeGeometryQuality corresponding to this geometry. +void ArStreetscapeGeometry_getQuality( + const ArSession *session, + const ArStreetscapeGeometry *streetscape_geometry, + ArStreetscapeGeometryQuality *out_quality); + +/// @ingroup ArStreetscapeGeometry +/// Acquires a polygon @c ::ArMesh that corresponds to this geometry. A @c +/// ::ArMesh describes the geometry as a collection of polygons which should be +/// transformed by @c ::ArStreetscapeGeometry_getMeshPose. +/// +/// @c ::ArMesh must be released by calling @c ::ArMesh_release. +void ArStreetscapeGeometry_acquireMesh( + const ArSession *session, + const ArStreetscapeGeometry *streetscape_geometry, + ArMesh **out_mesh); + /// @ingroup ArImageMetadata /// Defines a rational data type in @c ::ArImageMetadata_const_entry. /// diff --git a/samples/augmented_faces_java/app/build.gradle b/samples/augmented_faces_java/app/build.gradle index c318ac82a..eff192029 100644 --- a/samples/augmented_faces_java/app/build.gradle +++ b/samples/augmented_faces_java/app/build.gradle @@ -41,7 +41,7 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.36.0' + implementation 'com.google.ar:core:1.37.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/augmented_faces_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java b/samples/augmented_faces_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java new file mode 100644 index 000000000..5694cf898 --- /dev/null +++ b/samples/augmented_faces_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java @@ -0,0 +1,53 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.ar.core.examples.java.common.helpers; + +import android.content.Context; +import android.content.SharedPreferences; + +/** + * A class providing persistent EIS preference across instances using {@code + * android.content.SharedPreferences}. + */ +public class EisSettings { + public static final String SHARED_PREFERENCE_ID = "SHARED_PREFERENCE_EIS_OPTIONS"; + public static final String SHARED_PREFERENCE_EIS_ENABLED = "eis_enabled"; + private boolean eisEnabled = false; + private SharedPreferences sharedPreferences; + + /** Creates shared preference entry for EIS setting. */ + public void onCreate(Context context) { + sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCE_ID, Context.MODE_PRIVATE); + eisEnabled = sharedPreferences.getBoolean(SHARED_PREFERENCE_EIS_ENABLED, false); + } + + /** Returns saved EIS state. */ + public boolean isEisEnabled() { + return eisEnabled; + } + + /** Sets and saves the EIS using {@code android.content.SharedPreferences} */ + public void setEisEnabled(boolean enable) { + if (enable == eisEnabled) { + return; + } + + eisEnabled = enable; + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(SHARED_PREFERENCE_EIS_ENABLED, eisEnabled); + editor.apply(); + } +} diff --git a/samples/augmented_faces_java/gradle/wrapper/gradle-wrapper.jar b/samples/augmented_faces_java/gradle/wrapper/gradle-wrapper.jar index e708b1c02..943f0cbfa 100644 Binary files a/samples/augmented_faces_java/gradle/wrapper/gradle-wrapper.jar and b/samples/augmented_faces_java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/augmented_faces_java/gradlew b/samples/augmented_faces_java/gradlew index 4f906e0c8..65dcd68d6 100755 --- a/samples/augmented_faces_java/gradlew +++ b/samples/augmented_faces_java/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/samples/augmented_faces_java/gradlew.bat b/samples/augmented_faces_java/gradlew.bat index ac1b06f93..93e3f59f1 100644 --- a/samples/augmented_faces_java/gradlew.bat +++ b/samples/augmented_faces_java/gradlew.bat @@ -1,89 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/augmented_image_c/app/build.gradle b/samples/augmented_image_c/app/build.gradle index 0ab2c8892..208f7a8a1 100644 --- a/samples/augmented_image_c/app/build.gradle +++ b/samples/augmented_image_c/app/build.gradle @@ -68,8 +68,8 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.36.0' - natives 'com.google.ar:core:1.36.0' + implementation 'com.google.ar:core:1.37.0' + natives 'com.google.ar:core:1.37.0' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'com.google.android.material:material:1.1.0' diff --git a/samples/augmented_image_c/gradle/wrapper/gradle-wrapper.jar b/samples/augmented_image_c/gradle/wrapper/gradle-wrapper.jar index e708b1c02..943f0cbfa 100644 Binary files a/samples/augmented_image_c/gradle/wrapper/gradle-wrapper.jar and b/samples/augmented_image_c/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/augmented_image_c/gradlew b/samples/augmented_image_c/gradlew index 4f906e0c8..65dcd68d6 100755 --- a/samples/augmented_image_c/gradlew +++ b/samples/augmented_image_c/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/samples/augmented_image_c/gradlew.bat b/samples/augmented_image_c/gradlew.bat index ac1b06f93..93e3f59f1 100644 --- a/samples/augmented_image_c/gradlew.bat +++ b/samples/augmented_image_c/gradlew.bat @@ -1,89 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/augmented_image_java/app/build.gradle b/samples/augmented_image_java/app/build.gradle index 86a302a14..7ca627bd6 100644 --- a/samples/augmented_image_java/app/build.gradle +++ b/samples/augmented_image_java/app/build.gradle @@ -41,7 +41,7 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.36.0' + implementation 'com.google.ar:core:1.37.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java b/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java new file mode 100644 index 000000000..5694cf898 --- /dev/null +++ b/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java @@ -0,0 +1,53 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.ar.core.examples.java.common.helpers; + +import android.content.Context; +import android.content.SharedPreferences; + +/** + * A class providing persistent EIS preference across instances using {@code + * android.content.SharedPreferences}. + */ +public class EisSettings { + public static final String SHARED_PREFERENCE_ID = "SHARED_PREFERENCE_EIS_OPTIONS"; + public static final String SHARED_PREFERENCE_EIS_ENABLED = "eis_enabled"; + private boolean eisEnabled = false; + private SharedPreferences sharedPreferences; + + /** Creates shared preference entry for EIS setting. */ + public void onCreate(Context context) { + sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCE_ID, Context.MODE_PRIVATE); + eisEnabled = sharedPreferences.getBoolean(SHARED_PREFERENCE_EIS_ENABLED, false); + } + + /** Returns saved EIS state. */ + public boolean isEisEnabled() { + return eisEnabled; + } + + /** Sets and saves the EIS using {@code android.content.SharedPreferences} */ + public void setEisEnabled(boolean enable) { + if (enable == eisEnabled) { + return; + } + + eisEnabled = enable; + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(SHARED_PREFERENCE_EIS_ENABLED, eisEnabled); + editor.apply(); + } +} diff --git a/samples/augmented_image_java/gradle/wrapper/gradle-wrapper.jar b/samples/augmented_image_java/gradle/wrapper/gradle-wrapper.jar index e708b1c02..943f0cbfa 100644 Binary files a/samples/augmented_image_java/gradle/wrapper/gradle-wrapper.jar and b/samples/augmented_image_java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/augmented_image_java/gradlew b/samples/augmented_image_java/gradlew index 4f906e0c8..65dcd68d6 100755 --- a/samples/augmented_image_java/gradlew +++ b/samples/augmented_image_java/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/samples/augmented_image_java/gradlew.bat b/samples/augmented_image_java/gradlew.bat index ac1b06f93..93e3f59f1 100644 --- a/samples/augmented_image_java/gradlew.bat +++ b/samples/augmented_image_java/gradlew.bat @@ -1,89 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/cloud_anchor_java/app/build.gradle b/samples/cloud_anchor_java/app/build.gradle index 0936f636f..40057b720 100644 --- a/samples/cloud_anchor_java/app/build.gradle +++ b/samples/cloud_anchor_java/app/build.gradle @@ -41,7 +41,7 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.36.0' + implementation 'com.google.ar:core:1.37.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/cloudanchor/CloudAnchorActivity.java b/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/cloudanchor/CloudAnchorActivity.java index 9bcd9ab52..b0c159ef0 100644 --- a/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/cloudanchor/CloudAnchorActivity.java +++ b/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/cloudanchor/CloudAnchorActivity.java @@ -590,8 +590,7 @@ public void onError(DatabaseError error) { } @Override - public void onCloudTaskComplete(Anchor anchor) { - CloudAnchorState cloudState = anchor.getCloudAnchorState(); + public void onCloudTaskComplete(String cloudId, CloudAnchorState cloudState) { if (cloudState.isError()) { Log.e(TAG, "Error hosting a cloud anchor, state " + cloudState); snackbarHelper.showMessageWithDismiss( @@ -600,8 +599,7 @@ public void onCloudTaskComplete(Anchor anchor) { } Preconditions.checkState( cloudAnchorId == null, "The cloud anchor ID cannot have been set before."); - cloudAnchorId = anchor.getCloudAnchorId(); - setNewAnchor(anchor); + cloudAnchorId = cloudId; checkAndMaybeShare(); } @@ -624,9 +622,8 @@ private final class CloudAnchorResolveStateListener } @Override - public void onCloudTaskComplete(Anchor anchor) { + public void onCloudTaskComplete(Anchor anchor, CloudAnchorState cloudState) { // When the anchor has been resolved, or had a final error state. - CloudAnchorState cloudState = anchor.getCloudAnchorState(); if (cloudState.isError()) { Log.w( TAG, diff --git a/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/cloudanchor/CloudAnchorManager.java b/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/cloudanchor/CloudAnchorManager.java index 1326a3b58..512d0e4e9 100644 --- a/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/cloudanchor/CloudAnchorManager.java +++ b/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/cloudanchor/CloudAnchorManager.java @@ -17,14 +17,17 @@ package com.google.ar.core.examples.java.cloudanchor; import android.os.SystemClock; +import android.util.Pair; import androidx.annotation.Nullable; import com.google.ar.core.Anchor; import com.google.ar.core.Anchor.CloudAnchorState; +import com.google.ar.core.FutureState; +import com.google.ar.core.HostCloudAnchorFuture; +import com.google.ar.core.ResolveCloudAnchorFuture; import com.google.ar.core.Session; import com.google.common.base.Preconditions; -import java.util.HashMap; +import java.util.ArrayList; import java.util.Iterator; -import java.util.Map; /** * A helper class to handle all the Cloud Anchors logic, and add a callback-like mechanism on top of @@ -40,22 +43,28 @@ class CloudAnchorManager { interface CloudAnchorHostListener { /** This method is invoked when the results of a Cloud Anchor operation are available. */ - void onCloudTaskComplete(Anchor anchor); + void onCloudTaskComplete(@Nullable String cloudAnchorId, CloudAnchorState cloudAnchorState); } /** Listener for the results of a resolve operation. */ interface CloudAnchorResolveListener { /** This method is invoked when the results of a Cloud Anchor operation are available. */ - void onCloudTaskComplete(Anchor anchor); + void onCloudTaskComplete(@Nullable Anchor anchor, CloudAnchorState cloudAnchorState); /** This method show the toast message. */ void onShowResolveMessage(); } @Nullable private Session session = null; - private final HashMap pendingHostAnchors = new HashMap<>(); - private final HashMap pendingResolveAnchors = new HashMap<>(); + + /** The pending hosting operations. */ + private final ArrayList> hostTasks = + new ArrayList<>(); + + /** The pending resolving operations. */ + private final ArrayList> resolveTasks = + new ArrayList<>(); /** * This method is used to set the session, since it might not be available when this object is @@ -71,8 +80,8 @@ synchronized void setSession(Session session) { */ synchronized void hostCloudAnchor(Anchor anchor, CloudAnchorHostListener listener) { Preconditions.checkNotNull(session, "The session cannot be null."); - Anchor newAnchor = session.hostCloudAnchor(anchor); - pendingHostAnchors.put(newAnchor, listener); + HostCloudAnchorFuture future = session.hostCloudAnchorAsync(anchor, 1, null); + hostTasks.add(new Pair<>(future, listener)); } /** @@ -82,34 +91,35 @@ synchronized void hostCloudAnchor(Anchor anchor, CloudAnchorHostListener listene synchronized void resolveCloudAnchor( String anchorId, CloudAnchorResolveListener listener, long startTimeMillis) { Preconditions.checkNotNull(session, "The session cannot be null."); - Anchor newAnchor = session.resolveCloudAnchor(anchorId); + ResolveCloudAnchorFuture future = session.resolveCloudAnchorAsync(anchorId, null); + resolveTasks.add(new Pair<>(future, listener)); deadlineForMessageMillis = startTimeMillis + DURATION_FOR_NO_RESOLVE_RESULT_MS; - pendingResolveAnchors.put(newAnchor, listener); } /** Should be called after a {@link Session#update()} call. */ synchronized void onUpdate() { Preconditions.checkNotNull(session, "The session cannot be null."); - Iterator> hostIter = - pendingHostAnchors.entrySet().iterator(); + Iterator> hostIter = hostTasks.iterator(); while (hostIter.hasNext()) { - Map.Entry entry = hostIter.next(); - Anchor anchor = entry.getKey(); - if (isReturnableState(anchor.getCloudAnchorState())) { - CloudAnchorHostListener listener = entry.getValue(); - listener.onCloudTaskComplete(anchor); + Pair entry = hostIter.next(); + if (entry.first.getState() == FutureState.DONE) { + CloudAnchorHostListener listener = entry.second; + String cloudAnchorId = entry.first.getResultCloudAnchorId(); + CloudAnchorState cloudAnchorState = entry.first.getResultCloudAnchorState(); + listener.onCloudTaskComplete(cloudAnchorId, cloudAnchorState); hostIter.remove(); } } - Iterator> resolveIter = - pendingResolveAnchors.entrySet().iterator(); + Iterator> resolveIter = + resolveTasks.iterator(); while (resolveIter.hasNext()) { - Map.Entry entry = resolveIter.next(); - Anchor anchor = entry.getKey(); - CloudAnchorResolveListener listener = entry.getValue(); - if (isReturnableState(anchor.getCloudAnchorState())) { - listener.onCloudTaskComplete(anchor); + Pair entry = resolveIter.next(); + CloudAnchorResolveListener listener = entry.second; + if (entry.first.getState() == FutureState.DONE) { + Anchor anchor = entry.first.getResultAnchor(); + CloudAnchorState cloudAnchorState = entry.first.getResultCloudAnchorState(); + listener.onCloudTaskComplete(anchor, cloudAnchorState); resolveIter.remove(); } if (deadlineForMessageMillis > 0 && SystemClock.uptimeMillis() > deadlineForMessageMillis) { @@ -121,17 +131,8 @@ synchronized void onUpdate() { /** Used to clear any currently registered listeners, so they won't be called again. */ synchronized void clearListeners() { - pendingHostAnchors.clear(); + hostTasks.clear(); + resolveTasks.clear(); deadlineForMessageMillis = 0; } - - private static boolean isReturnableState(CloudAnchorState cloudState) { - switch (cloudState) { - case NONE: - case TASK_IN_PROGRESS: - return false; - default: - return true; - } - } } diff --git a/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java b/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java new file mode 100644 index 000000000..5694cf898 --- /dev/null +++ b/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java @@ -0,0 +1,53 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.ar.core.examples.java.common.helpers; + +import android.content.Context; +import android.content.SharedPreferences; + +/** + * A class providing persistent EIS preference across instances using {@code + * android.content.SharedPreferences}. + */ +public class EisSettings { + public static final String SHARED_PREFERENCE_ID = "SHARED_PREFERENCE_EIS_OPTIONS"; + public static final String SHARED_PREFERENCE_EIS_ENABLED = "eis_enabled"; + private boolean eisEnabled = false; + private SharedPreferences sharedPreferences; + + /** Creates shared preference entry for EIS setting. */ + public void onCreate(Context context) { + sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCE_ID, Context.MODE_PRIVATE); + eisEnabled = sharedPreferences.getBoolean(SHARED_PREFERENCE_EIS_ENABLED, false); + } + + /** Returns saved EIS state. */ + public boolean isEisEnabled() { + return eisEnabled; + } + + /** Sets and saves the EIS using {@code android.content.SharedPreferences} */ + public void setEisEnabled(boolean enable) { + if (enable == eisEnabled) { + return; + } + + eisEnabled = enable; + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(SHARED_PREFERENCE_EIS_ENABLED, eisEnabled); + editor.apply(); + } +} diff --git a/samples/cloud_anchor_java/gradle/wrapper/gradle-wrapper.jar b/samples/cloud_anchor_java/gradle/wrapper/gradle-wrapper.jar index e708b1c02..943f0cbfa 100644 Binary files a/samples/cloud_anchor_java/gradle/wrapper/gradle-wrapper.jar and b/samples/cloud_anchor_java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/cloud_anchor_java/gradlew b/samples/cloud_anchor_java/gradlew index 4f906e0c8..65dcd68d6 100755 --- a/samples/cloud_anchor_java/gradlew +++ b/samples/cloud_anchor_java/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/samples/cloud_anchor_java/gradlew.bat b/samples/cloud_anchor_java/gradlew.bat index ac1b06f93..93e3f59f1 100644 --- a/samples/cloud_anchor_java/gradlew.bat +++ b/samples/cloud_anchor_java/gradlew.bat @@ -1,89 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/computervision_c/app/build.gradle b/samples/computervision_c/app/build.gradle index 312d21f0b..2d1f75bac 100644 --- a/samples/computervision_c/app/build.gradle +++ b/samples/computervision_c/app/build.gradle @@ -68,8 +68,8 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.36.0' - natives 'com.google.ar:core:1.36.0' + implementation 'com.google.ar:core:1.37.0' + natives 'com.google.ar:core:1.37.0' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'com.google.android.material:material:1.1.0' diff --git a/samples/computervision_c/gradle/wrapper/gradle-wrapper.jar b/samples/computervision_c/gradle/wrapper/gradle-wrapper.jar index e708b1c02..943f0cbfa 100644 Binary files a/samples/computervision_c/gradle/wrapper/gradle-wrapper.jar and b/samples/computervision_c/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/computervision_c/gradlew b/samples/computervision_c/gradlew index 4f906e0c8..65dcd68d6 100755 --- a/samples/computervision_c/gradlew +++ b/samples/computervision_c/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/samples/computervision_c/gradlew.bat b/samples/computervision_c/gradlew.bat index ac1b06f93..93e3f59f1 100644 --- a/samples/computervision_c/gradlew.bat +++ b/samples/computervision_c/gradlew.bat @@ -1,89 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/computervision_java/app/build.gradle b/samples/computervision_java/app/build.gradle index 8072114ac..408e738d9 100644 --- a/samples/computervision_java/app/build.gradle +++ b/samples/computervision_java/app/build.gradle @@ -41,7 +41,7 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.36.0' + implementation 'com.google.ar:core:1.37.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java new file mode 100644 index 000000000..5694cf898 --- /dev/null +++ b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java @@ -0,0 +1,53 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.ar.core.examples.java.common.helpers; + +import android.content.Context; +import android.content.SharedPreferences; + +/** + * A class providing persistent EIS preference across instances using {@code + * android.content.SharedPreferences}. + */ +public class EisSettings { + public static final String SHARED_PREFERENCE_ID = "SHARED_PREFERENCE_EIS_OPTIONS"; + public static final String SHARED_PREFERENCE_EIS_ENABLED = "eis_enabled"; + private boolean eisEnabled = false; + private SharedPreferences sharedPreferences; + + /** Creates shared preference entry for EIS setting. */ + public void onCreate(Context context) { + sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCE_ID, Context.MODE_PRIVATE); + eisEnabled = sharedPreferences.getBoolean(SHARED_PREFERENCE_EIS_ENABLED, false); + } + + /** Returns saved EIS state. */ + public boolean isEisEnabled() { + return eisEnabled; + } + + /** Sets and saves the EIS using {@code android.content.SharedPreferences} */ + public void setEisEnabled(boolean enable) { + if (enable == eisEnabled) { + return; + } + + eisEnabled = enable; + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(SHARED_PREFERENCE_EIS_ENABLED, eisEnabled); + editor.apply(); + } +} diff --git a/samples/computervision_java/gradle/wrapper/gradle-wrapper.jar b/samples/computervision_java/gradle/wrapper/gradle-wrapper.jar index e708b1c02..943f0cbfa 100644 Binary files a/samples/computervision_java/gradle/wrapper/gradle-wrapper.jar and b/samples/computervision_java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/computervision_java/gradlew b/samples/computervision_java/gradlew index 4f906e0c8..65dcd68d6 100755 --- a/samples/computervision_java/gradlew +++ b/samples/computervision_java/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/samples/computervision_java/gradlew.bat b/samples/computervision_java/gradlew.bat index ac1b06f93..93e3f59f1 100644 --- a/samples/computervision_java/gradlew.bat +++ b/samples/computervision_java/gradlew.bat @@ -1,89 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/geospatial_java/app/build.gradle b/samples/geospatial_java/app/build.gradle index f471b2c25..764657ac0 100644 --- a/samples/geospatial_java/app/build.gradle +++ b/samples/geospatial_java/app/build.gradle @@ -41,7 +41,7 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.36.0' + implementation 'com.google.ar:core:1.37.0' implementation 'com.google.android.gms:play-services-location:19.0.1' implementation 'com.google.android.gms:play-services-auth:19.0.0' diff --git a/samples/geospatial_java/app/src/main/assets/shaders/streetscape_geometry.frag b/samples/geospatial_java/app/src/main/assets/shaders/streetscape_geometry.frag new file mode 100644 index 000000000..199b53514 --- /dev/null +++ b/samples/geospatial_java/app/src/main/assets/shaders/streetscape_geometry.frag @@ -0,0 +1,22 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +precision mediump float; +varying vec4 v_Color; + +void main() { + gl_FragColor = v_Color; +} diff --git a/samples/geospatial_java/app/src/main/assets/shaders/streetscape_geometry.vert b/samples/geospatial_java/app/src/main/assets/shaders/streetscape_geometry.vert new file mode 100644 index 000000000..87fb23b36 --- /dev/null +++ b/samples/geospatial_java/app/src/main/assets/shaders/streetscape_geometry.vert @@ -0,0 +1,29 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +uniform mat4 u_ModelViewProjection; +uniform vec4 u_Color; +uniform float u_PointSize; + +attribute vec4 a_Position; + +varying vec4 v_Color; + +void main() { + v_Color = u_Color; + gl_Position = u_ModelViewProjection * vec4(a_Position.xyz, 1.0); + gl_PointSize = u_PointSize; +} diff --git a/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java b/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java new file mode 100644 index 000000000..5694cf898 --- /dev/null +++ b/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/common/helpers/EisSettings.java @@ -0,0 +1,53 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.ar.core.examples.java.common.helpers; + +import android.content.Context; +import android.content.SharedPreferences; + +/** + * A class providing persistent EIS preference across instances using {@code + * android.content.SharedPreferences}. + */ +public class EisSettings { + public static final String SHARED_PREFERENCE_ID = "SHARED_PREFERENCE_EIS_OPTIONS"; + public static final String SHARED_PREFERENCE_EIS_ENABLED = "eis_enabled"; + private boolean eisEnabled = false; + private SharedPreferences sharedPreferences; + + /** Creates shared preference entry for EIS setting. */ + public void onCreate(Context context) { + sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCE_ID, Context.MODE_PRIVATE); + eisEnabled = sharedPreferences.getBoolean(SHARED_PREFERENCE_EIS_ENABLED, false); + } + + /** Returns saved EIS state. */ + public boolean isEisEnabled() { + return eisEnabled; + } + + /** Sets and saves the EIS using {@code android.content.SharedPreferences} */ + public void setEisEnabled(boolean enable) { + if (enable == eisEnabled) { + return; + } + + eisEnabled = enable; + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(SHARED_PREFERENCE_EIS_ENABLED, eisEnabled); + editor.apply(); + } +} diff --git a/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/geospatial/GeospatialActivity.java b/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/geospatial/GeospatialActivity.java index c4da1f301..5b7e809cd 100644 --- a/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/geospatial/GeospatialActivity.java +++ b/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/geospatial/GeospatialActivity.java @@ -22,24 +22,25 @@ import android.opengl.GLSurfaceView; import android.opengl.Matrix; import android.os.Bundle; -import android.os.SystemClock; import android.util.Log; import android.view.GestureDetector; +import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.CompoundButton; +import android.widget.PopupMenu; import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.GuardedBy; import androidx.appcompat.app.AppCompatActivity; -import androidx.concurrent.futures.CallbackToFutureAdapter; import androidx.fragment.app.DialogFragment; import com.google.android.gms.location.FusedLocationProviderClient; import com.google.android.gms.location.LocationServices; import com.google.android.gms.tasks.OnSuccessListener; import com.google.ar.core.Anchor; +import com.google.ar.core.Anchor.RooftopAnchorState; import com.google.ar.core.Anchor.TerrainAnchorState; import com.google.ar.core.ArCoreApk; import com.google.ar.core.Camera; @@ -53,7 +54,10 @@ import com.google.ar.core.Point.OrientationMode; import com.google.ar.core.PointCloud; import com.google.ar.core.Pose; +import com.google.ar.core.ResolveAnchorOnRooftopFuture; +import com.google.ar.core.ResolveAnchorOnTerrainFuture; import com.google.ar.core.Session; +import com.google.ar.core.StreetscapeGeometry; import com.google.ar.core.Trackable; import com.google.ar.core.TrackingState; import com.google.ar.core.VpsAvailability; @@ -65,9 +69,11 @@ import com.google.ar.core.examples.java.common.helpers.SnackbarHelper; import com.google.ar.core.examples.java.common.helpers.TrackingStateHelper; import com.google.ar.core.examples.java.common.samplerender.Framebuffer; +import com.google.ar.core.examples.java.common.samplerender.IndexBuffer; import com.google.ar.core.examples.java.common.samplerender.Mesh; import com.google.ar.core.examples.java.common.samplerender.SampleRender; import com.google.ar.core.examples.java.common.samplerender.Shader; +import com.google.ar.core.examples.java.common.samplerender.Shader.BlendFactor; import com.google.ar.core.examples.java.common.samplerender.Texture; import com.google.ar.core.examples.java.common.samplerender.VertexBuffer; import com.google.ar.core.examples.java.common.samplerender.arcore.BackgroundRenderer; @@ -75,18 +81,16 @@ import com.google.ar.core.exceptions.CameraNotAvailableException; import com.google.ar.core.exceptions.FineLocationPermissionNotGrantedException; import com.google.ar.core.exceptions.GooglePlayServicesLocationLibraryNotLinkedException; -import com.google.ar.core.exceptions.ResourceExhaustedException; import com.google.ar.core.exceptions.UnavailableApkTooOldException; import com.google.ar.core.exceptions.UnavailableArcoreNotInstalledException; import com.google.ar.core.exceptions.UnavailableDeviceNotCompatibleException; import com.google.ar.core.exceptions.UnavailableSdkTooOldException; import com.google.ar.core.exceptions.UnavailableUserDeclinedInstallationException; import com.google.ar.core.exceptions.UnsupportedConfigurationException; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import java.io.IOException; +import java.nio.FloatBuffer; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -110,6 +114,7 @@ public class GeospatialActivity extends AppCompatActivity private static final String SHARED_PREFERENCES_SAVED_ANCHORS = "SHARED_PREFERENCES_SAVED_ANCHORS"; private static final String ALLOW_GEOSPATIAL_ACCESS_KEY = "ALLOW_GEOSPATIAL_ACCESS"; + private static final String ANCHOR_MODE = "ANCHOR_MODE"; private static final float Z_NEAR = 0.1f; private static final float Z_FAR = 1000f; @@ -126,7 +131,7 @@ public class GeospatialActivity extends AppCompatActivity private static final double LOCALIZED_ORIENTATION_YAW_ACCURACY_HYSTERESIS_DEGREES = 10; private static final int LOCALIZING_TIMEOUT_SECONDS = 180; - private static final int MAXIMUM_ANCHORS = 5; + private static final int MAXIMUM_ANCHORS = 20; private static final long DURATION_FOR_NO_TERRAIN_ANCHOR_RESULT_MS = 10000; // Rendering. The Renderers are created here, and initialized when the GL surface is created. @@ -165,14 +170,23 @@ enum State { private State state = State.UNINITIALIZED; + enum AnchorType { + // Set WGS84 anchor. + GEOSPATIAL, + // Set Terrain anchor. + TERRAIN, + // Set Rooftop anchor. + ROOFTOP + } + + private AnchorType anchorType = AnchorType.GEOSPATIAL; + private Session session; private final SnackbarHelper messageSnackbarHelper = new SnackbarHelper(); private DisplayRotationHelper displayRotationHelper; private final TrackingStateHelper trackingStateHelper = new TrackingStateHelper(this); private SampleRender render; private SharedPreferences sharedPreferences; - private final HashMap pendingTerrainAnchors = - new HashMap<>(); private String lastStatusText; private TextView geospatialPoseTextView; @@ -180,14 +194,14 @@ enum State { private TextView tapScreenTextView; private Button setAnchorButton; private Button clearAnchorsButton; - private Switch terrainAnchorSwitch; + private Switch streetscapeGeometrySwitch; private PlaneRenderer planeRenderer; private BackgroundRenderer backgroundRenderer; private Framebuffer virtualSceneFramebuffer; private boolean hasSetTextureNames = false; - // Set WGS84 anchor or Terrain anchor. - private boolean isTerrainAnchorMode = false; + // Set rendering Streetscape Geometry. + private boolean isRenderStreetscapeGeometry = false; // Virtual object (ARCore geospatial) private Mesh virtualObjectMesh; @@ -195,8 +209,14 @@ enum State { // Virtual object (ARCore geospatial terrain) private Shader terrainAnchorVirtualObjectShader; + private final Object anchorsLock = new Object(); + + @GuardedBy("anchorsLock") private final List anchors = new ArrayList<>(); + private final Set terrainAnchors = new HashSet<>(); + private final Set rooftopAnchors = new HashSet<>(); + // Temporary matrix allocated here to reduce number of allocations for each frame. private final float[] modelMatrix = new float[16]; private final float[] viewMatrix = new float[16]; @@ -204,6 +224,8 @@ enum State { private final float[] modelViewMatrix = new float[16]; // view x model private final float[] modelViewProjectionMatrix = new float[16]; // projection x view x model + private final float[] identityQuaternion = {0, 0, 0, 1}; + // Locks needed for synchronization private final Object singleTapLock = new Object(); @@ -223,6 +245,14 @@ enum State { // Provides device location. private FusedLocationProviderClient fusedLocationClient; + // Streetscape geometry. + private final ArrayList wallsColor = new ArrayList(); + + private Shader streetscapeGeometryTerrainShader; + private Shader streetscapeGeometryBuildingShader; + // A set of planes representing building outlines and floors. + private final Map streetscapeGeometryToMeshes = new HashMap<>(); + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -236,15 +266,29 @@ protected void onCreate(Bundle savedInstanceState) { setAnchorButton = findViewById(R.id.set_anchor_button); clearAnchorsButton = findViewById(R.id.clear_anchors_button); - setAnchorButton.setOnClickListener(view -> handleSetAnchorButton()); + setAnchorButton.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + PopupMenu popup = new PopupMenu(GeospatialActivity.this, v); + popup.setOnMenuItemClickListener(GeospatialActivity.this::settingsMenuClick); + popup.inflate(R.menu.setting_menu); + popup.show(); + popup + .getMenu() + .findItem(sharedPreferences.getInt(ANCHOR_MODE, R.id.geospatial)) + .setChecked(true); + } + }); + clearAnchorsButton.setOnClickListener(view -> handleClearAnchorsButton()); - terrainAnchorSwitch = findViewById(R.id.terrain_anchor_switch); + streetscapeGeometrySwitch = findViewById(R.id.streetscape_geometry_switch); // Initial terrain anchor mode is DISABLED. - terrainAnchorSwitch.setChecked(false); - terrainAnchorSwitch.setOnCheckedChangeListener(this::onTerrainAnchorModeChanged); + streetscapeGeometrySwitch.setChecked(false); + streetscapeGeometrySwitch.setOnCheckedChangeListener(this::onRenderStreetscapeGeometryChanged); - displayRotationHelper = new DisplayRotationHelper(/*activity=*/ this); + displayRotationHelper = new DisplayRotationHelper(/* activity= */ this); // Set up renderer. render = new SampleRender(surfaceView, this, getAssets()); @@ -271,7 +315,7 @@ public boolean onDown(MotionEvent e) { } }); surfaceView.setOnTouchListener((v, event) -> gestureDetector.onTouchEvent(event)); - fusedLocationClient = LocationServices.getFusedLocationProviderClient(/*context=*/ this); + fusedLocationClient = LocationServices.getFusedLocationProviderClient(/* context= */ this); } @Override @@ -291,7 +335,7 @@ protected void onDestroy() { @Override protected void onResume() { super.onResume(); - if (sharedPreferences.getBoolean(ALLOW_GEOSPATIAL_ACCESS_KEY, /*defValue=*/ false)) { + if (sharedPreferences.getBoolean(ALLOW_GEOSPATIAL_ACCESS_KEY, /* defValue= */ false)) { createSession(); } else { showPrivacyNoticeDialog(); @@ -424,24 +468,15 @@ public void onSuccess(Location location) { } private void checkVpsAvailability(double latitude, double longitude) { - ListenableFuture availabilityFuture = - checkVpsAvailabilityFuture(latitude, longitude); - Futures.addCallback( - availabilityFuture, - new FutureCallback() { - @Override - public void onSuccess(VpsAvailability result) { - if (result != VpsAvailability.AVAILABLE) { - showVpsNotAvailabilityNoticeDialog(); - } - } - - @Override - public void onFailure(Throwable t) { - Log.e(TAG, "Error checking VPS availability", t); - } - }, - getMainExecutor()); + final VpsAvailabilityFuture future = + session.checkVpsAvailabilityAsync( + latitude, + longitude, + availability -> { + if (availability != VpsAvailability.AVAILABLE) { + showVpsNotAvailabilityNoticeDialog(); + } + }); } private void showVpsNotAvailabilityNoticeDialog() { @@ -505,7 +540,7 @@ public void onSurfaceCreated(SampleRender render) { try { planeRenderer = new PlaneRenderer(render); backgroundRenderer = new BackgroundRenderer(render); - virtualSceneFramebuffer = new Framebuffer(render, /*width=*/ 1, /*height=*/ 1); + virtualSceneFramebuffer = new Framebuffer(render, /* width= */ 1, /* height= */ 1); // Virtual object to render (ARCore geospatial) Texture virtualObjectTexture = @@ -521,7 +556,7 @@ public void onSurfaceCreated(SampleRender render) { render, "shaders/ar_unlit_object.vert", "shaders/ar_unlit_object.frag", - /*defines=*/ null) + /* defines= */ null) .setTexture("u_Texture", virtualObjectTexture); // Virtual object to render (Terrain anchor marker) @@ -536,7 +571,7 @@ public void onSurfaceCreated(SampleRender render) { render, "shaders/ar_unlit_object.vert", "shaders/ar_unlit_object.frag", - /*defines=*/ null) + /* defines= */ null) .setTexture("u_Texture", terrainAnchorVirtualObjectTexture); backgroundRenderer.setUseDepthVisualization(render, false); @@ -545,17 +580,43 @@ public void onSurfaceCreated(SampleRender render) { // Point cloud pointCloudShader = Shader.createFromAssets( - render, "shaders/point_cloud.vert", "shaders/point_cloud.frag", /*defines=*/ null) + render, + "shaders/point_cloud.vert", + "shaders/point_cloud.frag", + /* defines= */ null) .setVec4( "u_Color", new float[] {31.0f / 255.0f, 188.0f / 255.0f, 210.0f / 255.0f, 1.0f}) .setFloat("u_PointSize", 5.0f); // four entries per vertex: X, Y, Z, confidence pointCloudVertexBuffer = - new VertexBuffer(render, /*numberOfEntriesPerVertex=*/ 4, /*entries=*/ null); + new VertexBuffer(render, /* numberOfEntriesPerVertex= */ 4, /* entries= */ null); final VertexBuffer[] pointCloudVertexBuffers = {pointCloudVertexBuffer}; pointCloudMesh = new Mesh( - render, Mesh.PrimitiveMode.POINTS, /*indexBuffer=*/ null, pointCloudVertexBuffers); + render, Mesh.PrimitiveMode.POINTS, /* indexBuffer= */ null, pointCloudVertexBuffers); + + streetscapeGeometryBuildingShader = + Shader.createFromAssets( + render, + "shaders/streetscape_geometry.vert", + "shaders/streetscape_geometry.frag", + /* defines= */ null) + .setBlend( + BlendFactor.DST_ALPHA, // RGB (src) + BlendFactor.ONE); // ALPHA (dest) + + streetscapeGeometryTerrainShader = + Shader.createFromAssets( + render, + "shaders/streetscape_geometry.vert", + "shaders/streetscape_geometry.frag", + /* defines= */ null) + .setBlend( + BlendFactor.DST_ALPHA, // RGB (src) + BlendFactor.ONE); // ALPHA (dest) + wallsColor.add(new float[] {0.5f, 0.0f, 0.5f, 0.3f}); + wallsColor.add(new float[] {0.5f, 0.5f, 0.0f, 0.3f}); + wallsColor.add(new float[] {0.0f, 0.5f, 0.5f, 0.3f}); } catch (IOException e) { Log.e(TAG, "Failed to read a required asset file", e); messageSnackbarHelper.showError(this, "Failed to read a required asset file: " + e); @@ -588,6 +649,7 @@ public void onDrawFrame(SampleRender render) { // Notify ARCore session that the view size changed so that the perspective matrix and // the video background can be properly adjusted. displayRotationHelper.updateSessionIfNeeded(session); + updateStreetscapeGeometries(session.getAllTrackables(StreetscapeGeometry.class)); // Obtain the current frame from ARSession. When the configuration is set to // UpdateMode.BLOCKING (it is by default), this will throttle the rendering to the @@ -636,24 +698,7 @@ public void onDrawFrame(SampleRender render) { message = getResources().getString(R.string.status_localize_timeout); break; case LOCALIZED: - if (pendingTerrainAnchors.size() > 0) { - // If there is a terrain anchor, show terrain anchor state. - for (Map.Entry entry : - pendingTerrainAnchors.entrySet()) { - Anchor anchor = entry.getKey(); - TerrainAnchorResolveListener listener = entry.getValue(); - if (anchor.getTerrainAnchorState() != TerrainAnchorState.TASK_IN_PROGRESS) { - listener.onTaskComplete(anchor); - pendingTerrainAnchors.remove(anchor); - } - if (deadlineForMessageMillis > 0 - && SystemClock.uptimeMillis() > deadlineForMessageMillis) { - listener.onDeadlineExceeded(); - deadlineForMessageMillis = 0; - pendingTerrainAnchors.remove(anchor); - } - } - } else if (lastStatusText.equals(getResources().getString(R.string.status_localize_hint))) { + if (lastStatusText.equals(getResources().getString(R.string.status_localize_hint))) { message = getResources().getString(R.string.status_localize_complete); } break; @@ -667,6 +712,15 @@ public void onDrawFrame(SampleRender render) { statusTextView.setText(lastStatusText); }); } + synchronized (anchorsLock) { + if (anchors.size() >= MAXIMUM_ANCHORS) { + runOnUiThread( + () -> { + setAnchorButton.setVisibility(View.INVISIBLE); + tapScreenTextView.setVisibility(View.INVISIBLE); + }); + } + } // Handle user input. handleTap(frame, camera.getTrackingState()); @@ -713,37 +767,90 @@ public void onDrawFrame(SampleRender render) { // Visualize anchors created by touch. render.clear(virtualSceneFramebuffer, 0f, 0f, 0f, 0f); - for (Anchor anchor : anchors) { - // Get the current pose of an Anchor in world space. The Anchor pose is updated - // during calls to session.update() as ARCore refines its estimate of the world. - // Only render resolved Terrain anchors and Geospatial anchors. - if (anchor.getTerrainAnchorState() != TerrainAnchorState.SUCCESS - && anchor.getTerrainAnchorState() != TerrainAnchorState.NONE) { - continue; + // -- Draw Streetscape Geometries. + if (isRenderStreetscapeGeometry) { + int index = 0; + for (Map.Entry set : streetscapeGeometryToMeshes.entrySet()) { + StreetscapeGeometry streetscapeGeometry = set.getKey(); + if (streetscapeGeometry.getTrackingState() != TrackingState.TRACKING) { + continue; + } + Mesh mesh = set.getValue(); + Pose pose = streetscapeGeometry.getMeshPose(); + pose.toMatrix(modelMatrix, 0); + + // Calculate model/view/projection matrices + Matrix.multiplyMM(modelViewMatrix, 0, viewMatrix, 0, modelMatrix, 0); + Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, modelViewMatrix, 0); + + if (streetscapeGeometry.getType() == StreetscapeGeometry.Type.BUILDING) { + float[] color = wallsColor.get(index % wallsColor.size()); + index += 1; + streetscapeGeometryBuildingShader + .setVec4( + "u_Color", + new float[] {/* r= */ color[0], /* g= */ color[1], /* b= */ color[2], color[3]}) + .setMat4("u_ModelViewProjection", modelViewProjectionMatrix); + render.draw(mesh, streetscapeGeometryBuildingShader); + } else if (streetscapeGeometry.getType() == StreetscapeGeometry.Type.TERRAIN) { + streetscapeGeometryTerrainShader + .setVec4("u_Color", new float[] {/* r= */ 0f, /* g= */ .5f, /* b= */ 0f, 0.3f}) + .setMat4("u_ModelViewProjection", modelViewProjectionMatrix); + render.draw(mesh, streetscapeGeometryTerrainShader); + } } - anchor.getPose().toMatrix(modelMatrix, 0); - - // Rotate the virtual object 180 degrees around the Y axis to make the object face the GL - // camera -Z axis, since camera Z axis faces toward users. - float[] rotationMatrix = new float[16]; - Matrix.setRotateM(rotationMatrix, 0, 180, 0.0f, 1.0f, 0.0f); - float[] rotationModelMatrix = new float[16]; - Matrix.multiplyMM(rotationModelMatrix, 0, modelMatrix, 0, rotationMatrix, 0); - // Calculate model/view/projection matrices - Matrix.multiplyMM(modelViewMatrix, 0, viewMatrix, 0, rotationModelMatrix, 0); - Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, modelViewMatrix, 0); - // Update shader properties and draw - if (anchor.getTerrainAnchorState() == TerrainAnchorState.SUCCESS) { - terrainAnchorVirtualObjectShader.setMat4( - "u_ModelViewProjection", modelViewProjectionMatrix); - - render.draw(virtualObjectMesh, terrainAnchorVirtualObjectShader, virtualSceneFramebuffer); - } else { - geospatialAnchorVirtualObjectShader.setMat4( - "u_ModelViewProjection", modelViewProjectionMatrix); - render.draw( - virtualObjectMesh, geospatialAnchorVirtualObjectShader, virtualSceneFramebuffer); + } + render.clear(virtualSceneFramebuffer, 0f, 0f, 0f, 0f); + synchronized (anchorsLock) { + for (Anchor anchor : anchors) { + // Get the current pose of an Anchor in world space. The Anchor pose is updated + // during calls to session.update() as ARCore refines its estimate of the world. + // Only render resolved Terrain & Rooftop anchors and Geospatial anchors. + if (anchor.getTrackingState() != TrackingState.TRACKING) { + continue; + } + anchor.getPose().toMatrix(modelMatrix, 0); + float[] scaleMatrix = new float[16]; + Matrix.setIdentityM(scaleMatrix, 0); + float scale = getScale(anchor.getPose(), camera.getDisplayOrientedPose()); + scaleMatrix[0] = scale; + scaleMatrix[5] = scale; + scaleMatrix[10] = scale; + Matrix.multiplyMM(modelMatrix, 0, modelMatrix, 0, scaleMatrix, 0); + // Rotate the virtual object 180 degrees around the Y axis to make the object face the GL + // camera -Z axis, since camera Z axis faces toward users. + float[] rotationMatrix = new float[16]; + Matrix.setRotateM(rotationMatrix, 0, 180, 0.0f, 1.0f, 0.0f); + float[] rotationModelMatrix = new float[16]; + Matrix.multiplyMM(rotationModelMatrix, 0, modelMatrix, 0, rotationMatrix, 0); + // Calculate model/view/projection matrices + Matrix.multiplyMM(modelViewMatrix, 0, viewMatrix, 0, rotationModelMatrix, 0); + Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, modelViewMatrix, 0); + + // Update shader properties and draw + if (terrainAnchors.contains(anchor) || rooftopAnchors.contains(anchor)) { + terrainAnchorVirtualObjectShader.setMat4( + "u_ModelViewProjection", modelViewProjectionMatrix); + + render.draw(virtualObjectMesh, terrainAnchorVirtualObjectShader, virtualSceneFramebuffer); + } else { + geospatialAnchorVirtualObjectShader.setMat4( + "u_ModelViewProjection", modelViewProjectionMatrix); + render.draw( + virtualObjectMesh, geospatialAnchorVirtualObjectShader, virtualSceneFramebuffer); + } + } + if (anchors.size() > 0) { + String anchorMessage = + getResources() + .getQuantityString( + R.plurals.status_anchors_set, anchors.size(), anchors.size(), MAXIMUM_ANCHORS); + runOnUiThread( + () -> { + statusTextView.setVisibility(View.VISIBLE); + statusTextView.setText(anchorMessage); + }); } } @@ -751,6 +858,39 @@ public void onDrawFrame(SampleRender render) { backgroundRenderer.drawVirtualScene(render, virtualSceneFramebuffer, Z_NEAR, Z_FAR); } + /** + * Updates all the StreetscapeGeometries. Existing StreetscapeGeometries will have pose updated, + * and non-existing StreetscapeGeometries will be removed from the scene. + */ + private void updateStreetscapeGeometries(Collection streetscapeGeometries) { + for (StreetscapeGeometry streetscapeGeometry : streetscapeGeometries) { + // If the Streetscape Geometry node is already added to the scene, then we'll simply update + // the pose. + if (streetscapeGeometryToMeshes.containsKey(streetscapeGeometry)) { + } else { + // Otherwise, we create a StreetscapeGeometry mesh and add it to the scene. + Mesh mesh = getSampleRenderMesh(streetscapeGeometry); + streetscapeGeometryToMeshes.put(streetscapeGeometry, mesh); + } + } + } + + private Mesh getSampleRenderMesh(StreetscapeGeometry streetscapeGeometry) { + FloatBuffer streetscapeGeometryBuffer = streetscapeGeometry.getMesh().getVertexList(); + streetscapeGeometryBuffer.rewind(); + VertexBuffer meshVertexBuffer = + new VertexBuffer( + render, /* numberOfEntriesPerVertex= */ 3, /* entries= */ streetscapeGeometryBuffer); + IndexBuffer meshIndexBuffer = + new IndexBuffer(render, streetscapeGeometry.getMesh().getIndexList()); + final VertexBuffer[] meshVertexBuffers = {meshVertexBuffer}; + return new Mesh( + render, + Mesh.PrimitiveMode.TRIANGLES, + /* indexBuffer= */ meshIndexBuffer, + meshVertexBuffers); + } + /** Configures the session with feature settings. */ private void configureSession() { // Earth mode may not be supported on this device due to insufficient sensor quality. @@ -760,7 +900,10 @@ private void configureSession() { } Config config = session.getConfig(); - config.setGeospatialMode(Config.GeospatialMode.ENABLED); + config = + config + .setGeospatialMode(Config.GeospatialMode.ENABLED) + .setStreetscapeGeometryMode(Config.StreetscapeGeometryMode.ENABLED); session.configure(config); state = State.PRETRACKING; localizingStartTimestamp = System.currentTimeMillis(); @@ -812,18 +955,21 @@ private void updateLocalizingState(Earth earth) { && geospatialPose.getOrientationYawAccuracy() <= LOCALIZING_ORIENTATION_YAW_ACCURACY_THRESHOLD_DEGREES) { state = State.LOCALIZED; - if (anchors.isEmpty()) { - createAnchorFromSharedPreferences(earth); - } - if (anchors.size() < MAXIMUM_ANCHORS) { - runOnUiThread( - () -> { - setAnchorButton.setVisibility(View.VISIBLE); - tapScreenTextView.setVisibility(View.VISIBLE); - if (anchors.size() > 0) { - clearAnchorsButton.setVisibility(View.VISIBLE); - } - }); + synchronized (anchorsLock) { + final int anchorNum = anchors.size(); + if (anchorNum == 0) { + createAnchorFromSharedPreferences(earth); + } + if (anchorNum < MAXIMUM_ANCHORS) { + runOnUiThread( + () -> { + setAnchorButton.setVisibility(View.VISIBLE); + tapScreenTextView.setVisibility(View.VISIBLE); + if (anchorNum > 0) { + clearAnchorsButton.setVisibility(View.VISIBLE); + } + }); + } } return; } @@ -889,20 +1035,44 @@ private void updateGeospatialPoseText(GeospatialPose geospatialPose) { }); } + // Return the scale in range [1, 2] after mapping a distance between camera and anchor to [2, 20]. + private float getScale(Pose anchorPose, Pose cameraPose) { + double distance = + Math.sqrt( + Math.pow(anchorPose.tx() - cameraPose.tx(), 2.0) + + Math.pow(anchorPose.ty() - cameraPose.ty(), 2.0) + + Math.pow(anchorPose.tz() - cameraPose.tz(), 2.0)); + double mapDistance = Math.min(Math.max(2, distance), 20); + return (float) (mapDistance - 2) / (20 - 2) + 1; + } + /** * Handles the button that creates an anchor. * *

Ensure Earth is in the proper state, then create the anchor. Persist the parameters used to * create the anchors so that the anchors will be loaded next time the app is launched. */ - private void handleSetAnchorButton() { - Earth earth = session.getEarth(); - if (earth == null || earth.getTrackingState() != TrackingState.TRACKING) { - return; - } + private void handleSetAnchorButton() {} - GeospatialPose geospatialPose = earth.getCameraGeospatialPose(); - createAnchorWithGeospatialPose(earth, geospatialPose); + /** Menu button to choose anchor type. */ + protected boolean settingsMenuClick(MenuItem item) { + int itemId = item.getItemId(); + if (itemId == R.id.anchor_reset) { + return true; + } + item.setChecked(!item.isChecked()); + sharedPreferences.edit().putInt(ANCHOR_MODE, itemId).commit(); + if (itemId == R.id.geospatial) { + anchorType = AnchorType.GEOSPATIAL; + return true; + } else if (itemId == R.id.terrain) { + anchorType = AnchorType.TERRAIN; + return true; + } else if (itemId == R.id.rooftop) { + anchorType = AnchorType.ROOFTOP; + return true; + } + return false; } /** Creates anchor with the provided GeospatialPose, either from camera or HitResult. */ @@ -911,20 +1081,19 @@ private void createAnchorWithGeospatialPose(Earth earth, GeospatialPose geospati double longitude = geospatialPose.getLongitude(); double altitude = geospatialPose.getAltitude(); float[] quaternion = geospatialPose.getEastUpSouthQuaternion(); - if (isTerrainAnchorMode) { - createTerrainAnchor(earth, latitude, longitude, quaternion); - storeAnchorParameters(latitude, longitude, 0, quaternion); - } else { - createAnchor(earth, latitude, longitude, altitude, quaternion); - storeAnchorParameters(latitude, longitude, altitude, quaternion); - String message = - getResources() - .getQuantityString(R.plurals.status_anchors_set, anchors.size(), anchors.size()); - runOnUiThread( - () -> { - statusTextView.setVisibility(View.VISIBLE); - statusTextView.setText(message); - }); + switch (anchorType) { + case TERRAIN: + createTerrainAnchor(earth, latitude, longitude, identityQuaternion); + storeAnchorParameters(latitude, longitude, 0, identityQuaternion); + break; + case GEOSPATIAL: + createAnchor(earth, latitude, longitude, altitude, quaternion); + storeAnchorParameters(latitude, longitude, altitude, quaternion); + break; + case ROOFTOP: + createRooftopAnchor(earth, latitude, longitude, identityQuaternion); + storeAnchorParameters(latitude, longitude, 0, identityQuaternion); + break; } runOnUiThread( () -> { @@ -936,19 +1105,21 @@ private void createAnchorWithGeospatialPose(Earth earth, GeospatialPose geospati } private void handleClearAnchorsButton() { - clearedAnchorsAmount = anchors.size(); - String message = - getResources() - .getQuantityString( - R.plurals.status_anchors_cleared, clearedAnchorsAmount, clearedAnchorsAmount); + synchronized (anchorsLock) { + clearedAnchorsAmount = anchors.size(); + String message = + getResources() + .getQuantityString( + R.plurals.status_anchors_cleared, clearedAnchorsAmount, clearedAnchorsAmount); - statusTextView.setVisibility(View.VISIBLE); - statusTextView.setText(message); + statusTextView.setVisibility(View.VISIBLE); + statusTextView.setText(message); - for (Anchor anchor : anchors) { - anchor.detach(); + for (Anchor anchor : anchors) { + anchor.detach(); + } + anchors.clear(); } - anchors.clear(); clearAnchorsFromSharedPreferences(); clearAnchorsButton.setVisibility(View.INVISIBLE); setAnchorButton.setVisibility(View.VISIBLE); @@ -967,48 +1138,59 @@ private void createAnchor( quaternion[1], quaternion[2], quaternion[3]); - anchors.add(anchor); - if (anchors.size() >= MAXIMUM_ANCHORS) { - runOnUiThread( - () -> { - setAnchorButton.setVisibility(View.INVISIBLE); - tapScreenTextView.setVisibility(View.INVISIBLE); - }); + synchronized (anchorsLock) { + anchors.add(anchor); } } /** Create a terrain anchor at a specific geodetic location using a EUS quaternion. */ private void createTerrainAnchor( Earth earth, double latitude, double longitude, float[] quaternion) { - Anchor anchor = null; - try { - anchor = - earth.resolveAnchorOnTerrain( - latitude, - longitude, - /* altitudeAboveTerrain= */ 0.0f, - quaternion[0], - quaternion[1], - quaternion[2], - quaternion[3]); - anchors.add(anchor); - if (anchors.size() >= MAXIMUM_ANCHORS) { - runOnUiThread( - () -> { - setAnchorButton.setVisibility(View.INVISIBLE); - tapScreenTextView.setVisibility(View.INVISIBLE); + final ResolveAnchorOnTerrainFuture future = + earth.resolveAnchorOnTerrainAsync( + latitude, + longitude, + /* altitudeAboveTerrain= */ 0.0f, + quaternion[0], + quaternion[1], + quaternion[2], + quaternion[3], + (anchor, state) -> { + if (state == TerrainAnchorState.SUCCESS) { + synchronized (anchorsLock) { + anchors.add(anchor); + terrainAnchors.add(anchor); + } + } else { + statusTextView.setVisibility(View.VISIBLE); + statusTextView.setText(getString(R.string.status_terrain_anchor, state)); + } + }); + } + + /** Create a rooftop anchor at a specific geodetic location using a EUS quaternion. */ + private void createRooftopAnchor( + Earth earth, double latitude, double longitude, float[] quaternion) { + final ResolveAnchorOnRooftopFuture future = + earth.resolveAnchorOnRooftopAsync( + latitude, + longitude, + /* altitudeAboveRooftop= */ 0.0f, + quaternion[0], + quaternion[1], + quaternion[2], + quaternion[3], + (anchor, state) -> { + if (state == RooftopAnchorState.SUCCESS) { + synchronized (anchorsLock) { + anchors.add(anchor); + rooftopAnchors.add(anchor); + } + } else { + statusTextView.setVisibility(View.VISIBLE); + statusTextView.setText(getString(R.string.status_rooftop_anchor, state)); + } }); - } - } catch (ResourceExhaustedException e) { - messageSnackbarHelper.showMessageWithDismiss( - this, getResources().getString(R.string.terrain_anchor_resource_exhausted)); - Log.d(TAG, "Exception creating terrain anchor", e); - } - deadlineForMessageMillis = - SystemClock.uptimeMillis() + DURATION_FOR_NO_TERRAIN_ANCHOR_RESULT_MS; - if (anchor != null) { - pendingTerrainAnchors.put(anchor, new TerrainAnchorResolveListener()); - } } /** @@ -1021,10 +1203,21 @@ private void storeAnchorParameters( HashSet newAnchorParameterSet = new HashSet<>(anchorParameterSet); SharedPreferences.Editor editor = sharedPreferences.edit(); - String terrain = isTerrainAnchorMode ? "Terrain" : ""; + String type = ""; + switch (anchorType) { + case TERRAIN: + type = "Terrain"; + break; + case ROOFTOP: + type = "Rooftop"; + break; + default: + type = ""; + break; + } newAnchorParameterSet.add( String.format( - terrain + "%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f", + type + "%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f", latitude, longitude, altitude, @@ -1051,9 +1244,13 @@ private void createAnchorFromSharedPreferences(Earth earth) { } for (String anchorParameters : anchorParameterSet) { - boolean isTerrain = anchorParameters.contains("Terrain"); - if (isTerrain) { + AnchorType type = AnchorType.GEOSPATIAL; + if (anchorParameters.contains("Terrain")) { + type = AnchorType.TERRAIN; anchorParameters = anchorParameters.replace("Terrain", ""); + } else if (anchorParameters.contains("Rooftop")) { + type = AnchorType.ROOFTOP; + anchorParameters = anchorParameters.replace("Rooftop", ""); } String[] parameters = anchorParameters.split(","); if (parameters.length != 7) { @@ -1071,10 +1268,16 @@ private void createAnchorFromSharedPreferences(Earth earth) { Float.parseFloat(parameters[5]), Float.parseFloat(parameters[6]) }; - if (isTerrain) { - createTerrainAnchor(earth, latitude, longitude, quaternion); - } else { - createAnchor(earth, latitude, longitude, altitude, quaternion); + switch (type) { + case TERRAIN: + createTerrainAnchor(earth, latitude, longitude, quaternion); + break; + case ROOFTOP: + createRooftopAnchor(earth, latitude, longitude, quaternion); + break; + default: + createAnchor(earth, latitude, longitude, altitude, quaternion); + break; } } @@ -1094,11 +1297,11 @@ public void onDialogContinueClick(DialogFragment dialog) { dialog.dismiss(); } - private void onTerrainAnchorModeChanged(CompoundButton button, boolean isChecked) { + private void onRenderStreetscapeGeometryChanged(CompoundButton button, boolean isChecked) { if (session == null) { return; } - isTerrainAnchorMode = isChecked; + isRenderStreetscapeGeometry = isChecked; } /** @@ -1113,11 +1316,13 @@ private void handleTap(Frame frame, TrackingState cameraTrackingState) { // Handle taps. Handling only one tap per frame, as taps are usually low frequency // compared to frame rate. synchronized (singleTapLock) { - if (queuedSingleTap == null - || anchors.size() >= MAXIMUM_ANCHORS - || cameraTrackingState != TrackingState.TRACKING) { - queuedSingleTap = null; - return; + synchronized (anchorsLock) { + if (queuedSingleTap == null + || anchors.size() >= MAXIMUM_ANCHORS + || cameraTrackingState != TrackingState.TRACKING) { + queuedSingleTap = null; + return; + } } Earth earth = session.getEarth(); if (earth == null || earth.getTrackingState() != TrackingState.TRACKING) { @@ -1138,8 +1343,13 @@ private void handleTap(Frame frame, TrackingState cameraTrackingState) { } /** Returns {@code true} if and only if the hit can be used to create an Anchor reliably. */ - private static boolean shouldCreateAnchorWithHit(HitResult hit) { + private boolean shouldCreateAnchorWithHit(HitResult hit) { Trackable trackable = hit.getTrackable(); + if (isRenderStreetscapeGeometry) { + if (trackable instanceof StreetscapeGeometry) { + return true; + } + } if (trackable instanceof Plane) { // Check if the hit was within the plane's polygon. return ((Plane) trackable).isPoseInPolygon(hit.getHitPose()); @@ -1150,42 +1360,4 @@ private static boolean shouldCreateAnchorWithHit(HitResult hit) { return false; } - /** Listener for the results of a resolving terrain anchor operation. */ - private final class TerrainAnchorResolveListener { - public void onTaskComplete(Anchor anchor) { - TerrainAnchorState state = anchor.getTerrainAnchorState(); - runOnUiThread( - () -> { - statusTextView.setVisibility(View.VISIBLE); - statusTextView.setText(getString(R.string.status_terrain_anchor, state)); - }); - } - - public void onDeadlineExceeded() { - runOnUiThread( - () -> { - statusTextView.setVisibility(View.VISIBLE); - statusTextView.setText(getResources().getString(R.string.terrain_anchor_no_result_yet)); - }); - deadlineForMessageMillis = 0; - } - } - - // Wrapper for checkVpsAvailability. Do not block on this future on the Main thread; deadlock will - // result. - private ListenableFuture checkVpsAvailabilityFuture( - double latitude, double longitude) { - return CallbackToFutureAdapter.getFuture( - completer -> { - final VpsAvailabilityFuture future = - session.checkVpsAvailabilityAsync( - latitude, longitude, availability -> completer.set(availability)); - completer.addCancellationListener( - () -> { - boolean cancel = future.cancel(); - }, - Runnable::run); - return "checkVpsAvailabilityFuture"; - }); - } } diff --git a/samples/geospatial_java/app/src/main/res/drawable/ic_settings_white.png b/samples/geospatial_java/app/src/main/res/drawable/ic_settings_white.png new file mode 100644 index 000000000..8909c3553 Binary files /dev/null and b/samples/geospatial_java/app/src/main/res/drawable/ic_settings_white.png differ diff --git a/samples/geospatial_java/app/src/main/res/layout/activity_main.xml b/samples/geospatial_java/app/src/main/res/layout/activity_main.xml index 4b1174709..63ee1ad94 100644 --- a/samples/geospatial_java/app/src/main/res/layout/activity_main.xml +++ b/samples/geospatial_java/app/src/main/res/layout/activity_main.xml @@ -55,24 +55,27 @@ android:text="@string/tap_screen_text" android:textColor="#ffffff"/> - + android:visibility="invisible"/> -