[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS8.1]\n - Browser [e.g. stock browser, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n.idea\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at prabhat.rai1707@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [2018] [Prabhat Rai]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README-zh_CN.md",
    "content": "# Android - EasyWayLocation\n该库包含与谷歌位置相关的所有实用程序。例如，获取经纬度、地址和位置设置对话框、绘制路线等\n\n[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-EasyWayLocation-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/6880)\n\n## 有什么新功能 Ver 2.4\n\n- 弧线绘制\n\n    a. 简单的\n    \n    b. 动画.\n\n- 在起点和终点之间绘制弧线路线\n\n- 现在，Dev 可以动态更改参数，例如起点、航点等\n\n- 获取arrayList和HashMap中的折线详细信息类\n\n- 使用 TAG 为弧形和航路点折线清除折线\n\n- 修复重大崩溃\n\n- 在示例文件夹中创建了一个曲目演示以供更多使用帮助\n\n# 演示图像和 Gif:\n\n![IMages1](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2F1.png?alt=media&token=0f7b6430-7dac-453e-879f-f0523792fb31)\n![alt Setting IMages2](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2F2.png?alt=media&token=a0aa40d3-2f84-4886-9579-79fdd694290d)\n![alt Setting IMages3](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2F3.png?alt=media&token=412a7e86-0363-4e97-bf01-e130865d015f)\n\n![gif1](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2Faniated_forgithub.gif?alt=media&token=d17c187f-8192-4d2f-a44e-26020acfd3eb)\n![gif2](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2Fgif_for_github.gif?alt=media&token=060e72c1-a3fd-4090-8589-7e85ed598b0e)\n\n\n# 先决条件\n- Android 16\n# 安装\n## Step 1:- 将其添加到存储库末尾的根 build.gradle 中：\n````\nall projects {\n        repositories {\n            ...\n            maven { url 'https://jitpack.io' }\n        }\n    }\n  \n````\n## Step 2:- 添加 dependency:\n````\n        dependencies {\n            implementation 'com.github.prabhat1707:EasyWayLocation:2.4'\n        }\n    \n````\n\n### 库使用 java 8 字节码，所以不要忘记在应用程序的 build.gradle 文件中启用 java 8。\n\n````\nandroid {\n    compileOptions {\n        sourceCompatibility 1.8\n        targetCompatibility 1.8\n    }\n}\n\n````\n\n# Usage\n\n###### 如果设备运行 Android 6.0 或更高版本，并且您的应用的目标 SDK 为 29 或更高版本，则首先检查位置的权限，然后调用它。\n\n## 添加所需的权限\n为了优越的位置 (GPS location), 在您的添加以下权限 AndroidManifest.xml:\n````\n<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n\n````\n\nFor coarse location (network location), add the following permission in your AndroidManifest.xml:\n````\n<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n\n````\n\n# 从设备中检索位置\n````\npublic class MainActivity extends AppCompatActivity implements Listener {\n    EasyWayLocation easyWayLocation;\n    private TextView location, latLong, diff;\n    private Double lati, longi;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        //--\n        easyWayLocation = new EasyWayLocation(this, false,false,this);\n    }\n\n    @Override\n    public void locationOn() {\n        Toast.makeText(this, \"Location ON\", Toast.LENGTH_SHORT).show();    \n    }\n\n   @Override\n    public void currentLocation(Location location) {\n        StringBuilder data = new StringBuilder();\n        data.append(location.getLatitude());\n        data.append(\" , \");\n        data.append(location.getLongitude());\n        latLong.setText(data);\n        getLocationDetail.getAddress(location.getLatitude(), location.getLongitude(), \"xyz\");\n    }\n    \n    @Override\n    public void locationCancelled() {\n         Toast.makeText(this, \"Location Cancelled\", Toast.LENGTH_SHORT).show();\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        switch (requestCode) {\n            case LOCATION_SETTING_REQUEST_CODE:\n                easyWayLocation.onActivityResult(resultCode);\n                break;\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        easyWayLocation.startLocation();\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        easyWayLocation.endUpdates();\n\n    }\n}\n\n````\n\n# 位置通知器\n\n````\n@Override\n    public void locationOn() {\n        Toast.makeText(this, \"Location ON\", Toast.LENGTH_SHORT).show();\n        \n    }\n\n    @Override\n    public void  currentLocation(Location location){\n       // give lat and long at every interval \n    }\n\n    @Override\n    public void locationCancelled() {\n        // location not on\n    }\n    \n````\n# 构造函数选项\n\n## 要记住的要点\n- 如果您只想要最后一个位置，则将其传递为 true，如果为 false，则根据默认位置请求为您提供位置更新。\n- 如果您不通过，则它需要默认位置请求，或者您也可以通过您的位置请求（参见构造函数 2nd）。\n\n````\nContext context = this;\nboolean requireFineGranularity = false;\nnew EasyWayLocation(this, requireLastLocation = false,isDebuggable = true/false,listner = this);\n\nor\n\nrequest = new LocationRequest();\nrequest.setInterval(10000);\nrequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);\n\nnew EasyWayLocation(this,locationRequest = request ,  requireLastLocation = false,isDebuggable = true/false,listner = this);\n\n\n````\n\n## 计算两点之间的距离\n\n````\n\ndouble startLatitude = 59.95;\ndouble startLongitude = 30.3;\ndouble endLatitude = 44.84;\ndouble endLongitude = -0.58;\nlocation.calculateDistance(startLatitude, startLongitude, endLatitude, endLongitude);\n\n// or\n\nPoint startPoint = new EasyWayLocation.Point(59.95, 30.3);\nPoint endPoint = new EasyWayLocation.Point(44.84, -0.58);\nlocation.calculateDistance(startPoint, endPoint);\n\n````\n\n## 更新获取位置的地址详细信息。\n- if you want an address from the current location then you need to pass key and context.\n- why I want key here if android already provides Geocoder because in some cases or some devices geocoder not work well and throws Exception, so in that case, I use google geocode API for fetch address.\n- For this, you need to implement Callback, LocationData.AddressCallBack\n\n````\nGetLocationDetail getLocationDetail = new GetLocationDetail(callback = this, context = this);\n\ngetLocationDetail.getAddress(location.getLatitude(), location.getLongitude(), key = \"xyz\");\n\n````\n\n## 谷歌地图路线\n\n#### 如果您想在您的应用程序中添加地图路线功能，您可以通过添加 DirectionUtil 类将其与此库一起使用，以使您更轻松地工作。这是 lib 将帮助您绘制两点 LatLng 与航点之间的路线图。\n\n## 当您的 GoogleMap 准备就绪时\n\n#### 确保在谷歌开发者控制台中启用谷歌地图和谷歌地图方向。\n\n#### 首先初始化Direction Util\n\n````\nwayPoints.add(LatLng(37.423669, -122.090168))\n        wayPoints.add(LatLng(37.420930, -122.085362))\n                val directionUtil = DirectionUtil.Builder()\n                .setDirectionKey(\"xyz\")\n                        .setOrigin(LatLng(37.421481, -122.092156))\n                        .setWayPoints(wayPoints)\n                        .setGoogleMap(mMap)\n                        .setPolyLinePrimaryColor(R.color.black)\n                        .setPolyLineWidth(5)\n                        .setPathAnimation(true)\n                        .setCallback(this)\n                        .setPolylineTag(WAY_POINT_TAG)\n                        .setDestination(LatLng(37.421519, -122.086809))\n                        .build()\n\n````\n\n#### 为路线绘制添加以下行\n\n#### 先调用init再调用drawRoute\n\n````\ndirectionUtil.initPath()\ndirectionUtil.drawPath(WAY_POINT_TAG)\n\n````\n\n#### 现在从 v2.4 开始，您可以在路径之间更改原点、颜色等\n\n````\n directionUtil.serOrigin(LatLng(driverCurrentLocation.latitude,driverCurrentLocation.longitude),wayPoints)\n\n````\n\n#### 为圆弧绘制添加下面的行\n\n````\ndirectionUtil.drawArcDirection(LatLng(37.421481, -122.092156),LatLng(37.421519, -122.086809),0.5,ARC_POINT_TAG)\n\n````\n\n#### 添加下面的行以根据相应的TAG删除折线\n\n````\ndirectionUtil.clearPolyline(WAY_POINT_TAG)\n\n````\n\n# 其中有两种情况：\n\n- 像优步这样的动画\n- 没有动画。\n\n1.带动画\n\n    - setPathAnimation = true\n\n![gif1](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2Fanimation_route.gif?alt=media&token=97af3e8c-e302-41af-b93b-e8b85b47d9e7)\n\n2.没有动画\n\n    - setPathAnimation = false\n    - change its color by, setPolyLinePrimaryColor() property\n    \n![gif2](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2Fnormal_routw.gif?alt=media&token=76e35316-2e76-4d4d-9099-98f3f0678b34)\n\n## 回调\n\n#### 当路由绘制路径完成时，调用下面的回调\n````\n\noverride fun pathFindFinish(polyLineDetails: HashMap<String, PolyLineDataBean>) {\n       for (i in polyLineDetails.keys){\n           Log.v(\"sample\",polyLineDetails[i]?.time)\n       }\n    }\n    \n````\n\nhere, polyLineDetails contain each polyline or route detail as time, distance and road summary.\n\n#### 您还可以更改路线动画的不同属性，如延迟、原色、次要颜色等，只需探索它即可。\n\n#### 错误，功能请求\n\n发现错误？缺少什么？反馈是改进项目的重要组成部分，所以，请\n<a href=\"https://github.com/prabhat1707/EasyWayLocation/issues\">open an issue</a>\n\n# 执照\n\n````\n版权所有 (c) <prabhat.rai1707@gmail.com>\n\n根据 Apache 许可证 2.0 版（“许可证”）获得许可；\n除非遵守许可，否则您不得使用此文件。\n您可以在以下网址获取许可证的副本\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\n除非适用法律要求\nw 或书面同意，软件\n根据许可分发是在“原样”基础上分发的，\n没有任何明示或暗示的保证或条件。\n请参阅许可以了解特定语言的管理权限和\n许可证下的限制。\n````\n"
  },
  {
    "path": "README.md",
    "content": "---\n\n<details><summary><b> See 1 Available Translations 🇨🇳</b></summary>\n<p>\n\n- [🇨🇳 简体中文](./README-zh_CN.md)\n\n</p>\n</details>\n\n---\n\n# Android - EasyWayLocation\nThis library contains all utils related to google location. like, getting lat or long, Address and Location Setting dialog, Draw Route, etc\n\n[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-EasyWayLocation-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/6880)\n\n## What's New in Ver 2.4\n\n- Arc Route Draw\n\n    a. simple.\n    \n    b. animation.\n\n- Draw Arc route between origin and destination.\n\n- Now , Dev can change parameter dynamically like origin, waypoints, etc\n\n- Get polyline details class in arrayList and HashMap.\n\n- Clear Polyline by using TAG for both Arc and waypoints polylines.\n\n- Fix Major Crash\n\n- Created one track demo in sample folder for more usage Help\n\n# Demo Images and Gif:\n![IMages1](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2F1.png?alt=media&token=0f7b6430-7dac-453e-879f-f0523792fb31)\n![alt Setting IMages2](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2F2.png?alt=media&token=a0aa40d3-2f84-4886-9579-79fdd694290d)\n![alt Setting IMages3](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2F3.png?alt=media&token=412a7e86-0363-4e97-bf01-e130865d015f)\n\n![gif1](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2Faniated_forgithub.gif?alt=media&token=d17c187f-8192-4d2f-a44e-26020acfd3eb)\n![gif2](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2Fgif_for_github.gif?alt=media&token=060e72c1-a3fd-4090-8589-7e85ed598b0e)\n\n\n# Prerequisites\n- Android 16\n# Installing\n## Step 1:- Add it in your root build.gradle at the end of repositories:\n````\nall projects {\n        repositories {\n            ...\n            maven { url 'https://jitpack.io' }\n        }\n    }\n  \n````\n## Step 2:- Add the dependency:\n````\n        dependencies {\n            implementation 'com.github.prabhat1707:EasyWayLocation:2.4'\n        }\n    \n````\n\n### Library uses java 8 bytecode, so dont forget to enable java 8 in your application's build.gradle file.\n\n````\nandroid {\n    compileOptions {\n        sourceCompatibility 1.8\n        targetCompatibility 1.8\n    }\n}\n\n````\n\n# Usage\n\n###### If the device is running Android 6.0 or higher, and your app's target SDK is 29 or higher then first check the permission of location then call it.\n\n## Add the required permissions\nFor fine location (GPS location), add the following permission in your AndroidManifest.xml:\n````\n<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n\n````\n\nFor coarse location (network location), add the following permission in your AndroidManifest.xml:\n````\n<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n\n````\n\n# Retrieve the location from the device\n````\npublic class MainActivity extends AppCompatActivity implements Listener {\n    EasyWayLocation easyWayLocation;\n    private TextView location, latLong, diff;\n    private Double lati, longi;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        //--\n        easyWayLocation = new EasyWayLocation(this, false,false,this);\n    }\n\n    @Override\n    public void locationOn() {\n        Toast.makeText(this, \"Location ON\", Toast.LENGTH_SHORT).show();    \n    }\n\n   @Override\n    public void currentLocation(Location location) {\n        StringBuilder data = new StringBuilder();\n        data.append(location.getLatitude());\n        data.append(\" , \");\n        data.append(location.getLongitude());\n        latLong.setText(data);\n        getLocationDetail.getAddress(location.getLatitude(), location.getLongitude(), \"xyz\");\n    }\n    \n    @Override\n    public void locationCancelled() {\n         Toast.makeText(this, \"Location Cancelled\", Toast.LENGTH_SHORT).show();\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        switch (requestCode) {\n            case LOCATION_SETTING_REQUEST_CODE:\n                easyWayLocation.onActivityResult(resultCode);\n                break;\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        easyWayLocation.startLocation();\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        easyWayLocation.endUpdates();\n\n    }\n}\n\n````\n\n# Location Notifier\n\n````\n@Override\n    public void locationOn() {\n        Toast.makeText(this, \"Location ON\", Toast.LENGTH_SHORT).show();\n        \n    }\n\n    @Override\n    public void  currentLocation(Location location){\n       // give lat and long at every interval \n    }\n\n    @Override\n    public void locationCancelled() {\n        // location not on\n    }\n    \n````\n# Constructor options\n\n## Points to Remember\n- if you want only last location then pass it true and if false then it gives you location update as per default location request.\n- if you don't pass then it takes default location request or you can pass your's one also(see constructor 2nd).\n\n````\nContext context = this;\nboolean requireFineGranularity = false;\nnew EasyWayLocation(this, requireLastLocation = false,isDebuggable = true/false,listner = this);\n\nor\n\nrequest = new LocationRequest();\nrequest.setInterval(10000);\nrequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);\n\nnew EasyWayLocation(this,locationRequest = request ,  requireLastLocation = false,isDebuggable = true/false,listner = this);\n\n\n````\n\n## Calculate distance between two points\n\n````\n\ndouble startLatitude = 59.95;\ndouble startLongitude = 30.3;\ndouble endLatitude = 44.84;\ndouble endLongitude = -0.58;\nlocation.calculateDistance(startLatitude, startLongitude, endLatitude, endLongitude);\n\n// or\n\nPoint startPoint = new EasyWayLocation.Point(59.95, 30.3);\nPoint endPoint = new EasyWayLocation.Point(44.84, -0.58);\nlocation.calculateDistance(startPoint, endPoint);\n\n````\n\n## Update Get Address Details of location.\n- if you want an address from the current location then you need to pass key and context.\n- why I want key here if android already provides Geocoder because in some cases or some devices geocoder not work well and throws Exception, so in that case, I use google geocode API for fetch address.\n- For this, you need to implement Callback, LocationData.AddressCallBack\n\n````\nGetLocationDetail getLocationDetail = new GetLocationDetail(callback = this, context = this);\n\ngetLocationDetail.getAddress(location.getLatitude(), location.getLongitude(), key = \"xyz\");\n\n````\n\n## Google Map Route\n\n#### If you want to add map route feature in your apps you can use this along with this lib by adding DirectionUtil Class to make you work more easier. This is lib will help you to draw route maps between two-point LatLng along it's with waypoints.\n\n## When Your GoogleMap Ready\n\n#### Make sure you enable google map and google map direction in the google developer console.\n\n#### First Initialize Direction Util\n\n````\nwayPoints.add(LatLng(37.423669, -122.090168))\n        wayPoints.add(LatLng(37.420930, -122.085362))\n                val directionUtil = DirectionUtil.Builder()\n                .setDirectionKey(\"xyz\")\n                        .setOrigin(LatLng(37.421481, -122.092156))\n                        .setWayPoints(wayPoints)\n                        .setGoogleMap(mMap)\n                        .setPolyLinePrimaryColor(R.color.black)\n                        .setPolyLineWidth(5)\n                        .setPathAnimation(true)\n                        .setCallback(this)\n                        .setPolylineTag(WAY_POINT_TAG)\n                        .setDestination(LatLng(37.421519, -122.086809))\n                        .build()\n\n````\n\n#### Add below line for route draw\n\n#### First call init and then drawRoute\n\n````\ndirectionUtil.initPath()\ndirectionUtil.drawPath(WAY_POINT_TAG)\n\n````\n\n#### Now from v2.4 you can change origin, color etc in between path\n\n````\n directionUtil.serOrigin(LatLng(driverCurrentLocation.latitude,driverCurrentLocation.longitude),wayPoints)\n\n````\n\n#### Add below line for Arc draw\n\n````\ndirectionUtil.drawArcDirection(LatLng(37.421481, -122.092156),LatLng(37.421519, -122.086809),0.5,ARC_POINT_TAG)\n\n````\n\n#### Add below line to remove polyline according to corresponding TAG\n\n````\ndirectionUtil.clearPolyline(WAY_POINT_TAG)\n\n````\n\n# There are two cases in it:\n\n- With Animation like Uber\n- without Animation.\n\n1. With Animation\n\n    - setPathAnimation = true\n\n![gif1](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2Fanimation_route.gif?alt=media&token=97af3e8c-e302-41af-b93b-e8b85b47d9e7)\n\n2. Without Animation\n\n    - setPathAnimation = false\n    - change its color by, setPolyLinePrimaryColor() property\n    \n![gif2](https://firebasestorage.googleapis.com/v0/b/chatapp-2e1df.appspot.com/o/location%20images%2Fnormal_routw.gif?alt=media&token=76e35316-2e76-4d4d-9099-98f3f0678b34)\n\n## Callbacks\n\n#### When route draw path has done then it below callback is called\n\n````\n\noverride fun pathFindFinish(polyLineDetails: HashMap<String, PolyLineDataBean>) {\n       for (i in polyLineDetails.keys){\n           Log.v(\"sample\",polyLineDetails[i]?.time)\n       }\n    }\n    \n````\n\nhere, polyLineDetails contain each polyline or route detail as time, distance and road summary.\n\n#### You can also change the route animation different properties like delay, primary color, a secondary color, etc, just explore it.\n\n#### Bugs, Feature requests\n\nFound a bug? Something that's missing? Feedback is an important part of improving the project, so, please\n<a href=\"https://github.com/prabhat1707/EasyWayLocation/issues\">open an issue</a>\n\n# License\n\n````\nCopyright (c) delight.im <prabhat.rai1707@gmail.com>\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable la\nw or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n````\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 29\n    defaultConfig {\n        applicationId \"com.example.prabhat.locationsample\"\n        minSdkVersion 17\n        targetSdkVersion 29\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility = '1.8'\n        targetCompatibility = '1.8'\n    }\n    buildToolsVersion = '28.0.3'\n}\n\ndependencies {\n    implementation fileTree(include: ['*.jar'], dir: 'libs')\n    implementation 'androidx.appcompat:appcompat:1.0.2'\n    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'\n    implementation project(':easywaylocation')\n    implementation 'com.google.android.gms:play-services-maps:17.0.0'\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n    implementation 'com.google.maps.android:android-maps-utils:0.6.2'\n    implementation 'androidx.cardview:cardview:1.0.0'\n\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app/src/debug/res/values/google_maps_api.xml",
    "content": "<resources>\n    <!--\n    TODO: Before you run your application, you need a Google Maps API key.\n\n    To get one, follow this link, follow the directions and press \"Create\" at the end:\n\n    https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend&keyType=CLIENT_SIDE_ANDROID&r=11:3D:A4:B3:98:07:A3:4C:03:51:DB:8A:F8:5E:C0:0F:5B:FF:61:82%3Bcom.example.prabhat.locationsample\n\n    You can also add your credentials to an existing key, using these values:\n\n    Package name:\n    11:3D:A4:B3:98:07:A3:4C:03:51:DB:8A:F8:5E:C0:0F:5B:FF:61:82\n\n    SHA-1 certificate fingerprint:\n    11:3D:A4:B3:98:07:A3:4C:03:51:DB:8A:F8:5E:C0:0F:5B:FF:61:82\n\n    Alternatively, follow the directions here:\n    https://developers.google.com/maps/documentation/android/start#get-key\n\n    Once you have your key (it starts with \"AIza\"), replace the \"google_maps_key\"\n    string in this file.\n    -->\n    <string name=\"google_maps_key\" templateMergeStrategy=\"preserve\" translatable=\"false\">xyz</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.prabhat.locationsample\">\n\n    <!--\n         The ACCESS_COARSE/FINE_LOCATION permissions are not required to use\n         Google Maps Android API v2, but you must specify either coarse or fine\n         location permissions for the 'MyLocation' functionality.\n    -->\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n\n        <!--\n             The API key for Google Maps-based APIs is defined as a string resource.\n             (See the file \"res/values/google_maps_api.xml\").\n             Note that the API key is linked to the encryption key used to sign the APK.\n             You need a different API key for each encryption key, including the release key that is used to\n             sign the APK for publishing.\n             You can define the keys for the debug and release targets in src/debug/ and src/release/.\n        -->\n        <activity\n            android:name=\".MainActivity\"\n            android:label=\"@string/title_activity_maps\"></activity>\n\n        <activity android:name=\".MapsActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <meta-data\n            android:name=\"com.google.android.geo.API_KEY\"\n            android:value=\"@string/google_maps_key\" />\n    </application>\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/com/example/prabhat/locationsample/CustomInfoWindowForGoogleMap.kt",
    "content": "package com.example.prabhat.locationsample\n\nimport android.app.Activity\nimport android.content.Context\nimport android.view.View\nimport android.widget.TextView\nimport com.google.android.gms.maps.GoogleMap\nimport com.google.android.gms.maps.model.Marker\nimport org.json.JSONObject\nimport java.lang.Exception\nimport java.text.DecimalFormat\n\nclass CustomInfoWindowForGoogleMap(context: Context): GoogleMap.InfoWindowAdapter  {\n    private val df: DecimalFormat = DecimalFormat(\"0.00\")\n\n    var mWindow = (context as Activity).layoutInflater.inflate(R.layout.marker_window, null)\n\n\n    override fun getInfoWindow(p0: Marker?): View {\n         render(p0, mWindow)\n        return mWindow\n    }\n\n    override fun getInfoContents(p0: Marker?): View {\n         render(p0, mWindow)\n        return mWindow\n    }\n\n    private fun render(marker: Marker?, mWindow: View) {\n\n        val title = mWindow.findViewById<TextView>(R.id.textView)\n        val time = mWindow.findViewById<TextView>(R.id.textView2)\n        val distance = mWindow.findViewById<TextView>(R.id.textView3)\n        try {\n            val json = JSONObject(marker?.title)\n            title.text = json.getString(\"placeSummary\")\n            if (json.getString(\"time\").isNotEmpty()){\n                time.visibility = View.VISIBLE\n                distance.visibility = View.VISIBLE\n                time.text = df.format(json.getString(\"timeFromPrevPoint\").toDouble()/60) + \" sec\"\n                distance.text = df.format(json.getString(\"distanceFromPrevPoint\").toDouble()/1609.344)+\" mile\"\n            }else{\n                time.visibility = View.GONE\n                distance.visibility = View.GONE\n            }\n        }catch (e:Exception){\n            e.printStackTrace()\n        }\n\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/example/prabhat/locationsample/MainActivity.java",
    "content": "package com.example.prabhat.locationsample;\n\nimport android.Manifest;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.location.Location;\nimport android.os.Bundle;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.core.app.ActivityCompat;\n\nimport com.example.easywaylocation.EasyWayLocation;\nimport com.example.easywaylocation.GetLocationDetail;\nimport com.example.easywaylocation.Listener;\nimport com.example.easywaylocation.LocationData;\n\nimport static com.example.easywaylocation.EasyWayLocation.LOCATION_SETTING_REQUEST_CODE;\n\npublic class MainActivity extends AppCompatActivity implements Listener, LocationData.AddressCallBack {\n    //EasyWayLocation easyWayLocation;\n    private TextView location, latLong, diff;\n    private Double lati, longi;\n    //private TestLocationRequest testLocationRequest;\n    private EasyWayLocation easyWayLocation;\n    GetLocationDetail getLocationDetail;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        location = findViewById(R.id.location);\n        latLong = findViewById(R.id.latlong);\n        diff = findViewById(R.id.diff);\n        getLocationDetail = new GetLocationDetail(this, this);\n        easyWayLocation = new EasyWayLocation(this, false,true,this);\n        if (permissionIsGranted()) {\n            doLocationWork();\n        } else {\n            // Permission not granted, ask for it\n            //testLocationRequest.requestPermission(121);\n        }\n    }\n\n    public boolean permissionIsGranted() {\n\n        int permissionState = ActivityCompat.checkSelfPermission(this,\n                Manifest.permission.ACCESS_FINE_LOCATION);\n\n        return permissionState == PackageManager.PERMISSION_GRANTED;\n    }\n\n    private void doLocationWork() {\n        easyWayLocation.startLocation();\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (requestCode == LOCATION_SETTING_REQUEST_CODE) {\n            easyWayLocation.onActivityResult(resultCode);\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        easyWayLocation.startLocation();\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        easyWayLocation.endUpdates();\n\n    }\n\n    @Override\n    public void locationOn() {\n        Toast.makeText(this, \"Location On\", Toast.LENGTH_SHORT).show();\n    }\n\n    @Override\n    public void currentLocation(Location location) {\n        StringBuilder data = new StringBuilder();\n        data.append(location.getLatitude());\n        data.append(\" , \");\n        data.append(location.getLongitude());\n        latLong.setText(data);\n        getLocationDetail.getAddress(location.getLatitude(), location.getLongitude(), \"xyz\");\n    }\n\n    @Override\n    public void locationCancelled() {\n        Toast.makeText(this, \"Location Cancelled\", Toast.LENGTH_SHORT).show();\n    }\n\n    @Override\n    public void locationData(LocationData locationData) {\n        location.setText(locationData.getFull_address());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/prabhat/locationsample/MapsActivity.kt",
    "content": "package com.example.prabhat.locationsample\n\nimport android.Manifest\nimport android.animation.ValueAnimator\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.graphics.Bitmap\nimport android.graphics.drawable.BitmapDrawable\nimport android.location.Location\nimport android.os.Bundle\nimport android.os.Handler\nimport android.os.SystemClock\nimport android.util.Log\nimport android.view.View\nimport android.view.animation.Interpolator\nimport android.view.animation.LinearInterpolator\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.app.ActivityCompat\nimport com.example.easywaylocation.EasyWayLocation\nimport com.example.easywaylocation.Listener\nimport com.example.easywaylocation.draw_path.DirectionUtil\nimport com.example.easywaylocation.draw_path.PolyLineDataBean\nimport com.google.android.gms.maps.CameraUpdateFactory\nimport com.google.android.gms.maps.GoogleMap\nimport com.google.android.gms.maps.OnMapReadyCallback\nimport com.google.android.gms.maps.SupportMapFragment\nimport com.google.android.gms.maps.model.BitmapDescriptorFactory\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.Marker\nimport com.google.android.gms.maps.model.MarkerOptions\nimport com.google.maps.android.SphericalUtil\nimport kotlinx.android.synthetic.main.activity_maps.*\n\n\nclass MapsActivity : AppCompatActivity(), OnMapReadyCallback, DirectionUtil.DirectionCallBack,\n    Listener {\n\n    private var isMarkerRotating: Boolean = false\n    lateinit var polyLineDetails:HashMap<String, PolyLineDataBean>\n    lateinit var directionUtil: DirectionUtil\n    lateinit var easyWayLocation: EasyWayLocation\n    var movingCabMarker: Marker? = null\n    lateinit var driverCurrentLocation: Location\n    var markerList = ArrayList<Marker>()\n    companion object{\n        val WAY_POINT_TAG = \"way_point_tag\"\n        val ARC_POINT_TAG = \"arc_point_tag\"\n        val waypoint1 = LatLng(37.423669, -122.090168)\n        val waypoint2 = LatLng(37.420930, -122.085362)\n        val origin = LatLng(37.421481, -122.092156)\n        val destination = LatLng(37.421519, -122.086809)\n\n        val markerOptionsOrigin = MarkerOptions()\n        val markerOptionsDestination = MarkerOptions()\n\n    }\n\n    override fun pathFindFinish(\n        polyLineDetailsMap: HashMap<String, PolyLineDataBean>,\n        polyLineDetailsArray: ArrayList<PolyLineDataBean>\n    ) {\n        this.polyLineDetails = polyLineDetailsMap\n       for (marker in markerList){\n           marker.remove()\n       }\n//        animateCamera(LatLng(driverCurrentLocation.latitude,driverCurrentLocation.longitude))\n        animateMarker(LatLng(driverCurrentLocation.latitude,driverCurrentLocation.longitude), movingCabMarker, driverCurrentLocation.bearing)\n        initAllMarker(polyLineDetailsArray)\n        directionUtil.drawPath(WAY_POINT_TAG)\n    }\n\n    private fun initAllMarker(polyLineDetails: ArrayList<PolyLineDataBean>) {\n        markerList.clear()\n//        markerOptionsOrigin.rotation(SphericalUtil.computeHeading(origin, waypoint1).toFloat())\n        for (data in polyLineDetails){\n            data.position?.let {\n                val markerOptionswayPoint = MarkerOptions()\n                markerOptionswayPoint.position(data.position!!)\n                markerOptionswayPoint.icon(BitmapDescriptorFactory.fromResource(R.drawable.map_pin));\n                markerOptionswayPoint.title(data.toJson().toString())\n                markerList.add(mMap.addMarker(markerOptionswayPoint))\n\n            }\n        }\n\n    }\n\n    private lateinit var mMap: GoogleMap\n    private var wayPoints:ArrayList<LatLng> = ArrayList()\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_maps)\n        // Obtain the SupportMapFragment and get notified when the map is ready to be used.\n        val mapFragment = supportFragmentManager\n                .findFragmentById(R.id.map) as SupportMapFragment\n        mapFragment.getMapAsync(this)\n    }\n\n    override fun onMapReady(googleMap: GoogleMap) {\n        mMap = googleMap\n        val markerInfoWindowAdapter = CustomInfoWindowForGoogleMap(this)\n        googleMap.setInfoWindowAdapter(markerInfoWindowAdapter)\n        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(37.423669, -122.090168), 16F))\n        wayPoints.add(waypoint1)\n        wayPoints.add(waypoint2)\n        directionUtil = DirectionUtil.Builder()\n            .setDirectionKey(\"xyz\")\n            .setOrigin(origin)\n            .setWayPoints(wayPoints)\n            .setGoogleMap(mMap)\n            .setPathAnimation(true)\n            .setPolyLineWidth(5)\n            .setCallback(this)\n            .setDestination(destination)\n            .build()\n\n        easyWayLocation = EasyWayLocation(this, false, true, this)\n        easyWayLocation.endUpdates()\n        val bean = PolyLineDataBean().also {\n            it.placeSummary = \"Origin\"\n        }\n        val bean2 = PolyLineDataBean().also {\n            it.placeSummary = \"destination\"\n        }\n        markerOptionsOrigin.position(origin)\n        markerOptionsOrigin.icon(BitmapDescriptorFactory.fromBitmap(getIcon(R.drawable.map_pin)));\n        markerOptionsOrigin.title(bean.toJson().toString())\n\n        val data = directionUtil.getShortestPathDetails(origin, destination)\n\n        markerOptionsDestination.position(destination)\n        markerOptionsDestination.icon(BitmapDescriptorFactory.fromResource(R.drawable.map_pin));\n        markerOptionsDestination.title(data.toJson().toString())\n\n        directionUtil.drawArcDirection(origin, destination, 0.5, ARC_POINT_TAG)\n        markerList.add(mMap.addMarker(markerOptionsOrigin))\n        markerList.add(mMap.addMarker(markerOptionsDestination))\n\n        end_update.setOnClickListener {\n            easyWayLocation.endUpdates()\n        }\n\n        button2.setOnClickListener {\n            if (permissionIsGranted()) {\n                button2.visibility = View.GONE\n                end_update.visibility = View.VISIBLE\n                directionUtil.clearPolyline(ARC_POINT_TAG)\n                easyWayLocation.startLocation()\n            } else {\n                // Permission not granted, ask for it\n                //testLocationRequest.requestPermission(121);\n            }\n            button2.text = \"Complete Ride\"\n        }\n    }\n\n    fun permissionIsGranted(): Boolean {\n        val permissionState = ActivityCompat.checkSelfPermission(\n            this,\n            Manifest.permission.ACCESS_FINE_LOCATION\n        )\n        return permissionState == PackageManager.PERMISSION_GRANTED\n    }\n\n    fun getIcon(id:Int):Bitmap{\n        val height = 100\n        val width = 100\n        val bitmapdraw: BitmapDrawable = resources.getDrawable(id) as BitmapDrawable\n        val b: Bitmap = bitmapdraw.getBitmap()\n        return Bitmap.createScaledBitmap(b, width, height, false)\n    }\n\n    override fun locationOn() {\n\n    }\n\n    override fun currentLocation(location: Location?) {\n        try {\n            try {\n                directionUtil.clearPolyline(WAY_POINT_TAG)\n            }catch (e:java.lang.Exception){\n                e.printStackTrace()\n            }\n            location?.let {\n                driverCurrentLocation = it\n                checkPoint(driverCurrentLocation,wayPoints);\n                if (movingCabMarker == null){\n                    markerOptionsOrigin\n                        .icon(BitmapDescriptorFactory.fromBitmap(getIcon(R.drawable.car_icon)))\n                        .anchor(0.5f, 0.5f)\n                        .rotation(driverCurrentLocation.bearing)\n                        .flat(true)\n                        .title(\"Driver\")\n                    movingCabMarker = mMap.addMarker(markerOptionsOrigin)\n                }\n                directionUtil.serOrigin(\n                    LatLng(driverCurrentLocation.latitude,driverCurrentLocation.longitude),wayPoints)\n                directionUtil.initPath()\n            }\n        }catch (e:Exception){\n            e.printStackTrace()\n        }\n    }\n\n\n    fun animateCamera(location: LatLng) {\n        mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(location, mMap.cameraPosition.zoom))\n    }\n\n    private fun checkPoint(location: Location, wayPoints: ArrayList<LatLng>) {\n        val results = FloatArray(1)\n        for (points in wayPoints){\n            Location.distanceBetween(\n                location.latitude,\n                location.longitude,\n                points.latitude,\n                points.longitude,\n                results\n            )\n            val distanceInMeters = results[0]\n            if(distanceInMeters <= 50.0){\n                wayPoints.remove(points)\n            }\n            return\n        }\n    }\n\n    override fun locationCancelled() {\n\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        super.onActivityResult(requestCode, resultCode, data)\n        if (requestCode == EasyWayLocation.LOCATION_SETTING_REQUEST_CODE) {\n            easyWayLocation.onActivityResult(resultCode)\n        }\n    }\n\n    private fun rotateMarker(marker: Marker, toRotation: Float) {\n        if (!isMarkerRotating) {\n            val handler = Handler()\n            val start: Long = SystemClock.uptimeMillis()\n            val startRotation = marker.rotation\n            val duration: Long = 1000\n            val interpolator: Interpolator = LinearInterpolator()\n            handler.post(object : Runnable {\n                override fun run() {\n                    isMarkerRotating = true\n                    val elapsed: Long = SystemClock.uptimeMillis() - start\n                    val t: Float = interpolator.getInterpolation(elapsed.toFloat() / duration)\n                    val rot = t * toRotation + (1 - t) * startRotation\n                    marker.rotation = if (-rot > 180) rot / 2 else rot\n                    if (t < 1.0) {\n                        // Post again 16ms later.\n                        handler.postDelayed(this, 16)\n                    } else {\n                        isMarkerRotating = false\n                    }\n                }\n            })\n        }\n    }\n\n    private fun animateMarker(destination: LatLng, marker: Marker?, bearing: Float) {\n        if (marker != null) {\n            Log.d(\"check_in_device_9\", \"----------->\" + \"markerAnimate\" + destination.latitude.toString())\n\n            val startPosition = marker.position\n\n            val startRotation = marker.rotation\n\n            val latLngInterpolator = LatLngInterpolator.LinearFixed()\n            val valueAnimator = ValueAnimator.ofFloat(0F, 1F)\n            valueAnimator.duration = 1000 // duration 1 second\n            valueAnimator.interpolator = LinearInterpolator()\n            valueAnimator.addUpdateListener {\n                try {\n                    val v = it.animatedFraction\n                    val newPosition = latLngInterpolator.interpolate(v, startPosition, destination)\n                    marker.position = newPosition\n                    marker.setAnchor(0.5f, 0.5f)\n                    marker.rotation = computeRotation(v, startRotation, bearing)\n                    marker.isFlat = true\n                } catch (ex: Exception) {\n                    ex.printStackTrace()\n                    Log.d(\"check_in_device_9\", \"----------->\" + \"exsception\" + ex.message.toString())\n\n                }\n            }\n\n            valueAnimator.start()\n        }\n    }\n\n    fun computeRotation(fraction: Float, start: Float, end: Float): Float {\n        val normalizeEnd = end - start // rotate start to 0\n        val normalizedEndAbs = (normalizeEnd + 360) % 360\n        val direction: Float\n        if (normalizedEndAbs > 180) {\n            direction = -1F\n        } else {\n            direction = 1F\n        }\n//        val direction: Float = (normalizedEndAbs > 180) ?-1 : 1; // -1 = anticlockwise, 1 = clockwise\n        val rotation: Float\n        if (direction > 0) {\n            rotation = normalizedEndAbs\n        } else {\n            rotation = normalizedEndAbs - 360\n        }\n\n        val result = fraction * rotation + start\n        return (result + 360) % 360\n    }\n\n    interface LatLngInterpolator {\n        fun interpolate(fraction: Float, a: LatLng, b: LatLng): LatLng\n\n        class LinearFixed : LatLngInterpolator {\n            override fun interpolate(fraction: Float, a: LatLng, b: LatLng): LatLng {\n                val lat = (b.latitude - a.latitude) * fraction + a.latitude\n                var lngDelta = b.longitude - a.longitude\n                // Take the shortest path across the 180th meridian.\n                if (Math.abs(lngDelta) > 180) {\n                    lngDelta -= Math.signum(lngDelta) * 360\n                }\n                val lng = lngDelta * fraction + a.longitude\n                return LatLng(lat, lng)\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillColor=\"#26A69A\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\"com.example.prabhat.locationsample.MainActivity\">\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:autoSizeTextType=\"uniform\"\n        android:padding=\"5dp\"\n        android:text=\"Current Address\"\n        android:textAlignment=\"center\"\n        android:textAppearance=\"@style/TextAppearance.AppCompat.Large\" />\n\n    <TextView\n        android:id=\"@+id/location\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"5dp\"\n        android:textAlignment=\"center\"\n        android:textAppearance=\"@style/TextAppearance.AppCompat.Medium\"\n        android:textColor=\"@color/black\" />\n\n    <TextView\n        android:id=\"@+id/latlong\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:textAlignment=\"center\"\n        android:textColor=\"@color/black\" />\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:visibility=\"gone\"\n        android:autoSizeTextType=\"uniform\"\n        android:padding=\"5dp\"\n        android:text=\"Difference between two points in meter\"\n        android:textAlignment=\"center\"\n        android:textAppearance=\"@style/TextAppearance.AppCompat.Large\" />\n\n    <TextView\n        android:id=\"@+id/diff\"\n        android:visibility=\"gone\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"8dp\"\n        android:textAlignment=\"center\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_maps.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <fragment\n        android:id=\"@+id/map\"\n        android:name=\"com.google.android.gms.maps.SupportMapFragment\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"1.0\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintVertical_bias=\"0.0\"\n        tools:context=\".MapsActivity\" />\n\n    <Button\n        android:id=\"@+id/button2\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"48dp\"\n        android:text=\"Start Ride\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"@+id/guideline\" />\n\n    <Button\n        android:id=\"@+id/end_update\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"48dp\"\n        android:text=\"Stop Ride\"\n        android:visibility=\"gone\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"@+id/guideline\" />\n\n    <androidx.constraintlayout.widget.Guideline\n        android:id=\"@+id/guideline\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        app:layout_constraintGuide_percent=\".8\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/marker_window.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:background=\"#fff\"\n    android:padding=\"8dp\"\n    android:layout_height=\"wrap_content\">\n\n    <TextView\n        android:id=\"@+id/textView\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"8dp\"\n        android:text=\"TextView\"\n        android:textStyle=\"bold\"\n        android:textColor=\"@color/black\"\n        app:layout_constraintBottom_toTopOf=\"@+id/textView2\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <TextView\n        android:id=\"@+id/textView2\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"8dp\"\n        android:textColor=\"@color/black\"\n        android:text=\"TextView\"\n        app:layout_constraintBottom_toTopOf=\"@+id/textView3\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView\" />\n\n    <TextView\n        android:id=\"@+id/textView3\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginBottom=\"5dp\"\n        android:textColor=\"@color/black\"\n        android:text=\"TextView\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView2\" />\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"black\">#000000</color>\n    <color name=\"yellow\">#FFFF00</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">Location Sample</string>\n    <string name=\"loc_mess\">Please on location of your device. To get your current Address.</string>\n    <string name=\"loc_title\">Location Alert</string>\n    <string name=\"title_activity_maps\">Map</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/release/res/values/google_maps_api.xml",
    "content": "<resources>\n    <!--\n    TODO: Before you release your application, you need a Google Maps API key.\n\n    To do this, you can either add your release key credentials to your existing\n    key, or create a new key.\n\n    Note that this file specifies the API key for the release build target.\n    If you have previously set up a key for the debug target with the debug signing certificate,\n    you will also need to set up a key for your release certificate.\n\n    Follow the directions here:\n\n    https://developers.google.com/maps/documentation/android/signup\n\n    Once you have your key (it starts with \"AIza\"), replace the \"google_maps_key\"\n    string in this file.\n    -->\n    <string name=\"google_maps_key\" templateMergeStrategy=\"preserve\" translatable=\"false\">YOUR_KEY_HERE</string>\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript { \n    ext.kotlin_version = '1.4.32'\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.1.3'\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\" }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "easywaylocation/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "easywaylocation/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'kotlin-android-extensions'\napply plugin: 'kotlin-android'\napply plugin: 'com.github.dcendents.android-maven'\ngroup='com.github.prabhat1707'\nandroid {\n    compileSdkVersion 30\n    defaultConfig {\n        minSdkVersion 16\n        targetSdkVersion 30\n        versionCode 1\n        versionName \"1.0\"\n\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n            debuggable false\n        }\n        debug {\n            debuggable true\n        }\n    }\n    compileOptions {\n        sourceCompatibility = '1.8'\n        targetCompatibility = '1.8'\n    }\n    buildToolsVersion = '28.0.3'\n\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation 'com.google.android.gms:play-services-maps:17.0.0'\n    implementation 'com.google.android.gms:play-services-location:18.0.0'\n    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2'\n    implementation \"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5\"\n    implementation 'com.squareup.retrofit2:retrofit:2.6.1'\n    implementation 'com.squareup.retrofit2:converter-scalars:2.6.1'\n    implementation \"androidx.core:core-ktx:1.5.0\"\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n    implementation 'com.google.maps.android:android-maps-utils:0.6.2'\n\n}\nrepositories {\n    mavenCentral()\n}\n"
  },
  {
    "path": "easywaylocation/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "easywaylocation/src/androidTest/java/com/example/easywaylocation/ExampleInstrumentedTest.java",
    "content": "package com.example.easywaylocation;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.example.easywaylocation.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "easywaylocation/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.easywaylocation\" />\n"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/AddressHelper.java",
    "content": "package com.example.easywaylocation;\n\nimport android.content.Context;\nimport android.location.Address;\nimport android.location.Geocoder;\nimport android.location.Location;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Locale;\n\n/**\n * Created by prabhat on 2/10/18.\n */\n\n@Deprecated\npublic class AddressHelper {\n    private static final String TAG = AddressHelper.class.getSimpleName();\n\n    public static final int ADMIN_AREA = 0;\n    public static final int CITY_NAME = 1;\n    public static final int COUNTRY_CODE = 2;\n    public static final int COUNTRY_NAME = 3;\n    public static final int FEATURE_NAME = 4;\n    public static final int FULL_ADDRESS = 5;\n    public static final int PHONE_NUMBER = 6;\n    public static final int POST_CODE = 7;\n    public static final int PREMISES = 8;\n    public static final int STREET_NAME = 9;\n    public static final int SUB_ADMIN_AREA = 10;\n    public static final int SUB_THOROUGHFARE = 11;\n\n    private Context mContext;\n    private Geocoder mGeocoder;\n\n    public AddressHelper(Context context, Locale locale) {\n\n        this.mContext = context;\n        this.mGeocoder = new Geocoder(mContext, locale);\n\n    }\n\n    public void getAddressList(Location location, RequestCallback.AddressRequestCallback callback) {\n\n        List<Address> addressList = null;\n\n        try {\n\n            addressList = mGeocoder.getFromLocation(\n                    location.getLatitude(), location.getLongitude(),\n                    1); // We only want one address to be returned.\n\n        } catch (IOException e) {\n            // Catch network or other IO problems\n            callback.onAddressFailedResult(mContext.getString(R.string.deviceLocationUtil_geocoder_not_available));\n            return;\n        } catch (IllegalArgumentException e) {\n            // Catch invalid latitude or longitude values\n            callback.onAddressFailedResult(mContext.getString(R.string.deviceLocationUtil_geocoder_invalid_latLong));\n            return;\n        }\n\n        // Handle case where no address is found\n        if (addressList == null || addressList.size() == 0) {\n            callback.onAddressFailedResult(mContext.getString(R.string.deviceLocationUtil_geocoder_address_not_found));\n        } else {\n            // Return the address list\n            callback.onAddressSuccessfulResult(addressList);\n        }\n\n    }\n\n    /**\n     * Returns a String containing the requested address element or null if not found\n     *\n     * @param elementCode A package-defined int constant representing the specific\n     *                    address element to return.\n     * @param location    A Location object containing a latitude and longitude.\n     * @return String containing the requested address element if found, a reason for\n     * failure if necessary or null if address element doesn't exist.\n     */\n    public String getAddressElement(int elementCode, Location location) {\n\n        List<Address> addressList;\n        Address address;\n        String elementString = null;\n\n        try {\n\n            addressList = mGeocoder.getFromLocation(\n                    location.getLatitude(), location.getLongitude(),\n                    1); // We only want one address to be returned.\n\n        } catch (IOException e) {\n            // Catch network or other IO problems\n            return mContext.getString(R.string.deviceLocationUtil_geocoder_not_available);\n        } catch (IllegalArgumentException e) {\n            // Catch invalid latitude or longitude values\n            return mContext.getString(R.string.deviceLocationUtil_geocoder_invalid_latLong);\n        }\n\n        // Handle case where no address is found\n        if (addressList == null || addressList.size() == 0) {\n            return mContext.getString(R.string.deviceLocationUtil_geocoder_address_not_found);\n        } else {\n            // Create the Address object from the address list\n            address = addressList.get(0);\n        }\n\n        // Get the specific address element requested by the caller\n        switch (elementCode) {\n\n            case ADMIN_AREA:\n                elementString = address.getAdminArea();\n                break;\n            case CITY_NAME:\n                elementString = address.getLocality();\n                break;\n            case COUNTRY_CODE:\n                elementString = address.getCountryCode();\n                break;\n            case COUNTRY_NAME:\n                elementString = address.getCountryName();\n                break;\n            case FEATURE_NAME:\n                elementString = address.getFeatureName();\n                break;\n            case FULL_ADDRESS:\n                elementString = address.toString();\n                break;\n            case PHONE_NUMBER:\n                elementString = address.getPhone();\n                break;\n            case POST_CODE:\n                elementString = address.getPostalCode();\n                break;\n            case PREMISES:\n                elementString = address.getPremises();\n                break;\n            case STREET_NAME:\n                elementString = address.getThoroughfare();\n                break;\n            case SUB_ADMIN_AREA:\n                elementString = address.getSubAdminArea();\n                break;\n            case SUB_THOROUGHFARE:\n                elementString = address.getSubThoroughfare();\n                break;\n            default:\n                elementString = mContext.getString(R.string.deviceLocationUtil_geocoder_invalid_element);\n                break;\n        }\n\n        return elementString;\n    }\n\n}\n"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/EasyWayLocation.java",
    "content": "package com.example.easywaylocation;\n\n\nimport android.annotation.SuppressLint;\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.IntentSender;\nimport android.graphics.drawable.Drawable;\nimport android.location.Address;\nimport android.location.Geocoder;\nimport android.location.Location;\nimport android.location.LocationListener;\nimport android.location.LocationManager;\nimport android.os.Build;\nimport android.os.Looper;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.provider.Settings;\nimport android.text.TextUtils;\n\nimport com.google.android.gms.common.api.GoogleApiClient;\nimport com.google.android.gms.common.api.ResolvableApiException;\nimport com.google.android.gms.location.FusedLocationProviderClient;\nimport com.google.android.gms.location.LocationCallback;\nimport com.google.android.gms.location.LocationRequest;\nimport com.google.android.gms.location.LocationResult;\nimport com.google.android.gms.location.LocationServices;\nimport com.google.android.gms.location.LocationSettingsRequest;\nimport com.google.android.gms.location.LocationSettingsResponse;\nimport com.google.android.gms.location.SettingsClient;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.android.gms.tasks.Task;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Random;\n\n\n/**\n * Utility class for easy access to the device location on Android\n */\npublic class EasyWayLocation {\n\n\n    /*\n    google api client request code for activty result\n     */\n    public static final int LOCATION_SETTING_REQUEST_CODE = 5;\n\n    /**\n     * {@link Listener} object\n     */\n\n    public Listener getmListener;\n    /**\n     * The internal name of the provider for the coarse location\n     */\n    private static final String PROVIDER_COARSE = LocationManager.NETWORK_PROVIDER;\n    /**\n     * The internal name of the provider for the fine location\n     */\n    private static final String PROVIDER_FINE = LocationManager.GPS_PROVIDER;\n    /**\n     * The internal name of the provider for the fine location in passive mode\n     */\n    private static final String PROVIDER_FINE_PASSIVE = LocationManager.PASSIVE_PROVIDER;\n    /**\n     * The default interval to receive new location updates after (in milliseconds)\n     */\n    private static final long INTERVAL_DEFAULT = 10 * 60 * 1000;\n    /**\n     * The factor for conversion from kilometers to meters\n     */\n    private static final float KILOMETER_TO_METER = 1000.0f;\n    /**\n     * The factor for conversion from latitude to kilometers\n     */\n    private static final float LATITUDE_TO_KILOMETER = 111.133f;\n    /**\n     * The factor for conversion from longitude to kilometers at zero degree in latitude\n     */\n    private static final float LONGITUDE_TO_KILOMETER_AT_ZERO_LATITUDE = 111.320f;\n    private static final int REQUEST_CHECK_SETTINGS = 11;\n    /**\n     * The PRNG that is used for location blurring\n     */\n    private static final Random mRandom = new Random();\n    private static final double SQUARE_ROOT_TWO = Math.sqrt(2);\n    /**\n     * The last location that was internally cached when creating new instances in the same process\n     */\n    private static Location mCachedPosition;\n    /**\n     * The LocationManager instance used to query the device location\n     */\n    //private final LocationManager mLocationManager;\n    /**\n     * Whether a fine location should be required or coarse location can be used\n     */\n    //private final boolean mRequireFine;\n    /**\n     * Whether passive mode shall be used or not\n     */\n    private boolean mPassive;\n    /**\n     * The internal after which new location updates are requested (in milliseconds) where longer intervals save battery\n     */\n    private long mInterval;\n    /**\n     * Whether to require a new location (`true`) or accept old (last known) locations as well (`false`)\n     */\n    private boolean mRequireLastLocation;\n    private FusedLocationProviderClient fusedLocationClient;\n    boolean gps_enabled = false;\n    boolean network_enabled = false;\n    private Boolean locationReturn = true;\n    private Context activity;\n    private Context context;\n    private LocationCallback locationCallback;\n\n    /**\n     * The blur radius (in meters) that will be used to blur the location for privacy reasons\n     */\n    private int mBlurRadius;\n    /**\n     * The LocationListener instance used internally to listen for location updates\n     */\n    private LocationListener mLocationListener;\n    /**\n     * The current location with latitude, longitude, speed and altitude\n     */\n    private Location mPosition;\n    private Listener mListener;\n    private LocationRequest locationRequest;\n\n\n    /**\n     * Constructs a new instance\n     *\n     * @param context     the Context reference to get the system service from\n     */\n    public EasyWayLocation(final Context context,final boolean requireLastLocation,Boolean isDebuggable,final Listener listener) {\n        this(context, null, isDebuggable,requireLastLocation,listener);\n    }\n\n    /**\n     * Constructs a new instance\n     * @param context Context reference to get the system service from\n     * @param locationRequest\n     * location request\n     * @param requireLastLocation require last location or not\n\n     */\n\n    public EasyWayLocation(Context context, final LocationRequest locationRequest, final boolean requireLastLocation,Boolean isDebuggable,final Listener listener) {\n       // mLocationManager = (LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);\n        this.context = context;\n        this.mListener = listener;\n        Logger.INSTANCE.setDebuggable(isDebuggable);\n        fusedLocationClient = LocationServices.getFusedLocationProviderClient(context);\n        if (locationRequest != null){\n            this.locationRequest = locationRequest;\n        }else {\n            this.locationRequest = LocationRequest.create();\n            this.locationRequest.setInterval(10000);\n           // locationRequest.setSmallestDisplacement(10F);\n            this.locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);\n        }\n        this.mRequireLastLocation = requireLastLocation;\n        if (mRequireLastLocation) {\n            getCachedPosition();\n        }\n    }\n\n\n\n\n    /**\n     * For any radius `n`, calculate a random offset in the range `[-n, n]`\n     *\n     * @param radius the radius\n     * @return the random offset\n     */\n    private static int calculateRandomOffset(final int radius) {\n        return mRandom.nextInt((radius + 1) * 2) - radius;\n    }\n\n    /**\n     * Opens the device's settings screen where location access can be enabled\n     *\n     * @param context the Context reference to start the Intent from\n     */\n    public static void openSettings(final Context context) {\n        context.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));\n    }\n\n    /**\n     * Converts a difference in latitude to a difference in kilometers (rough estimation)\n     *\n     * @param latitude the latitude (difference)\n     * @return the kilometers (difference)\n     */\n    public static double latitudeToKilometer(double latitude) {\n        return latitude * LATITUDE_TO_KILOMETER;\n    }\n\n    /**\n     * Converts a difference in kilometers to a difference in latitude (rough estimation)\n     *\n     * @param kilometer the kilometers (difference)\n     * @return the latitude (difference)\n     */\n    public static double kilometerToLatitude(double kilometer) {\n        return kilometer / latitudeToKilometer(1.0f);\n    }\n\n    /**\n     * Converts a difference in latitude to a difference in meters (rough estimation)\n     *\n     * @param latitude the latitude (difference)\n     * @return the meters (difference)\n     */\n    public static double latitudeToMeter(double latitude) {\n        return latitudeToKilometer(latitude) * KILOMETER_TO_METER;\n    }\n\n    /**\n     * Converts a difference in meters to a difference in latitude (rough estimation)\n     *\n     * @param meter the meters (difference)\n     * @return the latitude (difference)\n     */\n    public static double meterToLatitude(double meter) {\n        return meter / latitudeToMeter(1.0f);\n    }\n\n    /**\n     * Converts a difference in longitude to a difference in kilometers (rough estimation)\n     *\n     * @param longitude the longitude (difference)\n     * @param latitude  the latitude (absolute)\n     * @return the kilometers (difference)\n     */\n    public static double longitudeToKilometer(double longitude, double latitude) {\n        return longitude * LONGITUDE_TO_KILOMETER_AT_ZERO_LATITUDE * Math.cos(Math.toRadians(latitude));\n    }\n\n    /**\n     * Converts a difference in kilometers to a difference in longitude (rough estimation)\n     *\n     * @param kilometer the kilometers (difference)\n     * @param latitude  the latitude (absolute)\n     * @return the longitude (difference)\n     */\n    public static double kilometerToLongitude(double kilometer, double latitude) {\n        return kilometer / longitudeToKilometer(1.0f, latitude);\n    }\n\n    /**\n     * Converts a difference in longitude to a difference in meters (rough estimation)\n     *\n     * @param longitude the longitude (difference)\n     * @param latitude  the latitude (absolute)\n     * @return the meters (difference)\n     */\n    public static double longitudeToMeter(double longitude, double latitude) {\n        return longitudeToKilometer(longitude, latitude) * KILOMETER_TO_METER;\n    }\n\n    /**\n     * Converts a difference in meters to a difference in longitude (rough estimation)\n     *\n     * @param meter    the meters (difference)\n     * @param latitude the latitude (absolute)\n     * @return the longitude (difference)\n     */\n    public static double meterToLongitude(double meter, double latitude) {\n        return meter / longitudeToMeter(1.0f, latitude);\n    }\n\n    /**\n     * Calculates the difference from the start position to the end position (in meters)\n     *\n     * @param start the start position\n     * @param end   the end position\n     * @return the distance in meters\n     */\n    public static double calculateDistance(Point start, Point end) {\n        return calculateDistance(start.latitude, start.longitude, end.latitude, end.longitude);\n    }\n\n    /**\n     * Calculates the difference from the start position to the end position (in meters)\n     *\n     * @param startLatitude  the latitude of the start position\n     * @param startLongitude the longitude of the start position\n     * @param endLatitude    the latitude of the end position\n     * @param endLongitude   the longitude of the end position\n     * @return the distance in meters\n     */\n    public static double calculateDistance(double startLatitude, double startLongitude, double endLatitude, double endLongitude) {\n        float[] results = new float[3];\n        Location.distanceBetween(startLatitude, startLongitude, endLatitude, endLongitude, results);\n        return results[0];\n    }\n\n    /**\n     * Attaches or detaches a listener that informs about certain events\n     *\n     * @param listener the `EasyWayLocation.Listener` instance to attach or `null` to detach\n     */\n    public void setListener(final Listener listener) {\n        mListener = listener;\n    }\n\n\n    public boolean hasLocationEnabled() {\n        try {\n            int locationMode = 0;\n            String locationProviders;\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){\n                try {\n                    locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);\n\n                } catch (Settings.SettingNotFoundException e) {\n                    e.printStackTrace();\n                    return false;\n                }\n                return locationMode != Settings.Secure.LOCATION_MODE_OFF;\n            }else{\n                locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);\n                return !TextUtils.isEmpty(locationProviders);\n            }\n        }catch (Exception e){\n            e.printStackTrace();\n            return false;\n        }\n    }\n\n    public void startLocation(){\n        checkLocationSetting();\n    }\n\n    /**\n     * Starts updating the location and requesting new updates after the defined interval\n     */\n    @SuppressLint(\"MissingPermission\")\n    private void beginUpdates() {\n        locationCallback = new LocationCallback(){\n            @Override\n            public void onLocationResult(LocationResult locationResult) {\n                if (locationResult == null) {\n                    mListener.locationCancelled();\n                }else {\n                    for (Location location : locationResult.getLocations()) {\n                        mListener.currentLocation(location);\n                    }\n                }\n\n            }\n        };\n\n        fusedLocationClient.requestLocationUpdates(locationRequest,\n                locationCallback,\n                Looper.getMainLooper());\n    }\n\n    /**\n     * Stops the location updates when they aren't needed anymore so that battery can be saved\n     */\n    @SuppressLint(\"MissingPermission\")\n    public void endUpdates() {\n        if (locationCallback != null){\n            fusedLocationClient.removeLocationUpdates(locationCallback);\n        }\n    }\n\n    /**\n     * Blurs the specified location with the defined blur radius or returns an unchanged location if no blur radius is set\n     *\n     * @param originalLocation the original location received from the device\n     * @return the blurred location\n     */\n    private Location blurWithRadius(final Location originalLocation) {\n        if (mBlurRadius <= 0) {\n            return originalLocation;\n        } else {\n            Location newLocation = new Location(originalLocation);\n\n            double blurMeterLong = calculateRandomOffset(mBlurRadius) / SQUARE_ROOT_TWO;\n            double blurMeterLat = calculateRandomOffset(mBlurRadius) / SQUARE_ROOT_TWO;\n\n            newLocation.setLongitude(newLocation.getLongitude() + meterToLongitude(blurMeterLong, newLocation.getLatitude()));\n            newLocation.setLatitude(newLocation.getLatitude() + meterToLatitude(blurMeterLat));\n\n            return newLocation;\n        }\n    }\n\n    /**\n     * Returns the current position as a Point instance\n     *\n     * @return the current location (if any) or `null`\n     */\n    public Point getPosition() {\n        if (mPosition == null) {\n            return null;\n        } else {\n            Location position = blurWithRadius(mPosition);\n            return new Point(position.getLatitude(), position.getLongitude());\n        }\n    }\n\n    /**\n     * Returns the latitude of the current location\n     *\n     * @return the current latitude (if any) or `0`\n     */\n    public double getLatitude() {\n        if (mPosition == null) {\n            return 0.0f;\n        } else {\n            Location position = blurWithRadius(mPosition);\n            return position.getLatitude();\n        }\n    }\n\n    /**\n     * Returns the longitude of the current location\n     *\n     * @return the current longitude (if any) or `0`\n     */\n    public double getLongitude() {\n        if (mPosition == null) {\n            return 0.0f;\n        } else {\n            Location position = blurWithRadius(mPosition);\n            return position.getLongitude();\n        }\n    }\n\n    /**\n     * Returns the current speed\n     *\n     * @return the current speed (if detected) or `0`\n     */\n    public float getSpeed() {\n        if (mPosition == null) {\n            return 0.0f;\n        } else {\n            return mPosition.getSpeed();\n        }\n    }\n\n    /**\n     * Returns the current altitude\n     *\n     * @return the current altitude (if detected) or `0`\n     */\n    public double getAltitude() {\n        if (mPosition == null) {\n            return 0.0f;\n        } else {\n            return mPosition.getAltitude();\n        }\n    }\n\n    /**\n     * Sets the blur radius (in meters) to use for privacy reasons\n     *\n     * @param blurRadius the blur radius (in meters)\n     */\n    public void setBlurRadius(final int blurRadius) {\n        mBlurRadius = blurRadius;\n    }\n\n\n    @SuppressLint(\"MissingPermission\")\n    private void getCachedPosition() {\n        fusedLocationClient.getLastLocation()\n                .addOnSuccessListener(new OnSuccessListener<Location>() {\n                    @Override\n                    public void onSuccess(Location location) {\n                        // Got last known location. In some rare situations this can be null.\n                        if (location != null) {\n                            mListener.currentLocation(location);\n                        }else {\n                            checkLocationSetting();\n                            beginUpdates();\n                            endUpdates();\n                        }\n                    }\n                });\n    }\n\n    /**\n     * Caches the current position\n     */\n    @Deprecated\n    private void cachePosition() {\n        if (mPosition != null) {\n            mCachedPosition = mPosition;\n        }\n    }\n\n    /**\n     * Wrapper for two coordinates (latitude and longitude)\n     */\n    public static class Point implements Parcelable {\n\n        public static final Creator<Point> CREATOR = new Creator<Point>() {\n\n            @Override\n            public Point createFromParcel(Parcel in) {\n                return new Point(in);\n            }\n\n            @Override\n            public Point[] newArray(int size) {\n                return new Point[size];\n            }\n\n        };\n        /**\n         * The latitude of the point\n         */\n        public final double latitude;\n        /**\n         * The longitude of the point\n         */\n        public final double longitude;\n\n        /**\n         * Constructs a new point from the given coordinates\n         *\n         * @param lat the latitude\n         * @param lon the longitude\n         */\n        public Point(double lat, double lon) {\n            latitude = lat;\n            longitude = lon;\n        }\n\n        private Point(Parcel in) {\n            latitude = in.readDouble();\n            longitude = in.readDouble();\n        }\n\n        @Override\n        public String toString() {\n            return \"(\" + latitude + \", \" + longitude + \")\";\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel out, int flags) {\n            out.writeDouble(latitude);\n            out.writeDouble(longitude);\n        }\n\n    }\n\n    public void onActivityResult(int result) {\n\n        if (result == Activity.RESULT_OK) {\n            mListener.locationOn();\n            beginUpdates();\n        } else if (result == Activity.RESULT_CANCELED) {\n            mListener.locationCancelled();\n        }\n    }\n\n    public void showAlertDialog(String title, String message, Drawable drawable) {\n        AlertDialog alertDialog = new AlertDialog.Builder(context).create();\n        alertDialog.setTitle(title);\n        if (drawable != null) {\n            alertDialog.setIcon(drawable);\n        }\n        alertDialog.setMessage(message);\n        alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.ok),\n                new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        dialog.dismiss();\n                    }\n                });\n        alertDialog.show();\n    }\n\n    public static String getAddress(Context context, Double latitude, Double longitude, boolean country, boolean fullAddress) {\n        String add = \"\";\n        Geocoder geoCoder = new Geocoder(((Activity) context).getBaseContext(), Locale.getDefault());\n        try {\n            List<Address> addresses = geoCoder.getFromLocation(latitude, longitude, 1);\n\n            if (addresses.size() > 0) {\n                if (country) {\n                    add = addresses.get(0).getCountryName();\n                } else if (fullAddress) {\n                    add = addresses.get(0).getFeatureName() + \",\" + addresses.get(0).getSubLocality() + \",\" + addresses.get(0).getSubAdminArea() + \",\" + addresses.get(0).getPostalCode() + \",\" + addresses.get(0).getCountryName();\n                } else {\n                    add = addresses.get(0).getLocality();\n                }\n            }\n\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return add.replaceAll(\",null\", \"\");\n    }\n\n    private void checkLocationSetting(){\n        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();\n        builder.setAlwaysShow(true);\n        builder.addLocationRequest(locationRequest);\n        SettingsClient client = LocationServices.getSettingsClient(context);\n        Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());\n\n        task.addOnSuccessListener(locationSettingsResponse -> {\n            if (mRequireLastLocation){\n                beginUpdates();\n                endUpdates();\n            }else {\n                beginUpdates();\n            }\n\n        });\n\n        task.addOnFailureListener(e -> {\n            if (e instanceof ResolvableApiException) {\n                // Location settings are not satisfied, but this can be fixed\n                // by showing the user a dialog.\n                try {\n                    // Show the dialog by calling startResolutionForResult(),\n                    // and check the result in onActivityResult().\n                    ResolvableApiException resolvable = (ResolvableApiException) e;\n                    resolvable.startResolutionForResult((Activity)context,\n                            LOCATION_SETTING_REQUEST_CODE);\n                } catch (IntentSender.SendIntentException sendEx) {\n                        sendEx.printStackTrace();\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/GetLocationDetail.java",
    "content": "package com.example.easywaylocation;\n\nimport android.content.Context;\nimport android.location.Address;\nimport android.location.Geocoder;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Locale;\n\nimport retrofit2.Call;\nimport retrofit2.Callback;\nimport retrofit2.Response;\nimport retrofit2.Retrofit;\nimport retrofit2.converter.scalars.ScalarsConverterFactory;\nimport retrofit2.http.GET;\nimport retrofit2.http.Query;\n\npublic class GetLocationDetail {\n    private static final String BASE_URL = \"https://maps.googleapis.com/maps/\";\n    private static Retrofit retrofit;\n    private LocationData.AddressCallBack addressCallBack;\n    private Context context;\n    private final String TAG = \"GetLocationDetailExc-->\";\n\n    public GetLocationDetail(LocationData.AddressCallBack addressCallBack, Context context) {\n        this.addressCallBack = addressCallBack;\n        this.context = context;\n    }\n\n    private static Retrofit getRetrofitInstance() {\n        if (retrofit == null) {\n            retrofit = new retrofit2.Retrofit.Builder()\n                    .baseUrl(BASE_URL)\n                    .addConverterFactory(ScalarsConverterFactory.create())\n                    .build();\n        }\n        return retrofit;\n    }\n\n    public void getAddress(Double latitude, Double longitude, String key) {\n        try {\n            Geocoder geocoder = new Geocoder(context, Locale.getDefault());\n            List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);\n            if (addresses != null && addresses.size() > 0) {\n\n                String address = addresses.get(0).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()\n                String city = addresses.get(0).getLocality();\n                String state = addresses.get(0).getAdminArea();\n                String country = addresses.get(0).getCountryName();\n                String postalCode = addresses.get(0).getPostalCode();\n                String knownName = addresses.get(0).getFeatureName(); // Only if available else return NULL\n                LocationData locationData = new LocationData();\n                locationData.setCity(city);\n                locationData.setFull_address(address);\n                locationData.setPincode(postalCode);\n                locationData.setCountry(country);\n                addressCallBack.locationData(locationData);\n\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n            getAddressFromApi(latitude, longitude, key);\n        }\n    }\n\n    private void getAddressFromApi(Double latitude, Double longitude, String key) {\n        StringBuilder tempBuilder = new StringBuilder();\n        tempBuilder.append(latitude);\n        tempBuilder.append(\",\");\n        tempBuilder.append(longitude);\n        DataService dataService = getRetrofitInstance().create(DataService.class);\n        Call<String> stringCall = dataService.getData(tempBuilder.toString(), true, key);\n        if (stringCall.isExecuted()) {\n            stringCall.cancel();\n        }\n        stringCall.enqueue(new Callback<String>() {\n            @Override\n            public void onResponse(Call<String> call, Response<String> response) {\n                try {\n                    JSONObject jsonObject = new JSONObject(response.body());\n                    JSONArray Results = jsonObject.getJSONArray(\"results\");\n                    JSONObject zero = Results.getJSONObject(0);\n                    JSONArray address_components = zero.getJSONArray(\"address_components\");\n                    LocationData locationData = new LocationData();\n                    locationData.setFull_address(zero.getString(\"formatted_address\"));\n                    for (int i = 0; i < address_components.length(); i++) {\n                        JSONObject zero2 = address_components.getJSONObject(i);\n                        String long_name = zero2.getString(\"long_name\");\n                        JSONArray mtypes = zero2.getJSONArray(\"types\");\n                        String Type = mtypes.getString(0);\n                        if (TextUtils.isEmpty(long_name) == false || !long_name.equals(null) || long_name.length() > 0 || long_name != \"\") {\n                            if (Type.equalsIgnoreCase(\"street_number\")) {\n                                //Address1 = long_name + \" \";\n                            } else if (Type.equalsIgnoreCase(\"route\")) {\n                                //Address1 = Address1 + long_name;\n                            } else if (Type.equalsIgnoreCase(\"sublocality\")) {\n                                // Address2 = long_name;\n                            } else if (Type.equalsIgnoreCase(\"locality\")) {\n                                // Address2 = Address2 + long_name + \", \";\n                                locationData.setCity(long_name);\n                            } else if (Type.equalsIgnoreCase(\"administrative_area_level_2\")) {\n                                // County = long_name;\n\n                            } else if (Type.equalsIgnoreCase(\"administrative_area_level_1\")) {\n                                // State = long_name;\n                            } else if (Type.equalsIgnoreCase(\"country\")) {\n                                locationData.setCountry(long_name);\n                            } else if (Type.equalsIgnoreCase(\"postal_code\")) {\n                                locationData.setPincode(long_name);\n                            }\n                        }\n                    }\n                    addressCallBack.locationData(locationData);\n                } catch (JSONException e) {\n                    Logger.INSTANCE.LogDebug(TAG,\"From getAddressFromApi JSONException \"+e.getMessage());\n                }\n                catch (NullPointerException e){\n                    Logger.INSTANCE.LogDebug(TAG,\"From getAddressFromApi NullPointerException \"+e.getMessage());\n                }\n            }\n\n            @Override\n            public void onFailure(Call<String> call, Throwable t) {\n                Logger.INSTANCE.LogDebug(TAG,\"From getAddressFromApi onFailure \"+ t.toString());\n            }\n        });\n    }\n\n\n    private interface DataService {\n        @GET(\"api/geocode/json\")\n        Call<String> getData(@Query(\"latlng\") String latLong, @Query(\"sensor\") boolean sensor, @Query(\"key\") String key);\n    }\n}\n"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/Listener.java",
    "content": "package com.example.easywaylocation;\n\n/**\n * Created by prabhat on 11/2/18.\n */\n\nimport android.location.Location;\n\n/**\n * Callback that can be implemented in order to listen for events\n */\n\npublic interface Listener {\n    public String TAG = \"Location_Sample_Logs\";\n    void locationOn();\n\n    void currentLocation(Location location);\n\n    void locationCancelled();\n}\n\n\n"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/LocationData.java",
    "content": "package com.example.easywaylocation;\n\npublic class LocationData {\n    private String city, country, pincode, full_address;\n\n    public String getCity() {\n        return city;\n    }\n\n    public void setCity(String city) {\n        this.city = city;\n    }\n\n    public String getCountry() {\n        return country;\n    }\n\n    public void setCountry(String country) {\n        this.country = country;\n    }\n\n    public String getPincode() {\n        return pincode;\n    }\n\n    public void setPincode(String pincode) {\n        this.pincode = pincode;\n    }\n\n    public String getFull_address() {\n        return full_address;\n    }\n\n    public void setFull_address(String full_address) {\n        this.full_address = full_address;\n    }\n\n    public interface AddressCallBack {\n        void locationData(LocationData locationData);\n    }\n}\n"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/Logger.kt",
    "content": "package com.example.easywaylocation\n\nimport android.util.Log\n\nobject Logger {\n     var isDebuggable = false;\n\n    fun LogDebug(tag:String,mess:String){\n       if (isDebuggable){\n           Log.e(tag,mess)\n       }\n    }\n\n    fun LogInfo(tag:String,mess:String){\n        if (isDebuggable){\n            Log.v(tag,mess)\n        }\n    }\n}"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/RequestCallback.java",
    "content": "package com.example.easywaylocation;\n\nimport android.location.Address;\nimport android.location.Location;\n\nimport java.util.List;\n\n/**\n * Created by prabhat on 2/10/18.\n */\n\npublic class RequestCallback {\n\n    public interface LocationRequestCallback {\n        void onLocationResult(Location location);\n\n        void onFailedRequest(String result);\n    }\n\n    public interface PermissionRequestCallback {\n        void onRationaleDialogOkPressed(int requestCode);\n    }\n\n    public interface AddressRequestCallback {\n        void onAddressSuccessfulResult(List<Address> addressList);\n\n        void onAddressFailedResult(String result);\n    }\n\n\n}\n"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/draw_path/DataParser.java",
    "content": "package com.example.easywaylocation.draw_path;\n\nimport com.google.android.gms.maps.model.LatLng;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\npublic class DataParser {\n    /** Receives a JSONObject and returns a list of lists containing latitude and longitude */\n    private PolyLineDataBean polyLineDataBean = new PolyLineDataBean();\n\n    public List<List<HashMap<String,String>>> parse(JSONObject jObject){\n\n        List<List<HashMap<String, String>>> routes = new ArrayList<>() ;\n        JSONArray jRoutes;\n        JSONArray jLegs;\n        JSONArray jSteps;\n\n        try {\n\n            jRoutes = jObject.getJSONArray(\"routes\");\n\n            /** Traversing all routes */\n            for(int i=0;i<jRoutes.length();i++){\n                jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray(\"legs\");\n               polyLineDataBean.setPlaceSummary(((JSONObject) jRoutes.get(i)).getString(\"summary\"));\n                List<HashMap<String, String>> path = new ArrayList<>();\n\n                /** Traversing all legs */\n                for(int j=0;j<jLegs.length();j++){\n                    polyLineDataBean.setTime(( (JSONObject)jLegs.get(j)).getJSONObject(\"duration\").getString(\"value\"));\n                    polyLineDataBean.setDistance(( (JSONObject)jLegs.get(j)).getJSONObject(\"distance\").getString(\"value\"));\n                    jSteps = ( (JSONObject)jLegs.get(j)).getJSONArray(\"steps\");\n\n                    /** Traversing all steps */\n                    for(int k=0;k<jSteps.length();k++){\n                        String polyline = \"\";\n                        polyline = (String)((JSONObject)((JSONObject)jSteps.get(k)).get(\"polyline\")).get(\"points\");\n                        List<LatLng> list = decodePoly(polyline);\n\n                        /** Traversing all points */\n                        for(int l=0;l<list.size();l++){\n                            HashMap<String, String> hm = new HashMap<>();\n                            hm.put(\"lat\", Double.toString((list.get(l)).latitude) );\n                            hm.put(\"lng\", Double.toString((list.get(l)).longitude) );\n                            path.add(hm);\n                        }\n                    }\n                    routes.add(path);\n                }\n            }\n\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }catch (Exception ignored){\n        }\n\n\n        return routes;\n    }\n\n    public PolyLineDataBean getPolyLineDataBean(){\n        return polyLineDataBean;\n    }\n\n    /**\n     * Method to decode polyline points\n     decoding-polylines-from-google-maps-direction-api-with-java\n     * */\n    private List<LatLng> decodePoly(String encoded) {\n\n        List<LatLng> poly = new ArrayList<>();\n        int index = 0, len = encoded.length();\n        int lat = 0, lng = 0;\n\n        while (index < len) {\n            int b, shift = 0, result = 0;\n            do {\n                b = encoded.charAt(index++) - 63;\n                result |= (b & 0x1f) << shift;\n                shift += 5;\n            } while (b >= 0x20);\n            int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));\n            lat += dlat;\n\n            shift = 0;\n            result = 0;\n            do {\n                b = encoded.charAt(index++) - 63;\n                result |= (b & 0x1f) << shift;\n                shift += 5;\n            } while (b >= 0x20);\n            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));\n            lng += dlng;\n\n            LatLng p = new LatLng((((double) lat / 1E5)),\n                    (((double) lng / 1E5)));\n            poly.add(p);\n        }\n\n        return poly;\n    }\n}\n"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/draw_path/DirectionUtil.kt",
    "content": "package com.example.easywaylocation.draw_path\n\nimport android.graphics.Color\nimport androidx.annotation.ColorRes\nimport androidx.annotation.IntegerRes\nimport com.example.easywaylocation.Logger\nimport com.google.android.gms.maps.GoogleMap\nimport com.google.android.gms.maps.model.JointType\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.Polyline\nimport com.google.android.gms.maps.model.PolylineOptions\nimport com.google.maps.android.SphericalUtil\nimport kotlinx.coroutines.*\nimport org.json.JSONObject\nimport java.io.BufferedReader\nimport java.io.InputStream\nimport java.io.InputStreamReader\nimport java.net.HttpURLConnection\nimport java.net.URL\n\nclass DirectionUtil private constructor(builder: Builder) {\n    private var directionCallBack: DirectionCallBack?\n    private val allPathPoints:ArrayList<LatLng> = ArrayList()\n    private var mMap: GoogleMap?\n    private var directionKey: String?\n    private val TAG = \"Draw path -->\"\n    private var wayPoints = ArrayList<LatLng>()\n    private var origin: LatLng?\n    private var destination: LatLng?\n    private var polyLineWidth = 10\n    private var pathAnimation:Boolean\n    private var polyLinePrimaryColor:Int = 0\n    private var polyLineSecondaryColor = 0\n    private var isEnd = false\n    private var pathCompletionTime = 2500\n    private var pathColorFillAnimationTime = 1800\n    private var polyLineDetails:HashMap<String,PolyLineDataBean> = HashMap()\n    private var polyLineDetailsArray:ArrayList<PolyLineDataBean> = ArrayList()\n    private var polyLineDataBean = PolyLineDataBean()\n    private var arrayOfPoints: ArrayList<ArrayList<LatLng>> = ArrayList()\n    private var primaryLineCompletionTime = 2000\n\n    private var animationDelay = 200\n    private var polylineMap:HashMap<String,ArrayList<PolylineBean>> = HashMap()\n\n    init {\n        this.directionCallBack = builder.directionCallBack\n        this.destination = builder.destination\n        this.directionKey = builder.key\n        this.origin = builder.origin\n        this.polyLineWidth = builder.polyLineWidth\n        builder.polyLinePrimaryColor?.let {\n            this.polyLinePrimaryColor =it\n        }?:kotlin.run {\n            this.polyLinePrimaryColor = Color.BLACK\n        }\n        builder.polyLineSecondaryColor?.let {\n            this.polyLineSecondaryColor =it\n        }?:kotlin.run {\n            this.polyLineSecondaryColor = Color.LTGRAY\n        }\n        this.wayPoints = builder.wayPoints\n        this.pathAnimation = builder.pathAnimation\n        this.mMap = builder.mMap\n        this.pathCompletionTime = builder.pathCompletionTime\n        this.pathColorFillAnimationTime = builder.pathColorFillAnimationTime\n        this.primaryLineCompletionTime = builder.primaryLineCompletionTime\n        this.animationDelay = builder.animationDelay\n    }\n\n    fun setPathAnimation(boolean:Boolean) = apply { this.pathAnimation = boolean }\n\n    fun setCompletionTime(@IntegerRes time: Int) = apply { this.pathCompletionTime = time }\n\n    fun setColorFillCompletion(@IntegerRes time: Int) = apply { this.pathColorFillAnimationTime = time }\n\n    fun setPrimaryLineCompletion(@IntegerRes time: Int) = apply { this.primaryLineCompletionTime = time }\n\n    fun setDelayTime(@IntegerRes time: Int) = apply { this.animationDelay = time }\n\n    fun setPolyLineWidth(polyLineWidth: Int) {\n        this.polyLineWidth = polyLineWidth\n    }\n\n    fun setPolyLinePrimaryColor(@ColorRes color: Int) {\n        this.polyLinePrimaryColor = color\n    }\n\n    fun getPolylineMap():HashMap<String,ArrayList<PolylineBean>>{\n        return polylineMap\n    }\n\n    fun setPolyLineSecondaryColor(@ColorRes color: Int) {\n        this.polyLineSecondaryColor = color\n    }\n\n    @Throws(Exception::class)\n    fun initPath() {\n        if (directionKey.isNullOrBlank()) {\n            throw Exception(\"Direction directionKey is not valid\")\n        }\n        if (allPathPoints.isNotEmpty()){\n            allPathPoints.clear()\n            polyLineDetailsArray.clear()\n        }\n        origin?.let { org ->\n            destination?.let { des ->\n                wayPoints.add(0, org)\n                wayPoints.add(wayPoints.size, des)\n                GlobalScope.launch(Dispatchers.Main + mainException) {\n                    for (i in 1 until wayPoints.size) {\n                        if (i == wayPoints.size - 1) {\n                            isEnd = true\n                        }\n                        val data = downlaodDataFromUrl(wayPoints[i - 1],wayPoints[i],i)\n                        Logger.LogDebug(TAG,data.await())\n                        drawData(parseDownloadedData(data.await(),i).await(),i)\n                    }\n                }\n\n            } ?: kotlin.run {\n                throw Exception(\"Make sure destination not null\")\n            }\n\n        } ?: kotlin.run {\n            throw Exception(\"Make sure Origin not null\")\n        }\n    }\n\n    private fun downlaodDataFromUrl(o:LatLng,d:LatLng,i:Int):Deferred<String> = runBlocking {\n        val url = getUrl(o, d)\n        Logger.LogInfo(\"$TAG url $i\", url)\n        async(Dispatchers.IO + downloadDataFromUrlException) { downloadUrl(url) }\n    }\n\n    private fun parseDownloadedData(data:String,i:Int):Deferred<List<List<HashMap<String, String>>> > = runBlocking {\n        async(Dispatchers.IO + parseDataFromUrlException) { doParsingWork(data,wayPoints[i]) }\n    }\n\n    fun getShortestPathDetails(origin:LatLng, destination: LatLng):PolyLineDataBean = runBlocking{\n        val data = downlaodDataFromUrl(origin,destination,0)\n        val jObject =  JSONObject(data.await())\n        Logger.LogInfo(TAG,jObject.toString())\n        val parser = DataParser()\n        parser.parse(jObject)\n        parser.polyLineDataBean.apply {\n            this.position = destination\n            this.distanceFromPrevPoint = this.distance\n            this.timeFromPrevPoint = this.time\n        }\n    }\n\n    private val downloadDataFromUrlException = CoroutineExceptionHandler { _, exception ->\n        exception.message?.let {\n            Logger.LogDebug(TAG, \"${it}\")\n        }\n    }\n\n    private val parseDataFromUrlException = CoroutineExceptionHandler { _, exception ->\n        exception.message?.let {\n            Logger.LogDebug(TAG, \"${it}\")\n        }\n    }\n\n    private val mainException = CoroutineExceptionHandler { _, exception ->\n        exception.message?.let {\n            Logger.LogDebug(TAG, \"${it} Please check your internet Connection.\")\n        }\n    }\n\n    fun serOrigin(latLng: LatLng, wayPoint: ArrayList<LatLng>){\n        this.origin = latLng\n        this.wayPoints.clear()\n        this.wayPoints = ArrayList(wayPoint)\n    }\n\n    private fun drawData(result: List<List<HashMap<String, String>>>, pathIncrementer: Int) {\n        arrayOfPoints.clear();\n        var points: ArrayList<LatLng>\n        val lineOptions = PolylineOptions()\n\n        // Traversing through all the routes\n        for (i in result.indices) {\n            points = ArrayList()\n            //lineOptions = PolylineOptions()\n\n            // Fetching i-th route\n            val path = result[i]\n\n            // Fetching all the points in i-th route\n            for (j in path.indices) {\n                val point = path[j]\n\n                val lat = java.lang.Double.parseDouble(point[\"lat\"]!!)\n                val lng = java.lang.Double.parseDouble(point[\"lng\"]!!)\n                val position = LatLng(lat, lng)\n\n                points.add(position)\n                allPathPoints.add(position)\n                arrayOfPoints.add(allPathPoints)\n\n            }\n        }\n        polyLineDetails[\"path$pathIncrementer\"] = polyLineDataBean\n        polyLineDetailsArray.add(polyLineDataBean)\n        if (isEnd) {\n            updatePathDetails(polyLineDetails)\n            directionCallBack?.pathFindFinish(polyLineDetails,polyLineDetailsArray)\n            isEnd = false\n        }\n    }\n\n    private fun updatePathDetails(polyLineDetails: java.util.HashMap<String, PolyLineDataBean>) {\n        val size = polyLineDetails.size\n        if (size == 1) return\n        var pathIncrementer = 1;\n        while (pathIncrementer <= size){\n            polyLineDetails[\"path${pathIncrementer}\"]?.timeFromPrevPoint = ((polyLineDetails[\"path${pathIncrementer-1}\"]?.timeFromPrevPoint?.toDouble() ?: 0.0) + (polyLineDetails[\"path${pathIncrementer}\"]?.time?.toDouble()\n                ?: 0.0)).toString()\n            polyLineDetails[\"path${pathIncrementer}\"]?.distanceFromPrevPoint = ((polyLineDetails[\"path${pathIncrementer-1}\"]?.distanceFromPrevPoint?.toDouble() ?: 0.0) + (polyLineDetails[\"path${pathIncrementer}\"]?.distance?.toDouble()\n                ?: 0.0)).toString()\n            pathIncrementer++;\n        }\n    }\n\n    fun drawPath(mTag:String){\n        val polylineArray = ArrayList<PolylineBean>()\n        if (!pathAnimation){\n            for(array in arrayOfPoints){\n                val lineOptions = PolylineOptions()\n                // Adding all the points in the route to LineOptions\n                lineOptions.addAll(array)\n                lineOptions.jointType(JointType.ROUND)\n                lineOptions.width(polyLineWidth.toFloat())\n                lineOptions.clickable(true)\n                polylineArray.add(PolylineBean(mMap?.addPolyline(lineOptions),null))\n                Logger.LogInfo(TAG,\"onPostExecute lineoptions decoded\")\n            }\n            polylineMap.put(mTag,polylineArray)\n\n        }else{\n            mMap?.let {\n                val mapAnimator = MapAnimator()\n                mapAnimator.setColorFillCompletion(pathColorFillAnimationTime)\n                mapAnimator.setDelayTime(animationDelay)\n                mapAnimator.setPrimaryLineColor(polyLinePrimaryColor)\n                mapAnimator.setSecondaryLineColor(polyLineSecondaryColor)\n                mapAnimator.setCompletionTime(pathCompletionTime)\n                mapAnimator.setPrimaryLineCompletion(primaryLineCompletionTime)\n                mapAnimator.animateRoute(it, allPathPoints,polyLineDataBean)\n                polylineMap.put(mTag,mapAnimator.getPolyline())\n            }\n        }\n\n    }\n\n    private fun doParsingWork(jsonData: String, latLng: LatLng): List<List<HashMap<String, String>>> {\n        val jObject = JSONObject(jsonData)\n        Logger.LogInfo(TAG,jsonData)\n        val parser = DataParser()\n        Logger.LogInfo(TAG,parser.toString())\n        // Starts parsing data\n        val routes: List<List<HashMap<String, String>>> = parser.parse(jObject)\n        polyLineDataBean = parser.polyLineDataBean.apply {\n            this.position = latLng\n        }\n        Logger.LogInfo(TAG,\"Executing routes--->\")\n        Logger.LogDebug(TAG, routes.toString())\n        return routes\n    }\n\n    /**\n     *\n     * A method to download json data frpublicom url\n     */\n\n    private fun downloadUrl(strUrl: String): String {\n        val data: String\n        var iStream: InputStream? = null\n        val urlConnection: HttpURLConnection?\n        val url = URL(strUrl)\n\n        // Creating an http connection to communicate with url\n        urlConnection = url.openConnection() as HttpURLConnection\n\n        // Connecting to url\n        urlConnection.connect()\n\n        // Reading data from url\n        iStream = urlConnection.inputStream\n\n        val br = BufferedReader(InputStreamReader(iStream))\n\n        val sb = StringBuffer()\n        val strings = br.readLines()\n        for( i in strings){\n            sb.append(i)\n        }\n        data = sb.toString()\n        br.close()\n        iStream?.close()\n        urlConnection.disconnect()\n        return data\n    }\n\n    private fun getUrl(origin: LatLng, dest: LatLng): String {\n\n        // Origin of route\n        val str_origin = \"origin=\" + origin.latitude + \",\" + origin.longitude\n\n        // Destination of route\n        val str_dest = \"destination=\" + dest.latitude + \",\" + dest.longitude\n\n        // Sensor enabled\n        val sensor = \"sensor=false\"\n\n        //directionKey\n        val key = \"key=\" + directionKey!!\n\n        // Building the parameters to the web service\n        val parameters = \"$str_origin&$str_dest&$sensor&$key\"\n\n        // Output format\n        val output = \"json\"\n\n        // Building the url to the web service\n\n\n        return \"https://maps.googleapis.com/maps/api/directions/$output?$parameters\"\n    }\n\n    fun drawArcDirection(origin: LatLng, destination: LatLng, radius: Double,tag:String) {\n         GlobalScope.launch(Dispatchers.IO) {\n             val allPathPoints:ArrayList<LatLng> = ArrayList()\n             val d: Double = SphericalUtil.computeDistanceBetween(origin, destination)\n             val h: Double = SphericalUtil.computeHeading(origin, destination)\n\n             //Midpoint position\n             val p: LatLng = SphericalUtil.computeOffset(origin, d * 0.5, h)\n\n             val x = (1 - radius * radius) * d * 0.5 / (2 * radius)\n             val r = (1 + radius * radius) * d * 0.5 / (2 * radius)\n             val c: LatLng = SphericalUtil.computeOffset(p, x, h + 90.0)\n\n             //Calculate heading between circle center and two points\n             val h1: Double = SphericalUtil.computeHeading(c, origin)\n             val h2: Double = SphericalUtil.computeHeading(c, destination)\n\n             //Calculate positions of points on circle border and add them to polyline options\n             val numpoints = 100\n             val step = (h2 - h1) / numpoints\n             for (i in 0 until numpoints) {\n                 val pi: LatLng = SphericalUtil.computeOffset(c, r, h1 + i * step)\n                 allPathPoints.add(pi)\n             }\n             withContext(Dispatchers.Main){\n                 val polylineArray = ArrayList<PolylineBean>()\n                 if (!pathAnimation){\n                     val lineOptions = PolylineOptions()\n                     lineOptions.addAll(allPathPoints)\n                     lineOptions.jointType(JointType.ROUND)\n                     lineOptions.width(polyLineWidth.toFloat())\n                     lineOptions.clickable(true)\n                     val polyLine = mMap?.addPolyline(lineOptions)\n                     polylineArray.add(PolylineBean(polyLine,null))\n                     polylineMap.put(tag,polylineArray)\n                     this.cancel()\n                     return@withContext\n                 }\n                 mMap?.let {\n                     val mapAnimator = MapAnimator()\n                     mapAnimator.setColorFillCompletion(pathColorFillAnimationTime)\n                     mapAnimator.setDelayTime(animationDelay)\n                     mapAnimator.setPrimaryLineColor(polyLinePrimaryColor)\n                     mapAnimator.setSecondaryLineColor(polyLineSecondaryColor)\n                     mapAnimator.setCompletionTime(pathCompletionTime)\n                     mapAnimator.setPrimaryLineCompletion(primaryLineCompletionTime)\n                     mapAnimator.animateRoute(it, allPathPoints,polyLineDataBean)\n                     polylineMap.put(tag,mapAnimator.getPolyline())\n                 }\n             }\n         }\n\n    }\n\n    fun clearPolyline(mTag: String){\n        if (!polylineMap.containsKey(mTag)){\n            throw java.lang.Exception(\"No Polyline Tag Found\")\n        }\n        polylineMap.get(mTag)?.let {\n            for (polyline in it){\n                polyline.foreground?.remove()\n                if (pathAnimation){\n                    polyline.backPolyline?.remove()\n                }\n            }\n        }?:run{\n            throw java.lang.Exception(\"Please initiate polyline before calling this.\")\n        }\n\n    }\n\n    interface DirectionCallBack {\n        fun pathFindFinish(\n            polyLineDetailsMap: HashMap<String, PolyLineDataBean>,\n            polyLineDetailsArray: ArrayList<PolyLineDataBean>\n        )\n    }\n\n    class Builder {\n        var directionCallBack: DirectionCallBack? = null\n            private set\n        var mMap: GoogleMap? = null\n            private set\n        var key: String? = null\n            private set\n        var wayPoints = ArrayList<LatLng>()\n            private set\n        var origin: LatLng? = null\n            private set\n        var destination: LatLng? = null\n            private set\n        var polyLineWidth = 13\n            private set\n        var polyLineSecondaryColor:Int? = null\n            private set\n        var polyLinePrimaryColor:Int? = null\n            private set\n        var pathAnimation = false\n            private set\n        var pathCompletionTime = 2500\n            private set\n\n        var pathColorFillAnimationTime = 1800\n            private set\n\n        var primaryLineCompletionTime = 2000\n            private set\n\n        var animationDelay = 200\n            private set\n\n        fun setCallback(directionCallBack: DirectionCallBack) = apply { this.directionCallBack = directionCallBack }\n\n        fun setWayPoints(wayPoints: ArrayList<LatLng>): Builder {\n            this.wayPoints = ArrayList(wayPoints)\n            return this\n        }\n\n        fun setOrigin(origin: LatLng): Builder {\n            this.origin = origin\n            return this\n        }\n\n        fun setDestination(destination: LatLng): Builder {\n            this.destination = destination\n            return this\n        }\n\n        fun setDebuggable():Builder{\n            Logger.isDebuggable = true\n            return this\n        }\n\n        fun setDirectionKey(key: String): Builder {\n            this.key = key\n            return this\n        }\n\n        fun setGoogleMap(map: GoogleMap): Builder {\n            this.mMap = map\n            return this\n        }\n\n        fun setPolyLineWidth(polyLineWidth: Int): Builder {\n            this.polyLineWidth = polyLineWidth\n            return this\n        }\n\n        fun setPolyLinePrimaryColor(@ColorRes color: Int): Builder {\n            this.polyLinePrimaryColor = color\n            return this\n        }\n\n        fun setPolyLineSecondaryColor(@ColorRes color: Int): Builder {\n            this.polyLineSecondaryColor = color\n            return this\n        }\n\n        fun setPathAnimation(boolean:Boolean) = apply { this.pathAnimation = boolean }\n\n        fun setCompletionTime(@IntegerRes time: Int) = apply { this.pathCompletionTime = time }\n\n        fun setColorFillCompletion(@IntegerRes time: Int) = apply { this.pathColorFillAnimationTime = time }\n\n        fun setPrimaryLineCompletion(@IntegerRes time: Int) = apply { this.primaryLineCompletionTime = time }\n\n        fun setDelayTime(@IntegerRes time: Int) = apply { this.animationDelay = time }\n\n        fun build(): DirectionUtil {\n            return DirectionUtil(this)\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/draw_path/MapAnimator.kt",
    "content": "package com.example.easywaylocation.draw_path\n\nimport android.animation.*\nimport android.view.animation.AccelerateDecelerateInterpolator\nimport android.view.animation.AccelerateInterpolator\nimport android.view.animation.DecelerateInterpolator\nimport androidx.annotation.IntegerRes\nimport com.google.android.gms.maps.GoogleMap\nimport com.google.android.gms.maps.model.LatLng\nimport com.google.android.gms.maps.model.Polyline\nimport com.google.android.gms.maps.model.PolylineOptions\nimport java.lang.Exception\n\n\ninternal class MapAnimator {\n\n    private var backgroundPolyline: Polyline? = null\n\n    private var foregroundPolyline: Polyline? = null\n\n    private var optionsForeground: PolylineOptions? = null\n\n    private var firstRunAnimSet: AnimatorSet? = null\n\n    private var secondLoopRunAnimSet: AnimatorSet? = null\n\n    private var backgroundColor: Int? = null\n    private var foregroundColor: Int? = null\n    private var PERCENT_COMPLETION = 2500\n    private var COLOR_FILL_ANIMATION = 1800\n    private var FOREGROUND_TIME = 2000\n    private var DELAY_TIME = 200\n    private lateinit var polylineBean: PolylineBean\n\n\n    private var polyLineDetails: HashMap<String, PolyLineDataBean> = HashMap()\n\n\n    fun setCompletionTime(@IntegerRes time: Int) {\n        PERCENT_COMPLETION = time\n    }\n\n    fun setColorFillCompletion(@IntegerRes time: Int) {\n        COLOR_FILL_ANIMATION = time\n    }\n\n    fun setPrimaryLineCompletion(@IntegerRes time: Int) {\n        FOREGROUND_TIME = time\n    }\n\n    fun setDelayTime(@IntegerRes time: Int) {\n        DELAY_TIME = time\n    }\n\n\n    fun setPrimaryLineColor(color: Int) {\n        foregroundColor = color\n    }\n\n    fun setSecondaryLineColor(color: Int) {\n        backgroundColor = color\n    }\n\n    fun animateRoute(googleMap: GoogleMap, routes: List<LatLng>, polyLineDataBean: PolyLineDataBean) {\n        if (firstRunAnimSet == null) {\n            firstRunAnimSet = AnimatorSet()\n        } else {\n            firstRunAnimSet!!.removeAllListeners()\n            firstRunAnimSet!!.end()\n            firstRunAnimSet!!.cancel()\n\n            firstRunAnimSet = AnimatorSet()\n        }\n        if (secondLoopRunAnimSet == null) {\n            secondLoopRunAnimSet = AnimatorSet()\n        } else {\n            secondLoopRunAnimSet!!.removeAllListeners()\n            secondLoopRunAnimSet!!.end()\n            secondLoopRunAnimSet!!.cancel()\n\n            secondLoopRunAnimSet = AnimatorSet()\n        }\n        //Reset the polylines\n        if (foregroundPolyline != null) foregroundPolyline!!.remove()\n        if (backgroundPolyline != null) backgroundPolyline!!.remove()\n\n\n        val optionsBackground = PolylineOptions().add(routes[0]).color(backgroundColor!!).width(8f)\n        backgroundPolyline = googleMap.addPolyline(optionsBackground)\n\n\n        optionsForeground = PolylineOptions().add(routes[0]).color(foregroundColor!!).width(8f)\n        foregroundPolyline = googleMap.addPolyline(optionsForeground)\n//        foregroundPolyline?.tag = getTag()\n//        polyLineDetails[foregroundPolyline?.tag as String] = polyLineDataBean\n\n\n        val percentageCompletion = ValueAnimator.ofInt(0, 100)\n        percentageCompletion.duration = PERCENT_COMPLETION.toLong()\n        percentageCompletion.interpolator = DecelerateInterpolator()\n        percentageCompletion.addUpdateListener { animation ->\n            val foregroundPoints = backgroundPolyline!!.points\n\n            val percentageValue = animation.animatedValue as Int\n            val pointcount = foregroundPoints.size\n            val countTobeRemoved = (pointcount * (percentageValue / 100.0f)).toInt()\n            val subListTobeRemoved = foregroundPoints.subList(0, countTobeRemoved)\n            subListTobeRemoved.clear()\n\n            foregroundPolyline!!.points = foregroundPoints\n        }\n        percentageCompletion.addListener(object : Animator.AnimatorListener {\n            override fun onAnimationStart(animation: Animator) {\n\n            }\n\n            override fun onAnimationEnd(animation: Animator) {\n                foregroundPolyline!!.color = backgroundColor!!\n                foregroundPolyline!!.points = backgroundPolyline!!.points\n            }\n\n            override fun onAnimationCancel(animation: Animator) {\n\n            }\n\n            override fun onAnimationRepeat(animation: Animator) {\n\n            }\n        })\n\n\n        val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), backgroundColor, foregroundColor)\n        colorAnimation.interpolator = AccelerateInterpolator()\n        colorAnimation.duration = COLOR_FILL_ANIMATION.toLong() // milliseconds\n\n        colorAnimation.addUpdateListener { animator -> foregroundPolyline!!.color = animator.animatedValue as Int }\n\n        val foregroundRouteAnimator = ObjectAnimator.ofObject(this, \"routeIncreaseForward\", RouteEvaluator(), *routes.toTypedArray())\n        foregroundRouteAnimator.interpolator = AccelerateDecelerateInterpolator()\n        foregroundRouteAnimator.addListener(object : Animator.AnimatorListener {\n            override fun onAnimationStart(animation: Animator) {\n\n            }\n\n            override fun onAnimationEnd(animation: Animator) {\n                backgroundPolyline!!.points = foregroundPolyline!!.points\n            }\n\n            override fun onAnimationCancel(animation: Animator) {\n\n            }\n\n            override fun onAnimationRepeat(animation: Animator) {\n\n            }\n        })\n        foregroundRouteAnimator.duration = FOREGROUND_TIME.toLong()\n        //        foregroundRouteAnimator.start();\n\n        firstRunAnimSet!!.playSequentially(foregroundRouteAnimator,\n                percentageCompletion)\n        firstRunAnimSet!!.addListener(object : Animator.AnimatorListener {\n            override fun onAnimationStart(animation: Animator) {\n\n            }\n\n            override fun onAnimationEnd(animation: Animator) {\n                secondLoopRunAnimSet!!.start()\n            }\n\n            override fun onAnimationCancel(animation: Animator) {\n\n            }\n\n            override fun onAnimationRepeat(animation: Animator) {\n\n            }\n        })\n\n        secondLoopRunAnimSet!!.playSequentially(colorAnimation,\n                percentageCompletion)\n        secondLoopRunAnimSet!!.startDelay = DELAY_TIME.toLong()\n\n        secondLoopRunAnimSet!!.addListener(object : Animator.AnimatorListener {\n            override fun onAnimationStart(animation: Animator) {\n\n            }\n\n            override fun onAnimationEnd(animation: Animator) {\n                secondLoopRunAnimSet!!.start()\n            }\n\n            override fun onAnimationCancel(animation: Animator) {\n\n            }\n\n            override fun onAnimationRepeat(animation: Animator) {\n\n            }\n        })\n\n        firstRunAnimSet!!.start()\n        addPolyineToBean(foregroundPolyline,backgroundPolyline);\n    }\n\n    private fun addPolyineToBean(foregroundPolyline: Polyline?, backgroundPolyline: Polyline?) {\n        polylineBean = PolylineBean(foregroundPolyline,backgroundPolyline)\n    }\n\n    fun getPolyline():ArrayList<PolylineBean>{\n        val data = ArrayList<PolylineBean>()\n        data.add(polylineBean)\n        return data\n    }\n\n    /**\n     * This will be invoked by the ObjectAnimator multiple times. Mostly every 16ms.\n     */\n    fun setRouteIncreaseForward(endLatLng: LatLng) {\n        val foregroundPoints = foregroundPolyline!!.points\n        foregroundPoints.add(endLatLng)\n        foregroundPolyline!!.points = foregroundPoints\n    }\n\n    fun getFor():Polyline{\n         foregroundPolyline?.let {\n             return it;\n         }?:run{\n             throw Exception(\"Please initiate polyline before calling this.\")\n         }\n    }\n\n    fun getBck():Polyline{\n        backgroundPolyline?.let {\n            return it;\n        }?:run{\n            throw Exception(\"Please initiate polyline before calling this.\")\n        }\n    }\n}\n\n"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/draw_path/PolyLineDataBean.kt",
    "content": "package com.example.easywaylocation.draw_path\n\nimport com.google.android.gms.maps.model.LatLng\nimport org.json.JSONObject\n\nclass PolyLineDataBean(){\n    var time:String = \"0.0\" // in second\n    var timeFromPrevPoint:String = \"0.0\" // in second\n    var distance:String = \"0.0\" // in meter\n    var distanceFromPrevPoint:String = \"0.0\" // in meter\n    var placeSummary:String = \"\"\n    var position:LatLng? = null\n\n    fun toJson(): JSONObject {\n        return JSONObject().put(\"placeSummary\",placeSummary)\n            .put(\"time\",time)\n            .put(\"distance\",distance)\n            .put(\"distanceFromPrevPoint\",distanceFromPrevPoint)\n            .put(\"timeFromPrevPoint\",timeFromPrevPoint)\n    }\n\n\n}"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/draw_path/PolylineBean.kt",
    "content": "package com.example.easywaylocation.draw_path\n\nimport com.google.android.gms.maps.model.Polyline\n\ndata class PolylineBean(val foreground:Polyline?,val backPolyline: Polyline?)"
  },
  {
    "path": "easywaylocation/src/main/java/com/example/easywaylocation/draw_path/RouteEvaluator.java",
    "content": "package com.example.easywaylocation.draw_path;\n\nimport android.animation.TypeEvaluator;\n\nimport com.google.android.gms.maps.model.LatLng;\n\n\npublic class RouteEvaluator implements TypeEvaluator<LatLng> {\n    @Override\n    public LatLng evaluate(float t, LatLng startPoint, LatLng endPoint) {\n        double lat = startPoint.latitude + t * (endPoint.latitude - startPoint.latitude);\n        double lng = startPoint.longitude + t * (endPoint.longitude - startPoint.longitude);\n        return new LatLng(lat,lng);\n    }\n}\n"
  },
  {
    "path": "easywaylocation/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">EasyWayLocation</string>\n    <string name=\"ok\">OK</string>\n\n    <string name=\"deviceLocationUtil_default_rationale_request_title\">Location Permission Required</string>\n    <string name=\"deviceLocationUtil_default_rationale_request_messageBody\">\n        This app requires location permissions in order to provide location-aware functionality.\n        If the permission is not granted any features that rely on such functionality may not work correctly.\n    </string>\n\n    <string name=\"deviceLocationUtil_request_returned_null\">Location request returned null</string>\n    <string name=\"deviceLocationUtil_requests_currently_active\">Device is already receiving location updates</string>\n\n    <string name=\"deviceLocationUtil_location_provided_by_lastLocation\">\n        Location provided by mLocationClient.getLastLocation()\n    </string>\n    <string name=\"deviceLocationUtil_location_provided_by_locationUpdates\">\n        Location provided by mLocationClient.requestLocationUpdates()\n    </string>\n    <string name=\"deviceLocationUtil_location_settings_satisfied\">\n        Location settings satisfied\n    </string>\n    <string name=\"deviceLocationUtil_location_settings_not_satisfied\">\n        Location settings not satisfied. Attempting to resolve…\n    </string>\n    <string name=\"deviceLocationUtil_location_updates_removed\">Location updates removed</string>\n    <string name=\"deviceLocationUtil_location_updates_resumed\">Location updates resumed</string>\n\n    <string name=\"deviceLocationUtil_geocoder_not_available\">Geocoder not available. Check network connection.</string>\n    <string name=\"deviceLocationUtil_geocoder_invalid_latLong\">Invalid latitude or longitude</string>\n    <string name=\"deviceLocationUtil_geocoder_address_not_found\">No address found for this location</string>\n    <string name=\"deviceLocationUtil_geocoder_invalid_element\">Invalid element code</string>\n\n</resources>\n"
  },
  {
    "path": "easywaylocation/src/test/java/com/example/easywaylocation/ExampleUnitTest.java",
    "content": "package com.example.easywaylocation;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Dec 08 01:01:22 IST 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-bin.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\nandroid.enableJetifier=true\nandroid.useAndroidX=true\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':easywaylocation'\n"
  }
]