[
  {
    "path": ".gitignore",
    "content": ".gradle\n.idea\nlocal.properties\n*.iml\n.DS_Store\nbuild"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "README.md",
    "content": "![mAppWidget](images/app_anim.gif)\n\nMap services are a major growth area for mobile applications. Services like Google maps have brought map technology to the masses in recent years, but it has been hard to integrate them into applications as Google maps and others require a constant Internet connection and use proprietary resources. This means that if the app has to work offline, use original graphics or other features, a custom map has to be built.\n\nAt Lemberg we’ve developed many Android apps with custom maps, and to streamline this process we came up with the mAppWidget code library.\n\n![ill](images/ill-3_1.jpg)\n\nDesigned to simplify custom map building, mAppWidget is a powerful tool that significantly cuts time and reduces the cost of the developing offline maps. Now any Android developer can benefit from our experience.\n\nUsing apps developed with mAppWidget is possible without data connection, unlike most of the other solutions. mAppWidget also uses a tiling technique for graphics that generates a larger map byre-using smaller images (tiles). This approach saves RAM and increases real-time performance, which is especially important on mobile devices. Zooming into images is not limited by the resolution of the input map image, as beyond the maximum zoom level of the image, the library uses digital zoom.\n\n## Features\n* Create map from any image\n* Tile engine rendering\n* GPS support\n* Zoom in/out\n* Pinch to zoom gesture\n* Zoom on double tap\n* Digital zoom\n* Pan\n* Inertial scroll\n* Smooth tiles appearing\n* Support of more than one map per application\n* Ability to move the map object after it was added to the map\n* Add/remove layers\n* Add/remove objects\n* Click handlers/info bubbles\n* Works offline\n* External storage support\n\n## Requirements\n* Android API 7 or higher\n* Android OS 2.1 or higher\n* Latest JDK, Android Studio 1.1 is recommended\n\n## Demo app\nmAppWidget demo is available for download on Google Play - \n[https://play.google.com/store/apps/details?id=com.ls.mappwidgetdemo](https://play.google.com/store/apps/details?id=com.ls.mappwidgetdemo)\n\n## How to use\nHere you can find information on how to use mAppWidget library and FAQ's - \n[http://lemberg.github.io/mappwidget/user_guide.html](http://lemberg.github.io/mappwidget/user_guide.html)\n\n## Proudly brought to you\nmAppWidget code library has been developed and open sourced by Lemberg Solutions Android development team. If you are interested in integration or customization of the mAppWidget or looking for any other mobile app development solution please feel free to reach us - [http://lemberg.co.uk](http://lemberg.co.uk).\n"
  },
  {
    "path": "mAppWidget/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:1.5.0'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n"
  },
  {
    "path": "mAppWidget/demo1app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "mAppWidget/demo1app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.2\"\n\n    defaultConfig {\n        applicationId \"com.ls.demo.demo1\"\n        minSdkVersion 7\n        targetSdkVersion 23\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.android.support:appcompat-v7:23.1.1'\n    compile project(':mappwidgetlib')\n}\n"
  },
  {
    "path": "mAppWidget/demo1app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/dmytrobaryskyy/Library/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\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"
  },
  {
    "path": "mAppWidget/demo1app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.ls.demo.demo1\">\n\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" >\n    </uses-permission>\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" >\n    </uses-permission>\n\n\n    <application android:allowBackup=\"true\" android:label=\"@string/app_name\"\n        android:icon=\"@drawable/ic_launcher\" android:theme=\"@style/AppTheme\">\n\n        <activity\n            android:name=\".HomeActivity\"\n            android:hardwareAccelerated=\"true\"\n            android:label=\"@string/app_name\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\".Sample1Activity\"\n            android:hardwareAccelerated=\"true\"\n            android:label=\"Sample1\">\n        </activity>\n\n        <activity\n            android:name=\".Sample2Activity\"\n            android:hardwareAccelerated=\"true\"\n            android:label=\"Sample2\">\n        </activity>\n\n        <activity\n            android:name=\".ExBrowseMapActivity\"\n            android:hardwareAccelerated=\"true\"\n            android:label=\"Sample2\">\n        </activity>\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/assets/grid/grid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><Image TileSize=\"256\" Overlap=\"1\" Format=\"png\"><Size Width=\"1600\" Height=\"1600\"/></Image>"
  },
  {
    "path": "mAppWidget/demo1app/src/main/assets/grid2/grid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><Image TileSize=\"128\" Overlap=\"1\" Format=\"png\"><Size Width=\"1600\" Height=\"1600\"/></Image>"
  },
  {
    "path": "mAppWidget/demo1app/src/main/assets/map/map.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Image TileSize=\"256\" Overlap=\"1\" Format=\"png\">\n\t<Size Width=\"1918\" Height=\"978\"/>\n\t<CalibrationRect>\n\t\t<Point x=\"257\" y=\"54\" lat=\"49.835401382423214\" lon=\"23.954856991767883\" topLeft=\"1\"/>\n\t\t<Point x=\"1736\" y=\"852\" lat=\"49.81328710324948\" lon=\"24.01834487915039\"/>\n\t</CalibrationRect>\n</Image>"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/BrowseMapActivity.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.Intent;\nimport android.content.res.AssetManager;\nimport android.graphics.Color;\nimport android.graphics.drawable.Drawable;\nimport android.location.Location;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.Window;\nimport android.view.WindowManager;\nimport android.widget.LinearLayout;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.config.OfflineMap;\nimport com.ls.widgets.map.events.MapTouchedEvent;\nimport com.ls.widgets.map.interfaces.Layer;\nimport com.ls.widgets.map.interfaces.MapEventsListener;\nimport com.ls.widgets.map.interfaces.OnLocationChangedListener;\nimport com.ls.widgets.map.interfaces.OnMapTouchListener;\nimport com.ls.widgets.map.model.MapLayer;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\npublic class BrowseMapActivity \n    extends Activity \n{\n    /** Called when the activity is first created. */\n\t\n\tprivate MapWidget mapWidget;\n//\tprivate static long PIN_ID = 0xdb70bca16186d187L;\n\t\n\tpublic static final long LAYER_ATTRACTIONS = 1000;\n    public static final long LAYER_KIDS = 2000;\n    public static final long LAYER_SPORT_AND_LEASURE = 3000;\n    public static final long PIN_LAYER = 4000;\n\t\n    private Model model;\n    \n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        requestWindowFeature(Window.FEATURE_NO_TITLE);\n        setContentView(R.layout.main);\n\n        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);\n\n        \n        this.model = new Model();\n        \n        LinearLayout layout = (LinearLayout) findViewById(R.id.mainLayout);\n        mapWidget = new MapWidget(this, OfflineMap.MAP_ROOT);\n//        mapWidget.setMemoryEconomyMode(true);\n        mapWidget.setBackgroundColor(Color.GREEN);\n\n        MapLayer layer = mapWidget.createLayer(LAYER_ATTRACTIONS);\n        initLayer(layer, Model.CAT_MAIN_ATTRACTIONS);\n        \n        layer = mapWidget.createLayer(LAYER_KIDS);\n        initLayer(layer, Model.CAT_KIDS);\n        \n        layer = mapWidget.createLayer(LAYER_SPORT_AND_LEASURE);\n        initLayer(layer, Model.CAT_SPORT_AND_LEISURE);\n        \n        mapWidget.getConfig().setMapCenteringEnabled(false); \n        \n        mapWidget.createLayer(PIN_LAYER);\n        \n//        layer.addTouchable(id, drawable, offsetX, offsetY)\n        \n//        mapWidget.addLayer(2);\n        mapWidget.setAnimationEnabled(true);\n        mapWidget.setOnMapTouchListener(new OnMapTouchListener() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onTouch(MapWidget v, MapTouchedEvent event){\n\t\t\t\tAlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());\n\t\t\t\tbuilder.setMessage(\"OnTouch, X: \" + event.getScreenX() + \" Y: \" + event.getScreenY() \n\t\t\t\t\t\t+ \" MAPX: \" + event.getMapX() + \" MAPY: \" + event.getMapY() +\n\t\t\t\t\t\t\" Touched Count: \" + event.getTouchedObjectIds().size());\n\t\t\t\tbuilder.create().show();\n\t\t\t}\n\t\t});\n        \n        \n        mapWidget.addMapEventsListener(new MapEventsListener() {\n\t\t\t\n\t\t\t\n\t\t\tpublic void onPreZoomOut() \n\t\t\t{\n\t\t\t\tLog.i(\"BrowseMapActivity\", \"On Map will zoom out\");\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\tpublic void onPreZoomIn() \n\t\t\t{\n\t\t\t\tLog.i(\"BrowseMapActivity\", \"On Map will zoom in\");\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\tpublic void onPostZoomOut() \n\t\t\t{\n\t\t\t\tLog.i(\"BrowseMapActivity\", \"On Map did zoom out\");\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\tpublic void onPostZoomIn() \n\t\t\t{\n\t\t\t\tLog.i(\"BrowseMapActivity\", \"On Map did zoom in\");\n\t\t\t\t\n\t\t\t} \n\n\t\t});\n\n        mapWidget.setOnLocationChangedListener(new OnLocationChangedListener()\n        {   \n           @Override\n           public void onLocationChanged(MapWidget v, Location location)\n           {\n               v.scrollMapTo(location);            \n           }\n       });\n        \n        mapWidget.setMinZoomLevel(1);\n //       mapWidget.setScale(2.0f);\n        \n        layout.addView(mapWidget);\n        \n//        Runnable runnable = new Runnable() {\n//        \t@Override\n//        \tpublic void run() {\n//                generateRandomMarkers();\n//                BitmapDrawable image = (BitmapDrawable) getResources().getDrawable(R.drawable.maps_blue_dot);\n//                if (image != null) {\n//                \tLayer layer = mapWidget.getLayerById(PIN_LAYER);\n//                \tMapObject object = new MapObject(PIN_ID, image, new Point(500, 250), PivotFactory.createPivotPoint(image, PivotPosition.PIVOT_CENTER), true);\n//                \tlayer.addMapObject(object);\n//\t              //  Pin pin = new Pin(PIN_ID, image, new android.graphics.Point(image.getBitmap().getWidth()/2, image.getBitmap().getHeight()/2));\n//\t              //  pin.moveTo(500, 250);\n//\t              //  mapWidget.getPinLayer().addPin(pin);\n//\t              //  mapWidget.setPinLayerVisible(true);\n//                }\n//        \t}\n//        };\n//        \n//        Thread thread = new Thread(runnable);\n//        thread.setPriority(Thread.MIN_PRIORITY);\n//        thread.start();\n    }\n\n\n//\tprivate void generateRandomMarkers() {\n//\t\ttry {\n//\t\t\tfinal int GREEN_POINT_COUNT = 100;\n//\t\t\tfinal int BLUE_POINT_COUNT = GREEN_POINT_COUNT;\n//\t\t\tfinal int MAP_WIDTH = 1500;\n//\t\t\tfinal int MAP_HEIGHT = 900;\n//\t\t\t\n//\t\t\tInputStream is = getAssets().open(\"other/trail_difficulty_green_circle.png\");\n//\t\t\tBitmapDrawable drawable = new BitmapDrawable(is);\n//\t\t\tis.close();\n//\t\t\tRandom random = new Random(System.currentTimeMillis());\n//\t\t\t\n//        \tfor (int i = 0; i < GREEN_POINT_COUNT; ++i) {\n//\t\t\t\tint randW = random.nextInt(MAP_WIDTH);\n//\t\t\t\tint randH = random.nextInt(MAP_HEIGHT);\n//\t\t\t\tBitmapDrawable dr = new BitmapDrawable(drawable.getBitmap());\n//\n//\t\t\t\tLayer layer = mapWidget.getLayer(0);\n//\t\t\t\tlayer.addMapObject(new MapObject(new Integer(random.nextInt(1000)), dr, randW, randH));\n//\t\t\t}\n//        \t\t\n//\t\t\t\n//\t\t\tis = getAssets().open(\"other/trail_difficulty_blue_rect.png\");\n//\t\t\tdrawable = new BitmapDrawable(is);\n//\t\t\tis.close();\n//        \tfor (int i = 0; i < BLUE_POINT_COUNT; ++i) {\n//\t\t\t\tint randW = random.nextInt(MAP_WIDTH);\n//\t\t\t\tint randH = random.nextInt(MAP_HEIGHT);\n//\t\t\t\t\n//\t\t\t\tBitmapDrawable dr = new BitmapDrawable(drawable.getBitmap());\t\n//\t\t\t\t\n//\t\t\t\tLayer layer = mapWidget.getLayer(1);\n//\t\t\t\tlayer.addMapObject(new MapObject(new Integer(random.nextInt(1000)), dr, randW, randH, true, false));\n//\t\t\t}\n//\t\t\t\n//\t\t} catch (IOException e) {\n//\t\t\tLog.e(\"TileManagerWorkerThread\", \"Exception: \" + e);\n//\t\t\te.printStackTrace();\n//\t\t}\n//\t}\n    \n    \n\t\n\tprivate void initLayer(Layer theLayer, String theCategoryId)\n\t{\n//\t    List<com.ls.widgets.map.location.l> listLocations = this.model.getLocations();\n//\t    \n//        for (Location location : listLocations)\n//        {\n//            try\n//            {\n//                String categoryId = location.getCategoryId();\n//\n//                if (categoryId.equals(theCategoryId))\n//                {\n//                    Point point = location.getPoint();\n//                    MapObject object = new MapObject(location.getId(), \n//                    \t\t\t\t\t\tgetIcon(categoryId),\n//                    \t\t\t\t\t\tpoint,\n//                    \t\t\t\t\t\ttrue,  // Touchable\n//                    \t\t\t\t\t\tfalse); // scalable\n//                   \n//                    theLayer.addMapObject(object);\n//                }\n//\n//            } catch (IOException e)\n//            {\n//                e.printStackTrace();\n//            }\n//        }\n        \n        theLayer.setVisible(true);\n//        if (settings.isCategorySelected(CategoryIds.LEISURE))\n//        {\n//            layerLeisure.enable();\n//        }\n\t}\n\t\n\t\n\t\n\tpublic Drawable getIcon(String theCatId) throws IOException\n    {\n\n        String path = \"media/icons/\";\n\n        if (Model.CAT_MAIN_ATTRACTIONS.equalsIgnoreCase(theCatId))\n        {\n            path += \"map_icon_leisure.png\";\n        } else if (Model.CAT_KIDS.equalsIgnoreCase(theCatId))\n        {\n            path += \"map_icon_meals.png\";\n        } else if (Model.CAT_SPORT_AND_LEISURE.equalsIgnoreCase(theCatId))\n        {\n            path += \"map_icon_others_3.png\";\n        } \n\n        AssetManager manager = getAssets();\n\n        InputStream input = manager.open(path);\n\n        return Drawable.createFromStream(input, null);\n    }\n\t\n\t\n    \n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = getMenuInflater();\n        inflater.inflate(R.menu.map_menu, menu);\n        return true;\n    }\n    \n    \n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        // Handle item selection\n\t\tint i = item.getItemId();\n\t\tif (i == R.id.zoom_in) {\n\t\t\ttry {\n\t\t\t\tmapWidget.zoomIn();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.e(\"BrowseMapActivity\", \"Exception while zoom in. \" + e);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.zoom_out) {\n\t\t\ttry {\n\t\t\t\tmapWidget.zoomOut();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.e(\"BrowseMapActivity\", \"Exception while zoom out. \" + e);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.double_size) {\n\t\t\tmapWidget.setScale(2.0f);\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.original_size) {\n\t\t\tmapWidget.setScale(1.0f);\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.half_size) {\n\t\t\tmapWidget.setScale(0.5f);\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.open_map) {\n\t\t\tIntent intent = new Intent(this, BrowseMapActivity.class);\n\t\t\tstartActivity(intent);\n\t\t\treturn true;\n\t\t}\n\t\telse {\n\t\t\treturn super.onOptionsItemSelected(item);\n\t\t}\n    }\n\n\n\t@Override\n\tpublic boolean onKeyDown(int keyCode, KeyEvent event) {\n\t\tLayer layer = null;\n\t\t\n\t\tswitch (keyCode) {\n\t\tcase KeyEvent.KEYCODE_1:\n\t\t\tlayer = mapWidget.getLayer(0);\n\t\t\tbreak;\n\t\tcase KeyEvent.KEYCODE_2:\n\t\t\tlayer = mapWidget.getLayer(1);\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tif (layer != null) {\n\t\t\tlayer.setVisible(!layer.isVisible());\n\t\t\t\n\t\t\treturn true;\n\t\t} else \n\t\t\treturn super.onKeyDown(keyCode, event);\n\t}\n\n\n\t@Override\n\tprotected void onStop() {\n\t\tsuper.onStop();\n\t}\n\n\t\n\t@Override\n\tprotected void onPause() {\n\t\tsuper.onPause();\n\t}\n\n\n\n\t@Override\n\tprotected void onDestroy() \n\t{\n\t//\tmapWidget.destroy();\n\t\tsuper.onDestroy();\n\t}\n};"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/CaptionMapObject.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Paint.Align;\nimport android.graphics.Point;\nimport android.graphics.Typeface;\nimport android.graphics.drawable.Drawable;\n\nimport com.ls.widgets.map.model.MapObject;\n\npublic class CaptionMapObject extends MapObject \n{\n\n\tprivate String caption;\n\tprivate Paint paint;\n\t\n\tpublic CaptionMapObject(Object id, Drawable drawable, Point position,\n\t\t\tPoint pivotPoint, boolean isTouchable, boolean isScalable) {\n\t\tsuper(id, drawable, position, pivotPoint, isTouchable, isScalable);\n\t\t\n\t\tpaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n\t\tpaint.setColor(Color.WHITE);\n\t\tpaint.setTextAlign(Align.CENTER);\n\t\tpaint.setTextSize(14);\n\t\tpaint.setTypeface(Typeface.SANS_SERIF);\n\t\tpaint.setFakeBoldText(true);\n\t\tpaint.setShadowLayer(1, 0, 0, Color.BLACK);\n\t}\n\n\t\n\tpublic void setCaption(String caption)\n\t{\n\t\tthis.caption = caption;\n\t}\n\t\n\t\n\t@Override\n\tpublic void draw(Canvas canvas) \n\t{\t\t\n\t\tsuper.draw(canvas);\n\t\t\n\t\tif (caption != null) {\n\t\t\tcanvas.drawText(caption, posScaled.x, posScaled.y - 10, paint);\n\t\t}\n\t}\n\t\n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/Category.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1;\n\npublic class Category\n{\n\n    private String id;\n    \n    private String name;\n\n    \n    \n    public String getId()\n    {\n        return id;\n    }\n\n    public void setId(String id)\n    {\n        this.id = id;\n    }\n\n    public String getName()\n    {\n        return name;\n    }\n\n    public void setName(String name)\n    {\n        this.name = name;\n    }\n    \n    \n    \n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/ExBrowseMapActivity.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.graphics.Point;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.location.Location;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.Window;\nimport android.view.WindowManager;\nimport android.widget.LinearLayout;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.config.MapGraphicsConfig;\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.events.MapScrolledEvent;\nimport com.ls.widgets.map.events.MapTouchedEvent;\nimport com.ls.widgets.map.interfaces.Layer;\nimport com.ls.widgets.map.interfaces.MapEventsListener;\nimport com.ls.widgets.map.interfaces.OnLocationChangedListener;\nimport com.ls.widgets.map.interfaces.OnMapScrollListener;\nimport com.ls.widgets.map.interfaces.OnMapTouchListener;\nimport com.ls.widgets.map.model.MapObject;\nimport com.ls.widgets.map.utils.PivotFactory;\nimport com.ls.widgets.map.utils.PivotFactory.PivotPosition;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Random;\n\npublic class ExBrowseMapActivity \n    extends Activity \n{\n    /** Called when the activity is first created. */\n\t\n\tprivate MapWidget mapWidget;\n\tprivate Thread animationThread;\n\tprivate boolean stopThreads;\n\t\n\t\n\tpublic static final long LAYER_A = 1000;\n\tpublic static final long LAYER_B = 2000;\n\tpublic static final long LAYER_C = 3000;\n\tpublic static final long PIN_LAYER = 4000;\n\t\n\tprivate int amplitude = 400;\n\tprivate float currX = 0;\n\tprivate float currY = 0;\n\t\n\tprivate boolean followPointer;\n\t\n\tpublic static final long[] LAYERS = new long[]{};\n\t\n\t\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        stopThreads = false;\n        followPointer = true;\n        \n        File dir = Environment.getExternalStorageDirectory();\n        Log.d(\"ExBrowseActivity\", \"External Storage Directory: \" + Environment.getDataDirectory().getAbsolutePath() + \"/maps/grid2\");\n        \n        requestWindowFeature(Window.FEATURE_NO_TITLE);\n        setContentView(R.layout.main);\n\n\n        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);\n        Log.d(\"ExBrowseActivity\", \"Window format is: \" + getWindow().getAttributes().format);\n        \n        LinearLayout layout = (LinearLayout) findViewById(R.id.mainLayout);\n        layout.setBackgroundColor(0xFFFFFFFF);\n        mapWidget = new MapWidget(savedInstanceState, this, new File(\"/sdcard/maps/grid2\"),12);\n\n        mapWidget.createLayer(0);\n        mapWidget.createLayer(1);\n        mapWidget.setAnimationEnabled(true);\n        mapWidget.setZoomButtonsVisible(true);\n        \n        MapGraphicsConfig gconfig = mapWidget.getMapGraphicsConfig();\n        if (gconfig != null) {\n            gconfig.setAccuracyAreaBorderColor(Color.RED);\n            gconfig.setAccuracyAreaColor(0x4400FF00);\n        }\n        \n        mapWidget.setOnMapTouchListener(new OnMapTouchListener() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onTouch(MapWidget v, MapTouchedEvent event) {\n\t\t\t\tAlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());\n\t\t\t\tbuilder.setMessage(\"OnTouch, X: \" + event.getScreenX() + \" Y: \" + event.getScreenY() \n\t\t\t\t\t\t+ \" MAPX: \" + event.getMapX() + \" MAPY: \" + event.getMapY() +\n\t\t\t\t\t\t\" Touched Count: \" + event.getTouchedObjectIds().size());\n\t\t\t\tbuilder.create().show();\n\t\t\t}\n\t\t});\n        \n        \n        mapWidget.setOnMapScrolledListener(new OnMapScrollListener()\n        { \n            @Override\n            public void onScrolledEvent(MapWidget v, MapScrolledEvent event)\n            {           \n                if (event.isByUser()) {\n                    followPointer = false;\n                }      \n            }\n        });\n        \n        \n        mapWidget.setMinZoomLevel(1);\n        mapWidget.setMaxZoomLevel(12);\n       // mapWidget.setZoomButtonsVisible(true);\n //       mapWidget.setScale(2.0f);\n        layout.addView(mapWidget);\n        \n     mapWidget.addMapEventsListener(new MapEventsListener() {\n            \n            \n            public void onPreZoomOut() \n            {\n                Log.i(\"BrowseMapActivity\", \"On Map will zoom out\");\n            }\n            \n            \n            public void onPreZoomIn() \n            {\n                Log.i(\"BrowseMapActivity\", \"On Map will zoom in\");\n                \n            }\n            \n            \n            public void onPostZoomOut() \n            {\n                Log.i(\"BrowseMapActivity\", \"On Map did zoom out\");\n                \n            }\n            \n            \n            public void onPostZoomIn() \n            {\n                Log.i(\"BrowseMapActivity\", \"On Map did zoom in\");\n                \n            }\n\n        });\n     \n     mapWidget.setOnLocationChangedListener(new OnLocationChangedListener()\n     {   \n        @Override\n        public void onLocationChanged(MapWidget v, Location location)\n        {\n            if (followPointer) {\n                v.scrollMapTo(location);\n            }\n        }\n    });\n        \n        Runnable runnable = new Runnable() {\n        \t@Override\n        \tpublic void run() {\n                generateRandomMarkers();\n//                BitmapDrawable image = (BitmapDrawable) getResources().getDrawable(R.drawable.maps_blue_dot);\n//                if (image != null) {\n//                \tLayer layer = mapWidget.getLayerById(PIN_LAYER);\n//                \tMapObject object = new MapObject(PIN_ID, image, new Point(500, 250), PivotFactory.createPivotPoint(image, PivotPosition.PIVOT_CENTER), false, true);\n//    \t\t\t\tlayer.addMapObject(object);\n//                 \tlayer.setVisible(true);\n//                }\n        \t}\n        };\n        \n        Thread thread = new Thread(runnable);\n        thread.setPriority(Thread.MIN_PRIORITY);\n        thread.run();\n        \n        OfflineMapConfig config = mapWidget.getConfig();\n        if (config != null) {\n            config.setFlingEnabled(true);\n            config.setMapCenteringEnabled(false);\n        }\n        \n        //layout.removeView(mapWidget);\n       \n        \n        //mapWidget.setShowMyPosition(true);\n        mapWidget.centerMap();\n    }\n\n\n\tprivate void generateRandomMarkers() {\n\t\ttry {\n\t\t\tfinal int GREEN_POINT_COUNT = 100;\n\t\t\tfinal int BLUE_POINT_COUNT = GREEN_POINT_COUNT;\n\t\t\tfinal int MAP_WIDTH = 1500;\n\t\t\tfinal int MAP_HEIGHT = 900;\n\t\t\t\n\t\t\tInputStream is = getAssets().open(\"other/trail_difficulty_green_circle.png\");\n\t\t\tBitmapDrawable drawable = new BitmapDrawable(is);\n\t\t\tis.close();\n\t\t\tRandom random = new Random(System.currentTimeMillis());\n\t\t\t\n\t\t\tLayer layer = mapWidget.getLayer(0);\n\t\t\t\n        \tfor (int i = 0; i < GREEN_POINT_COUNT; ++i) {\n\t\t\t\tint randW = random.nextInt(MAP_WIDTH);\n\t\t\t\tint randH = random.nextInt(MAP_HEIGHT);\n\t\t\t\tBitmapDrawable dr = new BitmapDrawable(drawable.getBitmap());\n\n\t\t\t\tMapObject object = new MapObject(Integer.valueOf(random.nextInt(1000)), dr, randW, randH, false);\n\t\t\t\tlayer.addMapObject(object);\n\t\t\t\t//layer.addTouchable(new Integer(random.nextInt(1000)), dr, randW, randH);\n\t\t\t}\n        \t\t\n\t\t\t\n\t\t\tis = getAssets().open(\"other/trail_difficulty_blue_rect.png\");\n\t\t\tdrawable = new BitmapDrawable(is);\n\t\t\tis.close();\n\t\t\t\n\t\t\t layer = mapWidget.getLayer(1);\n        \tfor (int i = 0; i < BLUE_POINT_COUNT; ++i) {\n\t\t\t\tint randW = random.nextInt(MAP_WIDTH);\n\t\t\t\tint randH = random.nextInt(MAP_HEIGHT);\n\t\t\t\t\n\t\t\t\tBitmapDrawable dr = new BitmapDrawable(drawable.getBitmap());\t\n\t\t\t\t\n\t\t\t\tMapObject object = new MapObject(Integer.valueOf((random.nextInt(1000))), dr, new Point(randW, randH), PivotFactory.createPivotPoint(dr, PivotPosition.PIVOT_CENTER), true, false);\n\t\t\t\tlayer.addMapObject(object);\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n//\t\t\t\tlayer.addTouchable(new Integer(random.nextInt(1000)), dr, new Point(randW, randH), PivotFactory.createPivotPoint(dr, PivotPosition.PIVOT_CENTER), false);\n\n//\t\t\t\tmapWidget.addDrawable(dr, randW, randH);\n\t\t\t}\n\t\t\t\n\t\t} catch (IOException e) {\n\t\t\tLog.e(\"TileManagerWorkerThread\", \"Exception: \" + e);\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n    \n \n    \n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = getMenuInflater();\n        inflater.inflate(R.menu.map_menu, menu);\n        return true;\n    }\n    \n    \n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        // Handle item selection\n\t\tint i = item.getItemId();\n\t\tif (i == R.id.zoom_in) {\n\t\t\ttry {\n\t\t\t\tmapWidget.zoomIn();\n\t\t\t\tmapWidget.scrollMapTo(1500, 700);\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.e(\"BrowseMapActivity\", \"Exception while zoom in. \" + e);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.zoom_out) {\n\t\t\ttry {\n\t\t\t\tmapWidget.zoomOut();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.e(\"BrowseMapActivity\", \"Exception while zoom out. \" + e);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.double_size) {\n\t\t\tmapWidget.setScale(2.0f);\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.original_size) {\n\t\t\tmapWidget.setScale(1.0f);\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.half_size) {\n\t\t\tmapWidget.setScale(0.5f);\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.open_map) {\n\t\t\tIntent intent = new Intent(this, ExBrowseMapActivity.class);\n\t\t\tstartActivity(intent);\n\t\t\treturn true;\n\t\t}\n\t\telse if (i == R.id.my_location) {\n\t\t\t//mapWidget.scrollToCurrentLocation();\n\t\t\t//followPointer = true;\n\t\t\tmapWidget.centerMap();\n\t\t\treturn true;\n\t\t}\n\t\telse {\n\t\t\treturn super.onOptionsItemSelected(item);\n\t\t}\n    }\n\n\n\tprivate void animatePin() {\n//\t\tif (animationThread == null || (animationThread != null && !animationThread.isAlive())) {\n//\t\t\tanimationThread = new Thread(new Runnable() {\n//\t\t\t\t@Override\n//\t\t\t\tpublic void run() {\n//\t\t\t\t//\tMapObject pin = mapWidget.getLayerById(PIN_LAYER).getMapObject(PIN_ID);\n//\t\t\t\t\t\n//\t\t\t\t\tif (pin == null) {\n//\t\t\t\t\t\tLog.e(\"PIN\", \"Pin not foind\");\n//\t\t\t\t\t}\n//\t\t\t\t\t\n//\t\t\t\t\twhile (!stopThreads) {\n//\t\t\t\t\t\tcurrX += 0.01;\n//\t\t\t\t\t\tcurrY += 0.01;\n//\t\t\t\t\t\t\n//\t\t\t\t\t\tif (pin != null) {\n//\t\t\t\t\t\t\tpin.moveTo((int)(700 + Math.sin(currX) * amplitude), (int)(350 + Math.cos(currY)*250));\n//\t\t\t\t\t\t}\n//\t\t\t\t\t\t\n//\t\t\t\t\t\ttry {\n//\t\t\t\t\t\t\tThread.sleep(50);\n//\t\t\t\t\t\t} catch (InterruptedException e) {\n//\t\t\t\t\t\t\te.printStackTrace();\n//\t\t\t\t\t\t\treturn;\n//\t\t\t\t\t\t}\n//\t\t\t\t\t}\n//\t\t\t\t\t\n//\t\t\t\t}\n//\t\t\t});\n//\t\t\t\n//\t\t\tanimationThread.start();\n//\t\t}\n\t}\n\n\n\t@Override\n\tpublic boolean onKeyDown(int keyCode, KeyEvent event) {\n\t\tLayer layer = null;\n\t\t\n\t\tswitch (keyCode) {\n\t\tcase KeyEvent.KEYCODE_1:\n\t\t\tlayer = mapWidget.getLayer(0);\n\t\t\tbreak;\n\t\tcase KeyEvent.KEYCODE_2:\n\t\t\tlayer = mapWidget.getLayer(1);\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tif (layer != null) {\n\t\t\tlayer.setVisible(!layer.isVisible());\n\t\t\treturn true;\n\t\t} else \n\t\t\treturn super.onKeyDown(keyCode, event);\n\t}\n\n\n\n\t@Override\n\tprotected void onStop() {\n\t\tstopThreads = true;\n\t\tsuper.onStop();\n\t}\n\n\t\n\t@Override\n\tprotected void onPause() {\n\t\tsuper.onPause();\n\t}\n\n\n\n\t@Override\n\tprotected void onDestroy() \n\t{\n\t\t//mapWidget.destroy();\n\t\tsuper.onDestroy();\n\t}\n\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState)\n    {\n        mapWidget.saveState(outState);     \n        super.onSaveInstanceState(outState);\n\n    }\n\t\n\t\n\t\n};"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/HomeActivity.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.Button;\n\npublic class HomeActivity \n    extends Activity\n{\n\n    \n    protected void onCreate(Bundle savedInstanceState)\n    {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.home);\n        \n        initWidgets();\n    }\n    \n    \n    private void initWidgets()\n    {\n        Button button1 = (Button) findViewById(R.id.button_sample_1);\n        button1.setOnClickListener(new View.OnClickListener()\n        {    \n            public void onClick(View arg0)\n            {\n                doOpenSample1();\n            }\n        });\n        \n        Button button2 = (Button) findViewById(R.id.button_sample_2);\n        button2.setOnClickListener(new View.OnClickListener()\n        {    \n            public void onClick(View arg0)\n            {\n                doOpenSample2();\n            }\n        });\n        \n        Button button3 = (Button) findViewById(R.id.button_sample_3);\n        button3.setOnClickListener(new View.OnClickListener()\n        {    \n        \tpublic void onClick(View arg0)\n            {\n        \t\tdoOpenExBrowseActivity();\n            }\n        });\n    }\n    \n    \n    private void doOpenExBrowseActivity()\n    {\n    \tIntent intent = new Intent(this, ExBrowseMapActivity.class);\n        startActivity(intent);\n    }\n    \n    private void doOpenSample1()\n    {\n        Intent intent = new Intent(this,Sample1Activity.class);\n        startActivity(intent);\n    }\n    \n    \n    private void doOpenSample2()\n    {\n        Intent intent = new Intent(this,Sample2Activity.class);\n        startActivity(intent);\n    }    \n    \n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/Location.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1;\n\nimport android.graphics.Point;\n\npublic class Location\n{\n\n    private String id;\n    \n    private String title;\n    \n    private String categoryId;\n    \n    private Point point;\n\n    \n    \n    public String getId()\n    {\n        return id;\n    }\n\n    public void setId(String id)\n    {\n        this.id = id;\n    }    \n    \n    public String getCategoryId()\n    {\n        return categoryId;\n    }\n\n    public void setCategoryId(String categoryId)\n    {\n        this.categoryId = categoryId;\n    }\n\n    public String getTitle()\n    {\n        return title;\n    }\n\n    public void setTitle(String title)\n    {\n        this.title = title;\n    }\n\n    public Point getPoint()\n    {\n        return point;\n    }\n\n    public void setPoint(Point point)\n    {\n        this.point = point;\n    }\n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/Model.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport android.graphics.Point;\n\npublic class Model\n{\n\n    public static final String CAT_MAIN_ATTRACTIONS = \"category.main.attractions\";\n    public static final String CAT_KIDS = \"category.kids\";\n    public static final String CAT_SPORT_AND_LEISURE = \"category.sport.and.leisure\";\n    \n    \n    private List<Location> locations;\n    \n    private List<Category> categories;\n    \n    \n    public Model()\n    {\n        createCategories();\n        createLocations();\n    }\n    \n    \n    public List<Category> getCategories()\n    {\n        return categories;\n    }\n    \n    \n    public List<Location> getLocations()\n    {\n        return locations;\n    }\n    \n    \n    \n    private void createCategories()\n    {\n        this.categories = new ArrayList<Category>();\n        \n        \n        Category category = new Category();\n        category.setId(CAT_MAIN_ATTRACTIONS);\n        category.setName(\"Main Attractions\");\n        \n        this.categories.add(category);\n        \n        category = new Category();\n        category.setId(CAT_KIDS);\n        category.setName(\"Kids In the Park\");\n        \n        this.categories.add(category);\n        \n        \n        category = new Category();\n        category.setId(CAT_SPORT_AND_LEISURE);\n        category.setName(\"Sport and Leisure\");\n        \n        this.categories.add(category);\n    }\n    \n    \n    private void createLocations()\n    {\n        this.locations = new ArrayList<Location>();\n        \n        Point point = new Point(20, 100);\n        \n        Location location = new Location();\n        location.setId(\"id.thehub\");\n        location.setTitle(\"The Hub\");\n        location.setCategoryId(CAT_MAIN_ATTRACTIONS);\n        location.setPoint(point);\n        \n        this.locations.add(location);\n        \n        point = new Point(20, 100);\n        location = new Location();\n        location.setId(\"id.queen.mary.garden\");\n        location.setTitle(\"Queen Mary's Garden\");\n        location.setCategoryId(CAT_MAIN_ATTRACTIONS);\n        location.setPoint(point);\n        \n        this.locations.add(location);\n        \n        point = new Point(20, 100);\n        location = new Location();\n        location.setId(\"id.wildlifegarden\");\n        location.setTitle(\"Wildlife Garden\");\n        location.setCategoryId(CAT_KIDS);\n        location.setPoint(point);\n        \n        this.locations.add(location);\n        \n        point = new Point(20, 100);\n        location = new Location();\n        location.setId(\"id.boatinglake\");\n        location.setTitle(\"Boating Lake\");\n        location.setCategoryId(CAT_KIDS);\n        location.setPoint(point);\n        \n        this.locations.add(location);\n        \n        point = new Point(20, 100);\n        location = new Location();\n        location.setId(\"id.openairtheatre\");\n        location.setTitle(\"Open Air Theatre\");\n        location.setCategoryId(CAT_SPORT_AND_LEISURE);\n        location.setPoint(point);\n        \n        this.locations.add(location);\n        \n        point = new Point(20, 100);\n        location = new Location();\n        location.setId(\"id.tenniscenter\");\n        location.setTitle(\"Tennis Center\");\n        location.setCategoryId(CAT_SPORT_AND_LEISURE);\n        location.setPoint(point);\n        \n        this.locations.add(location);\n    }\n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/Sample1Activity.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1;\n\nimport android.app.Activity;\nimport android.graphics.Color;\nimport android.graphics.Point;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.View.OnLongClickListener;\nimport android.view.View.OnTouchListener;\nimport android.widget.LinearLayout;\nimport android.widget.Toast;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.config.OfflineMap;\nimport com.ls.widgets.map.events.MapTouchedEvent;\nimport com.ls.widgets.map.interfaces.MapEventsListener;\nimport com.ls.widgets.map.interfaces.OnMapDoubleTapListener;\nimport com.ls.widgets.map.model.MapLayer;\nimport com.ls.widgets.map.model.MapObject;\nimport com.ls.widgets.map.utils.PivotFactory;\nimport com.ls.widgets.map.utils.PivotFactory.PivotPosition;\n\npublic class Sample1Activity \n    extends Activity\n{\n\n    \n    public static final int MAP_ID = 1; \n    private static final long LAYER_ID = 5;\n\n    \n    protected void onCreate(Bundle savedInstanceState)\n    {\n        super.onCreate(savedInstanceState);\n        \n        setContentView(R.layout.main);\n        \n        final int initialZoomLevel = 10;\n        \n        final MapWidget mapWidget = new MapWidget(savedInstanceState, this, OfflineMap.MAP_ROOT, initialZoomLevel);\n        mapWidget.setId(MAP_ID);\n        \n        LinearLayout layout = (LinearLayout) findViewById(R.id.mainLayout);\n        layout.addView(mapWidget);\n        \n        mapWidget.getConfig().setFlingEnabled(true);\n        mapWidget.getConfig().setPinchZoomEnabled(true);\n        \n        mapWidget.setMaxZoomLevel(13);\n        mapWidget.setUseSoftwareZoom(true);\n        mapWidget.setZoomButtonsVisible(true);\n        mapWidget.setBackgroundColor(Color.GREEN);\n        \n        mapWidget.setOnLongClickListener(new OnLongClickListener() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic boolean onLongClick(View v) {\n\t\t\t\tToast.makeText(Sample1Activity.this, \"Long press works!\", Toast.LENGTH_SHORT).show();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t});\n        \n        \n        mapWidget.setOnTouchListener(new OnTouchListener() {\n\n\t\t\t@Override\n\t\t\tpublic boolean onTouch(View arg0, MotionEvent arg1) {\n\t\t\t\treturn false;\n\t\t\t}\n        \t\n        });\n        \n        mapWidget.setOnDoubleTapListener(new OnMapDoubleTapListener() {\n\t\t\t@Override\n\t\t\tpublic boolean onDoubleTap(MapWidget v, MapTouchedEvent event) {\n\t\t\t\tLog.d(\"Sample1Activity\", \"On double tap\");\n\t\t\t\tToast.makeText(Sample1Activity.this, \"Double tap overridden\", Toast.LENGTH_SHORT).show();\n\t\t\t\treturn true;\n\t\t\t}\n        });\n\n        MapLayer layer = mapWidget.createLayer(LAYER_ID);        \n        \n        // getting icon from assets\n        Drawable icon = getResources().getDrawable(R.drawable.map_icon_attractions);\n        \n        // define coordinates of icon on map\n        int x = 240;\n        int y = 362;\n        \n        // set ID for the object\n        final long OBJ_ID = 25;\n        \n        // adding object to layer\n        layer.addMapObject(new MapObject(OBJ_ID, icon, new Point(x, y), PivotFactory.createPivotPoint(icon, PivotPosition.PIVOT_CENTER), false, false));\n\n        \n        \n        mapWidget.addMapEventsListener(new MapEventsListener() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onPreZoomOut() {\n\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onPreZoomIn() {\n\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onPostZoomOut() {\n\t\t\t\trunOnUiThread(new Runnable() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void run() {\n\t\t\t\t\t\tsetTitle(\"Zoom level: \" + mapWidget.getZoomLevel());\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onPostZoomIn() {\n\t\t\t\trunOnUiThread(new Runnable() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void run() {\n\t\t\t\t\t\tsetTitle(\"Zoom level: \" + mapWidget.getZoomLevel());\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\t\n\t\t\t}\n\t\t});\n\n    }\n\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState)\n    {\n        super.onSaveInstanceState(outState);\n        \n        MapWidget map = (MapWidget) findViewById(MAP_ID);\n        map.saveState(outState);\n    }\n\n\n    @Override\n    protected void onRestoreInstanceState(Bundle savedInstanceState)\n    {\n        // TODO Auto-generated method stub\n        super.onRestoreInstanceState(savedInstanceState);\n    }\n\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu)\n    {\n        MenuInflater inflater = new MenuInflater(this);\n        inflater.inflate(R.menu.a1menu, menu);\n        \n        return true;\n    }\n\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item)\n    {\n        MapWidget map = (MapWidget) findViewById(MAP_ID);\n\n\t\tint i = item.getItemId();\n\t\tif (i == R.id.scrollTo)\n\t\t{\n\t\t\tmap.scrollMapTo(new Point(240, 320));\n\t\t}\n\t\telse if (i == R.id.jumpTo)\n\t\t{\n\t\t\tmap.jumpTo(new Point(240, 320));\n\t\t}\n        return super.onOptionsItemSelected(item);\n    }\n\n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/Sample2Activity.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1;\n\nimport android.app.Activity;\nimport android.graphics.Point;\nimport android.graphics.drawable.Drawable;\nimport android.location.Location;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.View.OnLongClickListener;\nimport android.view.WindowManager;\nimport android.widget.LinearLayout;\nimport android.widget.Toast;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.events.MapTouchedEvent;\nimport com.ls.widgets.map.interfaces.Layer;\nimport com.ls.widgets.map.interfaces.MapEventsListener;\nimport com.ls.widgets.map.interfaces.OnLocationChangedListener;\nimport com.ls.widgets.map.interfaces.OnMapDoubleTapListener;\nimport com.ls.widgets.map.interfaces.OnMapLongClickListener;\nimport com.ls.widgets.map.interfaces.OnMapTilesFinishedLoadingListener;\nimport com.ls.widgets.map.model.MapLayer;\nimport com.ls.widgets.map.model.MapObject;\nimport com.ls.widgets.map.utils.GeoUtils;\nimport com.ls.widgets.map.utils.PivotFactory;\nimport com.ls.widgets.map.utils.PivotFactory.PivotPosition;\n\npublic class Sample2Activity \n    extends Activity\n{\n    public static final int MAP_ID = 1; \n    private int currId = 35;\n    \n    protected void onCreate(Bundle savedInstanceState)\n    {\n        super.onCreate(savedInstanceState);\n        \n        setContentView(R.layout.main);\n        \n        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);\n        \n        final MapWidget mapWidget = new MapWidget(savedInstanceState, this, \"map\", 10);\n        mapWidget.setSaveEnabled(true);\n        mapWidget.getConfig().setMinZoomLevelLimit(10);\n        mapWidget.getConfig().setZoomBtnsVisible(false);\n        mapWidget.setId(MAP_ID);\n        \n        // create map layer with specified ID\n        final long LAYER_ID = 5;\n        MapLayer layer = mapWidget.createLayer(LAYER_ID);        \n        \n        // getting icon from assets\n        Drawable icon = getResources().getDrawable(R.drawable.map_icon_attractions);\n        \n        // define coordinates of icon on map\n        int x = 200;\n        int y = 300;\n        \n        // set ID for the object\n        final long OBJ_ID = 25;\n        \n        // adding object to layer\n        MapObject obj = new MapObject(OBJ_ID, icon, new Point(x, y), PivotFactory.createPivotPoint(icon, PivotPosition.PIVOT_CENTER), true, false);\n       // obj.setCaption(\"5434 KNNB\");\n        \n        //MapObject(OBJ_ID, icon, new Point(x, y), PivotFactory.createPivotPoint(icon, PivotPosition.PIVOT_CENTER), true, false)\n        \n        layer.addMapObject(obj);\n          \n        LinearLayout layout = (LinearLayout) findViewById(R.id.mainLayout);\n        layout.setBackgroundColor(0xFFFFFFFF);\n        layout.addView(mapWidget);\n        \n        mapWidget.getMapGraphicsConfig().setArrowPointerDrawableId(R.drawable.maps_blue_arrow);\n        mapWidget.getMapGraphicsConfig().setDotPointerDrawableId(R.drawable.maps_blue_dot);\n        \n        mapWidget.setOnMapTilesFinishLoadingListener(new OnMapTilesFinishedLoadingListener() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onMapTilesFinishedLoading() {\n\t\t\t\tmapWidget.zoomIn();\n\t\t\t\tmapWidget.scrollMapTo(1000, 800);\n\t\t\t\tmapWidget.setOnMapTilesFinishLoadingListener(null);\n\t\t\t}\n\t\t});\n       // mapWidget.setShowMyPosition(true);\n        \n        \n        mapWidget.addMapEventsListener(new MapEventsListener()\n        {\n            \n            @Override\n            public void onPreZoomOut()\n            {\n                // TODO Auto-generated method stub\n                \n            }\n            \n        \n            @Override\n            public void onPreZoomIn()\n            {\n                // TODO Auto-generated method stub\n                \n            }\n            \n        \n            @Override\n            public void onPostZoomOut()\n            {\n                // TODO Auto-generated method stub\n                \n            }\n            \n        \n            @Override\n            public void onPostZoomIn()\n            {\n                // TODO Auto-generated method stub\n                \n            }\n        });\n        \n        \n        mapWidget.setOnLocationChangedListener(new OnLocationChangedListener() {\n            @Override\n            public void onLocationChanged(MapWidget v, Location location)\n            {\n                v.scrollMapTo(location);               \n            }\n        });\n        \n        \n        mapWidget.setOnDoubleTapListener(new OnMapDoubleTapListener() {\n\t\t\t@Override\n\t\t\tpublic boolean onDoubleTap(MapWidget v, MapTouchedEvent event) {\n\t\t\t\tLog.d(\"Sample1Activity\", \"On double tap\");\n\t\t\t\t\n\t\t\t\tLocation location = addObjetWhereTouched(mapWidget, event, R.drawable.map_icon_attractions);\n\t\t\t\tToast.makeText(Sample2Activity.this, \"New object coords: Lat: \" + location.getLatitude() + \" Lon:\" + location.getLongitude(), Toast.LENGTH_SHORT).show();\n\t\t\t\treturn true;\n\t\t\t}\n\n\n        });\n        \n        \n        mapWidget.setOnLongClickListener(new OnLongClickListener() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic boolean onLongClick(View arg0) {\n\t\t\t\t\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n        \n        \n        mapWidget.setOnMapLongClickListener(new OnMapLongClickListener() {\n\n\t\t\t@Override\n\t\t\tpublic boolean onLongClick(MapWidget v, MapTouchedEvent e) {\n\n\t\t\t\tif (e.getTouchedObjectIds().size() == 0) {\n\t\t\t\t\taddObjetWhereTouched(v, e, R.drawable.map_icon_leasure);\n\t\t\t\t} else {\n\t\t\t\t\tToast.makeText(Sample2Activity.this, \"Layer Id: \" + e.getTouchedObjectIds().get(0).getLayerId(), Toast.LENGTH_SHORT).show();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\treturn false;\n\t\t\t}\n        \t\n        });        \n    }\n\n    \n\tprivate Location addObjetWhereTouched(final MapWidget mapWidget, MapTouchedEvent event, int iconId) {\n\t\t// getting icon from assets\n        Drawable icon = getResources().getDrawable(iconId);\n        MapObject obj = new MapObject(currId++, icon, new Point(0, 0), \n        \t\tPivotFactory.createPivotPoint(icon, PivotPosition.PIVOT_CENTER), true, false);\n\n        Layer layer = mapWidget.getLayerById(5);   \n\t\tlayer.addMapObject(obj);\n\n\t\tLocation location = new Location(\"custom\");\n\t\tGeoUtils.translate(mapWidget, event.getMapX(), event.getMapY(), location);\n        \n\t\tobj.moveTo(location);\n\t\treturn location;\n\t}\n    \n    \n\t@Override\n\tprotected void onSaveInstanceState(Bundle outState) {\n\t\tMapWidget map = (MapWidget) findViewById(MAP_ID);\n\t\tmap.saveState(outState);\n\t\tsuper.onSaveInstanceState(outState);\n\t}\n    \n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/model/MapObjectContainer.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1.model;\n\nimport java.util.ArrayList;\n\npublic class MapObjectContainer \n{\n\tprivate ArrayList<MapObjectModel> container;\n\t\n\tpublic MapObjectContainer()\n\t{\n\t\tcontainer = new ArrayList<MapObjectModel>();\n\t}\n\n\t\n\tpublic void addObject(MapObjectModel object) \n\t{\n\t\tcontainer.add(object);\n\t}\n\t\n\t\n\tpublic void removeObject(MapObjectModel object)\n\t{\n\t\tcontainer.remove(object);\n\t}\n\t\n\t\n\tpublic MapObjectModel getObject(int index)\n\t{\n\t\treturn container.get(index);\n\t}\n\t\n\t\n\tpublic MapObjectModel getObjectById(int id)\n\t{\n\t\tfor (MapObjectModel model:container) {\n\t\t\tif (model.getId() == id) {\n\t\t\t\treturn model;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n\t\n\t\n\tpublic int size()\n\t{\n\t\treturn container.size();\n\t}\n\n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/model/MapObjectModel.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1.model;\n\nimport android.location.Location;\n\npublic class MapObjectModel \n{\n\tprivate int x;\n\tprivate int y;\n\tprivate int id;\n\tprivate String caption;\n\tprivate Location location;\n\t\n\tpublic MapObjectModel(int id, Location location, String caption)\n\t{\n\t\tthis.location = location;\n\t\tthis.caption = caption;\n\t\tthis.id = id;\n\t}\n\t\n\tpublic MapObjectModel(int id, int x, int y, String caption)\n\t{\n\t\tthis.id = id;\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.caption = caption;\n\t}\n\n\tpublic int getId() \n\t{\n\t\treturn id;\n\t}\n\n\t\n\tpublic int getX() \n\t{\n\t\treturn x;\n\t}\n\n\n\tpublic int getY() \n\t{\n\t\treturn y;\n\t}\n\t\n\t\n\tpublic Location getLocation()\n\t{\n\t\treturn location;\n\t}\n\t\n\t\n\tpublic String getCaption()\n\t{\n\t\treturn caption;\n\t}\n\n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/popup/MapPopupBase.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1.popup;\n\nimport android.content.Context;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.ViewGroup.LayoutParams;\nimport android.widget.LinearLayout;\n\npublic class MapPopupBase\n{\n\tprotected ViewGroup parentView;\n\t\n\tprotected LinearLayout container;\n\tprotected float dipScaleFactor;\n\tprotected int lastX;\n\tprotected int lastY;\n\tprotected int screenHeight;\n\tprotected int screenWidth;\n\t\n\n\tpublic MapPopupBase(Context context, ViewGroup parentView) \n\t{\n\t    screenHeight = context.getResources().getDisplayMetrics().heightPixels;\n\t    screenWidth = context.getResources().getDisplayMetrics().widthPixels;\n\t    \n\t\tthis.parentView = parentView;\n    \tdipScaleFactor = context.getResources().getDisplayMetrics().density;\n    \t\n\t\tcontainer = new LinearLayout(context);\n\t\tcontainer.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));\n\t\n\t\tlastX = lastY = -1;\n\t}\t\t\n\t\n\t\n\tpublic void show(ViewGroup view, int theX, int theY)\n\t{\n\t\thide();\n\n\t\tcontainer.measure(view.getWidth(), view.getHeight());\n\t\t\n\t\tint x = theX - (getWidth() / 2);\n\t\tint y = theY - getHeight();\n\t\t\n\t\tcontainer.setPadding(x, y, 0, 0);\n\n\t\tlastX = x;\n\t\tlastY = y;\n\t\t\n\t\tparentView.addView(container);\n\t\tcontainer.setVisibility(View.VISIBLE);\n\t}\n\n\t\n\tpublic int getHeight()\n\t{\n\t\treturn container.getMeasuredHeight();\n\t}\n\t\n\t\n\tpublic int getWidth()\n\t{\n\t\treturn container.getMeasuredWidth();\n\t}\n\t\n\t\n\tpublic boolean isVisible()\n\t{\n\t\treturn container.getVisibility() == View.VISIBLE;\n\t}\n\t\n\t\n\tpublic void hide()\n\t{\n\t\tcontainer.setPadding(0, 0, 0, 0);\n\t\tcontainer.setVisibility(View.INVISIBLE);\n\t\tparentView.removeView(container);\n\t}\n\t\n\t\n\tpublic void setOnClickListener(View.OnTouchListener listener)\n\t{\n\t    if(container != null){\n\t        container.setOnTouchListener(listener);\n\t    }\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/java/com/ls/demo/demo1/popup/TextPopup.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo1.popup;\n\nimport com.ls.demo.demo1.R;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\npublic class TextPopup\n    extends MapPopupBase\n{\n\tpublic final static int ZERO = 0;\n\tpublic final static int PADDING_BOTTOM = 11;\n\tpublic final static int PADDING_TOP = 5;\n\tpublic final static int PADDING_LEFT = 15;\n\tpublic final static int PADDING_RIGHT = 10;\n\tpublic final static float DEF_TEXT_SIZE = 16;\n\tpublic final static int IMAGE_SIZE = 30;\n\tpublic final static int MAX_EMS = 14;\t\n\t\n    private TextView text;\n\n    public TextPopup(Context context, ViewGroup parentView) \n    {\n        super(context, parentView);\n        \n        text = new TextView(context);\n        \n        text.setPadding((int)(PADDING_LEFT * dipScaleFactor),\n                        (int)(PADDING_TOP * dipScaleFactor),\n                        (int)(PADDING_RIGHT  * dipScaleFactor), \n                        (int)(PADDING_BOTTOM * dipScaleFactor));\n        \n        text.setBackgroundResource(R.drawable.map_description_background);\n        text.setTextSize(DEF_TEXT_SIZE);\n        text.setGravity(Gravity.LEFT|Gravity.CENTER_VERTICAL);\n        text.setMaxEms(MAX_EMS);\n        text.setTextColor(Color.WHITE);\n        \n        container.addView(text);\n    \n        text.setFocusable(true);\n        text.setClickable(true);\n    }       \n\n \n    public void moveBy(int dx, int dy)\n    {\n        if (lastX != -1 && lastY != -1){\n            int paddingBottom = 0;\n            int paddingRight = 0;\n            if(container.getPaddingTop() > (screenHeight - (text.getHeight() + 3))){\n                paddingBottom = (container.getPaddingBottom() - dy);\n            }\n            \n            if(container.getPaddingLeft() > (screenWidth - (text.getWidth() + 3))){\n                paddingRight = container.getPaddingRight() - dx;\n            }\n            \n            container.setPadding(container.getPaddingLeft() + dx,\n                                 container.getPaddingTop() + dy, \n                                 paddingRight, paddingBottom);\n        }\n    }\n \n    \n    public void setText(String theText)\n    {\n        text.setPadding((int)(PADDING_LEFT * dipScaleFactor),\n                (int)(PADDING_TOP * dipScaleFactor),\n                (int)(PADDING_RIGHT  * dipScaleFactor), \n                (int)(PADDING_BOTTOM * dipScaleFactor));\n        \n        text.setText(theText + \"   \");\n    }\n    \n    \n    public void setIcon(BitmapDrawable theDrawable)\n    {\n        if (theDrawable != null) {\n            theDrawable.setBounds(0,0, (int) (theDrawable.getBitmap().getWidth()),\n                                        (int)(theDrawable.getBitmap().getHeight()));\n        }\n        \n        text.setCompoundDrawables(null, null, theDrawable, null);\n    }\n    \n    \n    public void removeIcon()\n    {\n        text.setCompoundDrawables(null, null, null, null);\n    }\n    \n    \n    public void setOnClickListener(View.OnTouchListener listener)\n    {\n        if(text != null){\n            text.setOnTouchListener(listener);\n        }\n    }\n}\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/res/layout/home.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:layout_width=\"fill_parent\"\n  android:layout_height=\"fill_parent\" android:orientation=\"vertical\" android:layout_gravity=\"center_vertical|center_horizontal\" android:gravity=\"center_vertical|center_horizontal\">\n    <Button android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:id=\"@+id/button_sample_1\" android:text=\"Sample 1\"></Button>\n    <Button android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:id=\"@+id/button_sample_2\" android:text=\"Sample 2\"></Button>\n    <Button android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:id=\"@+id/button_sample_3\" android:text=\"Sample 3\"></Button>\n</LinearLayout>\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/res/layout/main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:baselineAligned=\"false\"\n    android:id=\"@+id/mainLayout\" android:keepScreenOn=\"true\">\n\n</LinearLayout>\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/res/menu/a1menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n    <item android:id=\"@+id/scrollTo\" android:title=\"Scroll To\"></item>\n    <item android:id=\"@+id/jumpTo\" android:title=\"Jump To\"></item>\n\n    \n\n</menu>"
  },
  {
    "path": "mAppWidget/demo1app/src/main/res/menu/map_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:id=\"@+id/zoom_in\"\n          android:title=\"Zoom In\" />\n    <item android:id=\"@+id/zoom_out\"\n          android:title=\"Zoom Out\" />\n<item android:title=\"Open Map\" android:id=\"@+id/open_map\"></item>\n<item android:id=\"@+id/double_size\" android:title=\"Double Size\" android:visible=\"true\" android:enabled=\"true\"></item>\n<item android:id=\"@+id/half_size\" android:title=\"Half Size\" android:visible=\"true\" android:enabled=\"true\"></item>\n<item android:id=\"@+id/original_size\" android:title=\"Original Size\" android:visible=\"true\" android:enabled=\"true\"></item>\n<item android:title=\"Go to my location\" android:id=\"@+id/my_location\"></item>\n</menu>"
  },
  {
    "path": "mAppWidget/demo1app/src/main/res/menu/menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu\n  xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:id=\"@+id/zoomIn\" android:title=\"Zoom In\"></item>\n    <item android:id=\"@+id/zoomOut\" android:title=\"Zoom Out\"></item>\n    <item android:id=\"@+id/hideLayer2\" android:title=\"Hide Layer 2\"></item>\n    <item android:id=\"@+id/showLayer2\" android:title=\"Show Layer 2\"></item>\n    <item android:title=\"Scroll to next object\" android:id=\"@+id/scroll_next\"></item>\n</menu>\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">mAppWidget</string>\n</resources>\n"
  },
  {
    "path": "mAppWidget/demo1app/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    </style>\n\n</resources>\n"
  },
  {
    "path": "mAppWidget/demo1app/src/main/res/values/theme.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\t<style name=\"Theme.NoBackground\" parent=\"android:Theme\">\n        <item name=\"android:windowBackground\">@null</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "mAppWidget/demo2app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "mAppWidget/demo2app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.2\"\n\n    defaultConfig {\n        applicationId \"com.ls.demo.demo2\"\n        minSdkVersion 7\n        targetSdkVersion 23\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.android.support:appcompat-v7:23.1.1'\n    compile project(':mappwidgetlib')\n}\n"
  },
  {
    "path": "mAppWidget/demo2app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/dmytrobaryskyy/Library/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\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"
  },
  {
    "path": "mAppWidget/demo2app/src/androidTest/java/com/ls/demo/demo2/ApplicationTest.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo2;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "mAppWidget/demo2app/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.ls.demo.demo2\" >\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\".BrowseMapActivity\"\n            android:label=\"@string/app_name\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/assets/map/map.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Image TileSize=\"256\" Overlap=\"1\" Format=\"png\" >\n\t<Size Width=\"1536\" Height=\"768\" />\n\t<CalibrationRect>\n\t\t<Point x=\"1006\" y=\"141\" lat=\"3.214993635535601\" lon=\"73.03810715675354\" topLeft=\"1\"/>\n\t\t<Point x=\"1240\" y=\"582\" lat=\"3.211265870063092\" lon=\"73.03981840610504\"/>\n\t</CalibrationRect>\n</Image>"
  },
  {
    "path": "mAppWidget/demo2app/src/main/java/com/ls/demo/demo2/BrowseMapActivity.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo2;\n\nimport java.util.ArrayList;\n\nimport android.app.Activity;\nimport android.graphics.Color;\nimport android.graphics.Point;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.location.Location;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.View.OnTouchListener;\nimport android.widget.RelativeLayout;\n\nimport com.ls.demo.demo2.model.MapObjectContainer;\nimport com.ls.demo.demo2.model.MapObjectModel;\nimport com.ls.demo.demo2.popup.TextPopup;\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.config.GPSConfig;\nimport com.ls.widgets.map.config.MapGraphicsConfig;\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.events.MapScrolledEvent;\nimport com.ls.widgets.map.events.MapTouchedEvent;\nimport com.ls.widgets.map.events.ObjectTouchEvent;\nimport com.ls.widgets.map.interfaces.Layer;\nimport com.ls.widgets.map.interfaces.MapEventsListener;\nimport com.ls.widgets.map.interfaces.OnLocationChangedListener;\nimport com.ls.widgets.map.interfaces.OnMapScrollListener;\nimport com.ls.widgets.map.interfaces.OnMapTouchListener;\nimport com.ls.widgets.map.location.PositionMarker;\nimport com.ls.widgets.map.model.MapObject;\nimport com.ls.widgets.map.utils.PivotFactory;\nimport com.ls.widgets.map.utils.PivotFactory.PivotPosition;\n\npublic class BrowseMapActivity extends Activity \nimplements MapEventsListener,\n\t\t   OnMapTouchListener\n{\n\tprivate static final String TAG = \"BrowseMapActivity\";\n\t\n\tprivate static final Integer LAYER1_ID = 0;\n\tprivate static final Integer LAYER2_ID = 1;\n\tprivate static final int MAP_ID = 23;\n\n\tprivate int nextObjectId;\n\tprivate int pinHeight;\n\t\n\tprivate MapObjectContainer model;\n\tprivate MapWidget map;\n\tprivate TextPopup mapObjectInfoPopup;\n\t\n\tprivate Location points[];\n\tprivate int currentPoint;\n\t\n    /** Called when the activity is first created. */\n    @Override\n    public void onCreate(Bundle savedInstanceState) \n    {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.main);\n        \n        nextObjectId = 0;\n        \n        model = new MapObjectContainer();\n        \n        initTestLocationPoints();\n        initMap(savedInstanceState);\n        initModel();\n        initMapObjects();\n        initMapListeners();\n        \n        // Will show the position of the user on a map.\n        // Do not forget to enable ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permission int the manifest.\n        \n       // Uncomment this if you are at Filitheyo island :) \n       // map.setShowMyPosition(true);\n        \n         map.centerMap();\n    }\n    \n    \n    @Override\n\tprotected void onSaveInstanceState(Bundle outState) {\n    \tsuper.onSaveInstanceState(outState);\n    \tmap.saveState(outState);\n\t}\n\n    private void initTestLocationPoints() \n\t{\n\t\tpoints = new Location[5];\n\t\tfor (int i=0; i<points.length; ++i) {\n\t\t\tpoints[i] = new Location(\"test\");\n\t\t}\n\t\t\n\t\tpoints[0].setLatitude(3.2127012756213316);\n\t\tpoints[0].setLongitude(73.03406774997711);\n\t\t\n\t\tpoints[1].setLatitude(3.2122245926560167);\n\t\tpoints[1].setLongitude(73.03744733333588);\n\t\t\n\t\tpoints[2].setLatitude(3.2112819380469135);\n\t\tpoints[2].setLongitude(73.03983449935913);\n\t\t\n\t\tpoints[3].setLatitude(3.2130494147249915);\n\t\tpoints[3].setLongitude(73.03946435451508);\n\t\t\n\t\tpoints[4].setLatitude(3.2148276002942713);\n\t\tpoints[4].setLongitude(73.03796768188477);\n\t\t\n\t\tcurrentPoint = 0;\n\t}\n\t\n\t\n\tprivate Location getNextLocationPoint()\n\t{\n\t\tif (currentPoint < points.length-1) {\n\t\t\tcurrentPoint += 1;\n\t\t} else {\n\t\t\tcurrentPoint = 0;\n\t\t}\n\t\t\n\t\treturn points[currentPoint];\n\t}\n\n\n\tprivate void initMap(Bundle savedInstanceState) \n\t{\n\t\t// In order to display the map on the screen you will need \n\t\t// to initialize widget and place it into layout.\n        map = new MapWidget(savedInstanceState, this, \n\t\t\t\t\t\t\t  \"map\", // root name of the map under assets folder.\n\t\t\t\t\t\t\t  10); // initial zoom level\n\n        map.setId(MAP_ID);\n \n        OfflineMapConfig config = map.getConfig();\n        config.setPinchZoomEnabled(true); // Sets pinch gesture to zoom\n        config.setFlingEnabled(true);    // Sets inertial scrolling of the map\n        config.setMaxZoomLevelLimit(20);\n        config.setZoomBtnsVisible(true); // Sets embedded zoom buttons visible\n        \n        // Configuration of GPS receiver\n        GPSConfig gpsConfig = config.getGpsConfig();\n        gpsConfig.setPassiveMode(false);\n        gpsConfig.setGPSUpdateInterval(500, 5);\n        \n        // Configuration of position marker\n        MapGraphicsConfig graphicsConfig = config.getGraphicsConfig();\n        graphicsConfig.setAccuracyAreaColor(0x550000FF); // Blue with transparency\n        graphicsConfig.setAccuracyAreaBorderColor(Color.BLUE); // Blue without transparency\n\n        RelativeLayout layout = (RelativeLayout) findViewById(R.id.rootLayout);\n        // Adding the map to the layout\n        layout.addView(map, 0);\n        layout.setBackgroundColor(Color.parseColor(\"#0049FF\"));\n        \n        // Adding layers in order to put there some map objects\n        map.createLayer(LAYER1_ID); // you will need layer id's in order to access particular layer\n        map.createLayer(LAYER2_ID);\n\t}\n\t\n\t\n\tprivate void initModel()\n\t{\n\t\t// Adding objects to the model\n\t\t// You may want to implement your own model \n\t\tMapObjectModel objectModel = new MapObjectModel(0, 100, 100, \"Shows above the image 1\");\n\t\tmodel.addObject(objectModel);\n\t\tobjectModel = new MapObjectModel(1, 600, 350, \"Shows above the image 2\");\n\t\tmodel.addObject(objectModel);\n\t\t\n\t\tint id = 2;\n\t\tfor (Location point:points) {\n\t\t\tobjectModel = new MapObjectModel(id, point, \"Point \" + id);\n\t\t\tmodel.addObject(objectModel);\n\t\t\tid += 1;\n\t\t}\n\t\t\n\t}\n\n\n\tprivate void initMapObjects() \n\t{\t\n\t\t\n\t\tmapObjectInfoPopup = new TextPopup(this, (RelativeLayout)findViewById(R.id.rootLayout));\n\t\t\n\t\tLayer layer1 = map.getLayerById(LAYER1_ID);\n\t\tLayer layer2 = map.getLayerById(LAYER2_ID);\n\t\t\n\t\tfor (int i=0; i<model.size(); ++i) {\n\t\t\taddNotScalableMapObject(model.getObject(i), layer1);\n\t\t}\n\t\t\n\t\t// Adding two map objects to the second layer\n\t\taddScalableMapObject(800, 300, layer2);\n\t\taddNotScalableMapObject(900, 350, layer2);\n\t}\n\n\t\n\tprivate void addNotScalableMapObject(int x, int y,  Layer layer) \n\t{\n\t\t// Getting the drawable of the map object\n\t\tDrawable drawable = getResources().getDrawable(R.drawable.map_object);\n\t\tpinHeight = drawable.getIntrinsicHeight();\n\t\t// Creating the map object\n\t\tMapObject object1 = new MapObject(Integer.valueOf(nextObjectId), // id, will be passed to the listener when user clicks on it \n\t\t\t\t\t\t\t\t\t\t  drawable,  \n\t\t\t\t\t\t\t\t\t\t  new Point(x, y), // coordinates in original map coordinate system.\n\t\t\t\t\t\t\t\t\t\t  // Pivot point of center of the drawable in the drawable's coordinate system.\n\t\t\t\t\t\t\t\t\t\t  PivotFactory.createPivotPoint(drawable, PivotPosition.PIVOT_CENTER),\n\t\t\t\t\t\t\t\t\t\t  true, // This object will be passed to the listener\n\t\t\t\t\t\t\t\t\t\t  false); // is not scalable. It will have the same size on each zoom level\n\n\t\t// Adding object to layer\n\t\tlayer.addMapObject(object1);\n\t\tnextObjectId += 1;\n\t}\n\t\n\t\n\tprivate void addNotScalableMapObject(MapObjectModel objectModel,  Layer layer) \n\t{\n\t\tif (objectModel.getLocation() != null) {\n\t\t\taddNotScalableMapObject(objectModel.getLocation(), layer);\n\t\t} else {\n\t\t\taddNotScalableMapObject(objectModel.getX(), objectModel.getY(),  layer);\n\t\t}\n\t}\n\n\t\n\tprivate void addNotScalableMapObject(Location location, Layer layer) {\n\t\tif (location == null)\n\t\t\treturn;\n\t\t\n\t\t// Getting the drawable of the map object\n\t\tDrawable drawable = getResources().getDrawable(R.drawable.map_object);\n\t\t// Creating the map object\n\t\tMapObject object1 = new MapObject(Integer.valueOf(nextObjectId), // id, will be passed to the listener when user clicks on it \n\t\t\t\t\t\t\t\t\t\t  drawable,  \n\t\t\t\t\t\t\t\t\t\t  new Point(0, 0), // coordinates in original map coordinate system.\n\t\t\t\t\t\t\t\t\t\t  // Pivot point of center of the drawable in the drawable's coordinate system.\n\t\t\t\t\t\t\t\t\t\t  PivotFactory.createPivotPoint(drawable, PivotPosition.PIVOT_CENTER),\n\t\t\t\t\t\t\t\t\t\t  true, // This object will be passed to the listener\n\t\t\t\t\t\t\t\t\t\t  true); // is not scalable. It will have the same size on each zoom level\n\t\tlayer.addMapObject(object1);\n\t\t\n\t\t// Will crash if you try to move before adding to the layer. \n\t\tobject1.moveTo(location);\n\t\tnextObjectId += 1;\n\t}\n\n\n\tprivate void addScalableMapObject(int x, int y, Layer layer) \n\t{\n\t\tDrawable drawable = getResources().getDrawable(R.drawable.map_object);\n\t\tMapObject object1 = new MapObject(Integer.valueOf(nextObjectId), \n\t\t\t\t\t\t\t\t\t\t  drawable, \n\t\t\t\t\t\t\t\t\t\t  x, \n\t\t\t\t\t\t\t\t\t\t  y, \n\t\t\t\t\t\t\t\t\t\t  true, \n\t\t\t\t\t\t\t\t\t\t  true);\n\n\t\tlayer.addMapObject(object1);\n\t\tnextObjectId += 1;\n\t}\n\t\n\n\tprivate void initMapListeners() \n\t{\n\t\t// In order to receive MapObject touch events we need to set listener\n\t\tmap.setOnMapTouchListener(this);\n\t\t\n\t\t// In order to receive pre and post zoom events we need to set MapEventsListener\n        map.addMapEventsListener(this); \n        \n        // In order to receive map scroll events we set OnMapScrollListener\n        map.setOnMapScrolledListener(new OnMapScrollListener()\n        {\n            public void onScrolledEvent(MapWidget v, MapScrolledEvent event)\n            {\n                handleOnMapScroll(v, event);\n            }\n        });\n        \n        \n        map.setOnLocationChangedListener(new OnLocationChangedListener() {\n\t\t\t@Override\n\t\t\tpublic void onLocationChanged(MapWidget v, Location location) {\n\t\t\t\t// You can handle location change here.\n\t\t\t\t// For example you can scroll to new location by using v.scrollMapTo(location)\n\t\t\t}\n\t\t});\n\t}\n\n\t\n\t@Override\n\tpublic boolean onCreateOptionsMenu(Menu menu) \n\t{\n\t\tMenuInflater inflater = new MenuInflater(this);\n\t\tinflater.inflate(R.menu.menu, menu);\n\t\treturn true;\n\t}\n\n\n\t@Override\n\tpublic boolean onOptionsItemSelected(MenuItem item) \n\t{\n\t\tswitch (item.getItemId()) {\n\t\tcase R.id.zoomIn:\n\t\t\tmap.zoomIn();\n\t\t\treturn true;\n\t\tcase R.id.zoomOut:\n\t\t\tmap.zoomOut();\n\t\t\treturn true;\n\t\tcase R.id.hideLayer2: {\n\t\t\tLayer layer = map.getLayerById(LAYER2_ID);\n\t\t\tif (layer != null) {\n\t\t\t\tlayer.setVisible(false);\n\t\t\t\tmap.invalidate(); // Need to repaint the layer. This is a bug and will be fixed in next version.\n\t\t\t}\n\t\t\treturn true;\n\t\t\t}\n\t\tcase R.id.showLayer2: {\n\t\t\tLayer layer = map.getLayerById(LAYER2_ID);\n\t\t\tif (layer != null) {\n\t\t\t\tlayer.setVisible(true);\n\t\t\t\tmap.invalidate(); // Need to repaint the layer. This is a bug and will be fixed in next version.\n\t\t\t}\n\t\t\treturn true;\n\t\t\t}\n\t\t\n\t\tcase R.id.scroll_next:\n\t\t\tmap.scrollMapTo(getNextLocationPoint());\n\t\t\tbreak;\n\t\t\t\n\t\t}\n\t\t\n\t\treturn super.onOptionsItemSelected(item);\n\t}\n\n\n\tprivate void handleOnMapScroll(MapWidget v, MapScrolledEvent event) \n\t{\t\n\t\t// When user scrolls the map we receive scroll events\n\t\t// This is useful when need to move some object together with the map\n\t\t\n\t\tint dx = event.getDX(); // Number of pixels that user has scrolled horizontally\n\t\tint dy = event.getDY(); // Number of pixels that user has scrolled vertically\n\t\t\n\t\tif (mapObjectInfoPopup.isVisible()) {\n\t\t\tmapObjectInfoPopup.moveBy(dx, dy);\n\t\t}\n\t}\n\t\n\t\n\t\n\t@Override\n\tpublic void onPostZoomIn() \n\t{\n\t\tLog.i(TAG, \"onPostZoomIn()\");\n\t}\n\n\t@Override\n\tpublic void onPostZoomOut() \n\t{\n\t\tLog.i(TAG, \"onPostZoomOut()\");\t\t\n\t}\n\n\t@Override\n\tpublic void onPreZoomIn() \n\t{\n\t\tLog.i(TAG, \"onPreZoomIn()\");\n\t\t\n\t\tif (mapObjectInfoPopup != null) {\n\t\t\tmapObjectInfoPopup.hide();\n\t\t}\t\n\t}\n\n\t@Override\n\tpublic void onPreZoomOut() \n\t{\n\t\tLog.i(TAG, \"onPreZoomOut()\");\t\t\n\t\t\n\t\tif (mapObjectInfoPopup != null) {\n\t\t\tmapObjectInfoPopup.hide();\n\t\t}\t\n\t}\n\n\n\t//* On map touch listener implemetnation *//\n\t@Override\n\tpublic void onTouch(MapWidget v, MapTouchedEvent event) \n\t{\n\t\t// Get touched object events from the MapTouchEvent\n\t\tArrayList<ObjectTouchEvent> touchedObjs = event.getTouchedObjectIds();\n\t\t\n\t\tif (touchedObjs.size() > 0) {\n\t\t\t\n\t\t\tint xInMapCoords = event.getMapX();\n\t\t\tint yInMapCoords = event.getMapY();\n\t\t\tint xInScreenCoords = event.getScreenX();\n\t\t\tint yInScreenCoords = event.getScreenY();\n\t\t\t\n\t\t\tObjectTouchEvent objectTouchEvent = event.getTouchedObjectIds().get(0);\n\t\t\t\n\t\t\t// Due to a bug this is not actually the layer id, but index of the layer in layers array.\n\t\t\t// Will be fixed in the next release.\n\t\t\tlong layerId = objectTouchEvent.getLayerId();\n\t\t\tInteger objectId = (Integer)objectTouchEvent.getObjectId();\n\t\t\t// User has touched one or more map object\n\t\t\t// We will take the first one to show in the toast message.\n\t\t\tString message = \"You touched the object with id: \" + objectId + \" on layer: \" + layerId + \n\t\t\t\" mapX: \" + xInMapCoords + \" mapY: \" + yInMapCoords + \" screenX: \" + xInScreenCoords + \" screenY: \" + \n\t\t\tyInScreenCoords;\n\t\t\t\n\t\t\tLog.d(TAG, message);\n\t\t\t\t\n\t\t\tMapObjectModel objectModel = model.getObjectById(objectId.intValue());\n\t\t\t\t\t\n\t\t\tif (objectModel != null) {\n\t\t\t\t// This is a case when we want to show popup info exactly above the pin image\n\t\t\t\t\n\t\t        float density = getResources().getDisplayMetrics().density;\n\t\t        int imgHeight = (int) (pinHeight / density / 2);\n\t\t\t\t\t\n\t\t        // Calculating position of popup on the screen\n\t        \tint x = xToScreenCoords(objectModel.getX());\n\t\t\t\tint y = yToScreenCoords(objectModel.getY()) - imgHeight;\n\t\t\t\t\n\t\t\t\t// Show it\n\t\t\t\tshowLocationsPopup(x, y, objectModel.getCaption());\n\t\t\t} else {\n\t\t\t\t// This is a case when we want to show popup where the user has touched.\n\t\t\t\tshowLocationsPopup(xInScreenCoords, yInScreenCoords, \"Shows where user touched\");\n\t\t\t}\n\t\t\t\n\t\t\t// Hint: If user touched more than one object you can show the dialog in which ask\n\t\t\t// the user to select concrete object\n\t\t} else {\n\t\t\tif (mapObjectInfoPopup != null) {\n\t\t\t\tmapObjectInfoPopup.hide();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n    private void showLocationsPopup(int x, int y, String text)\n    {\n        RelativeLayout mapLayout = (RelativeLayout) findViewById(R.id.rootLayout);\n\n        if (mapObjectInfoPopup != null)\n        {\n            mapObjectInfoPopup.hide();\n        }\n\n        ((TextPopup) mapObjectInfoPopup).setIcon((BitmapDrawable) getResources().getDrawable(R.drawable.map_popup_arrow));\n        ((TextPopup) mapObjectInfoPopup).setText(text);\n\n        mapObjectInfoPopup.setOnClickListener(new OnTouchListener()\n        {\n            public boolean onTouch(View v, MotionEvent event)\n            {\n                if (event.getAction() == MotionEvent.ACTION_UP)\n                {\n                    if (mapObjectInfoPopup != null)\n                    {\n                        mapObjectInfoPopup.hide();\n                    }\n                }\n\n                return false;\n            }\n        });\n\n        ((TextPopup) mapObjectInfoPopup).show(mapLayout, x, y);\n    }\n    \n    /***\n     * Transforms coordinate in map coordinate system to screen coordinate system\n     * @param mapCoord - X in map coordinate in pixels. \n     * @return X coordinate in screen coordinates. You can use this value to display any object on the screen.\n     */\n    private int xToScreenCoords(int mapCoord)\n    {\n    \treturn (int)(mapCoord *  map.getScale() - map.getScrollX());\n    }\n    \n    private int yToScreenCoords(int mapCoord)\n    {\n    \treturn (int)(mapCoord *  map.getScale() - map.getScrollY());\n    }\n    \n  \n}"
  },
  {
    "path": "mAppWidget/demo2app/src/main/java/com/ls/demo/demo2/model/MapObjectContainer.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo2.model;\n\nimport java.util.ArrayList;\n\npublic class MapObjectContainer \n{\n\tprivate ArrayList<MapObjectModel> container;\n\t\n\tpublic MapObjectContainer()\n\t{\n\t\tcontainer = new ArrayList<MapObjectModel>();\n\t}\n\n\t\n\tpublic void addObject(MapObjectModel object) \n\t{\n\t\tcontainer.add(object);\n\t}\n\t\n\t\n\tpublic void removeObject(MapObjectModel object)\n\t{\n\t\tcontainer.remove(object);\n\t}\n\t\n\t\n\tpublic MapObjectModel getObject(int index)\n\t{\n\t\treturn container.get(index);\n\t}\n\t\n\t\n\tpublic MapObjectModel getObjectById(int id)\n\t{\n\t\tfor (MapObjectModel model:container) {\n\t\t\tif (model.getId() == id) {\n\t\t\t\treturn model;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n\t\n\t\n\tpublic int size()\n\t{\n\t\treturn container.size();\n\t}\n\n}\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/java/com/ls/demo/demo2/model/MapObjectModel.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo2.model;\n\nimport android.location.Location;\n\npublic class MapObjectModel \n{\n\tprivate int x;\n\tprivate int y;\n\tprivate int id;\n\tprivate String caption;\n\tprivate Location location;\n\t\n\tpublic MapObjectModel(int id, Location location, String caption)\n\t{\n\t\tthis.location = location;\n\t\tthis.caption = caption;\n\t\tthis.id = id;\n\t}\n\t\n\tpublic MapObjectModel(int id, int x, int y, String caption)\n\t{\n\t\tthis.id = id;\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.caption = caption;\n\t}\n\n\tpublic int getId() \n\t{\n\t\treturn id;\n\t}\n\n\t\n\tpublic int getX() \n\t{\n\t\treturn x;\n\t}\n\n\n\tpublic int getY() \n\t{\n\t\treturn y;\n\t}\n\t\n\t\n\tpublic Location getLocation()\n\t{\n\t\treturn location;\n\t}\n\t\n\t\n\tpublic String getCaption()\n\t{\n\t\treturn caption;\n\t}\n\n}\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/java/com/ls/demo/demo2/popup/MapPopupBase.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo2.popup;\n\nimport android.content.Context;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.ViewGroup.LayoutParams;\nimport android.widget.LinearLayout;\n\npublic class MapPopupBase\n{\n\tprotected ViewGroup parentView;\n\t\n\tprotected LinearLayout container;\n\tprotected float dipScaleFactor;\n\tprotected int lastX;\n\tprotected int lastY;\n\tprotected int screenHeight;\n\tprotected int screenWidth;\n\t\n\n\tpublic MapPopupBase(Context context, ViewGroup parentView) \n\t{\n\t    screenHeight = context.getResources().getDisplayMetrics().heightPixels;\n\t    screenWidth = context.getResources().getDisplayMetrics().widthPixels;\n\t    \n\t\tthis.parentView = parentView;\n    \tdipScaleFactor = context.getResources().getDisplayMetrics().density;\n    \t\n\t\tcontainer = new LinearLayout(context);\n\t\tcontainer.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));\n\t\n\t\tlastX = lastY = -1;\n\t}\t\t\n\t\n\t\n\tpublic void show(ViewGroup view, int theX, int theY)\n\t{\n\t\thide();\n\n\t\tcontainer.measure(view.getWidth(), view.getHeight());\n\t\t\n\t\tint x = theX - (getWidth() / 2);\n\t\tint y = theY - getHeight();\n\t\t\n\t\tcontainer.setPadding(x, y, 0, 0);\n\n\t\tlastX = x;\n\t\tlastY = y;\n\t\t\n\t\tparentView.addView(container);\n\t\tcontainer.setVisibility(View.VISIBLE);\n\t}\n\n\t\n\tpublic int getHeight()\n\t{\n\t\treturn container.getMeasuredHeight();\n\t}\n\t\n\t\n\tpublic int getWidth()\n\t{\n\t\treturn container.getMeasuredWidth();\n\t}\n\t\n\t\n\tpublic boolean isVisible()\n\t{\n\t\treturn container.getVisibility() == View.VISIBLE;\n\t}\n\t\n\t\n\tpublic void hide()\n\t{\n\t\tcontainer.setPadding(0, 0, 0, 0);\n\t\tcontainer.setVisibility(View.INVISIBLE);\n\t\tparentView.removeView(container);\n\t}\n\t\n\t\n\tpublic void setOnClickListener(View.OnTouchListener listener)\n\t{\n\t    if(container != null){\n\t        container.setOnTouchListener(listener);\n\t    }\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/java/com/ls/demo/demo2/popup/TextPopup.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.demo.demo2.popup;\n\nimport com.ls.demo.demo2.R;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\npublic class TextPopup\n    extends MapPopupBase\n{\n\tpublic final static int ZERO = 0;\n\tpublic final static int PADDING_BOTTOM = 11;\n\tpublic final static int PADDING_TOP = 5;\n\tpublic final static int PADDING_LEFT = 15;\n\tpublic final static int PADDING_RIGHT = 10;\n\tpublic final static float DEF_TEXT_SIZE = 16;\n\tpublic final static int IMAGE_SIZE = 30;\n\tpublic final static int MAX_EMS = 14;\t\n\t\n    private TextView text;\n\n    public TextPopup(Context context, ViewGroup parentView) \n    {\n        super(context, parentView);\n        \n        text = new TextView(context);\n        \n        text.setPadding((int)(PADDING_LEFT * dipScaleFactor),\n                        (int)(PADDING_TOP * dipScaleFactor),\n                        (int)(PADDING_RIGHT  * dipScaleFactor), \n                        (int)(PADDING_BOTTOM * dipScaleFactor));\n        \n        text.setBackgroundResource(R.drawable.map_description_background);\n        text.setTextSize(DEF_TEXT_SIZE);\n        text.setGravity(Gravity.LEFT|Gravity.CENTER_VERTICAL);\n        text.setMaxEms(MAX_EMS);\n        text.setTextColor(Color.WHITE);\n        \n        container.addView(text);\n    \n        text.setFocusable(true);\n        text.setClickable(true);\n    }       \n\n \n    public void moveBy(int dx, int dy)\n    {\n        if (lastX != -1 && lastY != -1){\n            int paddingBottom = 0;\n            int paddingRight = 0;\n            if(container.getPaddingTop() > (screenHeight - (text.getHeight() + 3))){\n                paddingBottom = (container.getPaddingBottom() - dy);\n            }\n            \n            if(container.getPaddingLeft() > (screenWidth - (text.getWidth() + 3))){\n                paddingRight = container.getPaddingRight() - dx;\n            }\n            \n            container.setPadding(container.getPaddingLeft() + dx,\n                                 container.getPaddingTop() + dy, \n                                 paddingRight, paddingBottom);\n        }\n    }\n \n    \n    public void setText(String theText)\n    {\n        text.setPadding((int)(PADDING_LEFT * dipScaleFactor),\n                (int)(PADDING_TOP * dipScaleFactor),\n                (int)(PADDING_RIGHT  * dipScaleFactor), \n                (int)(PADDING_BOTTOM * dipScaleFactor));\n        \n        text.setText(theText + \"   \");\n    }\n    \n    \n    public void setIcon(BitmapDrawable theDrawable)\n    {\n        if (theDrawable != null) {\n            theDrawable.setBounds(0,0, (int) (theDrawable.getBitmap().getWidth()),\n                                        (int)(theDrawable.getBitmap().getHeight()));\n        }\n        \n        text.setCompoundDrawables(null, null, theDrawable, null);\n    }\n    \n    \n    public void removeIcon()\n    {\n        text.setCompoundDrawables(null, null, null, null);\n    }\n    \n    \n    public void setOnClickListener(View.OnTouchListener listener)\n    {\n        if(text != null){\n            text.setOnTouchListener(listener);\n        }\n    }\n}\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/res/layout/activity_main.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\" tools:context=\".MainActivity\">\n\n    <TextView android:text=\"@string/hello_world\" android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/res/layout/main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\" android:id=\"@+id/rootLayout\">\n</RelativeLayout>\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/res/menu/menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu\n  xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:id=\"@+id/zoomIn\" android:title=\"Zoom In\"></item>\n    <item android:id=\"@+id/zoomOut\" android:title=\"Zoom Out\"></item>\n    <item android:id=\"@+id/hideLayer2\" android:title=\"Hide Layer 2\"></item>\n    <item android:id=\"@+id/showLayer2\" android:title=\"Show Layer 2\"></item>\n    <item android:title=\"Scroll to next object\" android:id=\"@+id/scroll_next\"></item>\n</menu>\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/res/menu/menu_main.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\" tools:context=\".MainActivity\">\n    <item android:id=\"@+id/action_settings\" android:title=\"@string/action_settings\"\n        android:orderInCategory=\"100\" app:showAsAction=\"never\" />\n</menu>\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">Demo2</string>\n    <string name=\"hello_world\">Hello world!</string>\n    <string name=\"action_settings\">Settings</string>\n\n</resources>\n"
  },
  {
    "path": "mAppWidget/demo2app/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    </style>\n\n</resources>\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/res/values/theme.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\t<style name=\"Theme.NoBackground\" parent=\"android:Theme\">\n        <item name=\"android:windowBackground\">@null</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "mAppWidget/demo2app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "mAppWidget/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Apr 10 15:27:10 PDT 2013\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.2.1-all.zip\n"
  },
  {
    "path": "mAppWidget/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.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\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"
  },
  {
    "path": "mAppWidget/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# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\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\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\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\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": "mAppWidget/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windowz variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\ngoto execute\r\n\r\n:4NT_args\r\n@rem Get arguments from the 4NT Shell from JP Software\r\nset CMD_LINE_ARGS=%$\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.2\"\n\n    defaultConfig {\n        minSdkVersion 7\n        targetSdkVersion 23\n        versionCode 1\n        versionName \"1.4.2\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    task androidJavadocs(type: Javadoc) {\n        source = android.sourceSets.main.java.srcDirs\n        classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n    }\n\n    task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {\n        classifier = 'javadoc'\n        from androidJavadocs.destinationDir\n    }\n\n    task cleanJar(type: Delete) {\n        delete 'build/outputs/mAppWidget.jar'\n    }\n\n    task makeJar(type: Copy) {\n        from('build/intermediates/bundles/release/')\n        into('build/outputs/')\n        include('classes.jar')\n        rename ('classes.jar', 'mAppWidget.jar')\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.android.support:support-v4:23.1.1'\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/dmytrobaryskyy/Library/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\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"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/androidTest/assets/map/map.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Image TileSize=\"256\" Overlap=\"1\" Format=\"png\">\n\t<Size Width=\"1918\" Height=\"978\"/>\n\t<CalibrationRect>\n\t\t<Point x=\"257\" y=\"54\" lat=\"49.835401382423214\" lon=\"23.954856991767883\" topLeft=\"1\"/>\n\t\t<Point x=\"1736\" y=\"852\" lat=\"49.81328710324948\" lon=\"24.01834487915039\"/>\n\t</CalibrationRect>\n</Image>"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/androidTest/java/com/ls/widgets/map/AllTests.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map;\n\nimport junit.framework.Test;\nimport junit.framework.TestSuite;\n\npublic class AllTests extends TestSuite {\n\n\tpublic static Test suite() {\n\t\tTestSuite suite = new TestSuite(AllTests.class.getName());\n\t\t//$JUnit-BEGIN$\n\t\tsuite.addTestSuite(OfflineMapUtilTest.class);\n\t\tsuite.addTestSuite(GridTest.class);\n\t\tsuite.addTestSuite(CellTest.class);\n\t\tsuite.addTestSuite(OfflineMapConfigTest.class);\n\t\tsuite.addTestSuite(MapLayerTest.class);\n\t\tsuite.addTestSuite(MapWidgetTest.class);\n\t\t//$JUnit-END$\n\t\treturn suite;\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/androidTest/java/com/ls/widgets/map/CellTest.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map;\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.model.Cell;\nimport com.ls.widgets.map.model.Grid;\nimport com.ls.widgets.map.providers.AssetTileProvider;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Rect;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.test.AndroidTestCase;\nimport android.widget.LinearLayout;\n\n\npublic class CellTest extends AndroidTestCase \n{\n\tprivate static final int MAP_ORIGINAL_WIDTH = 1520;\n\tprivate static final int MAP_ORIGINAL_HEIGHT = 920;\n\tprivate static final int MAX_ZOOM_LEVEL = 11;\n\n\tprivate OfflineMapConfig config;\n\tprivate AssetTileProvider tileManager;\n\tprivate Drawable drawable;\n\t\n\t\n\tprotected void setUp() throws Exception {\n\t\tsuper.setUp();\n\t\tconfig = new OfflineMapConfig(\"map\", MAP_ORIGINAL_WIDTH, MAP_ORIGINAL_HEIGHT, 256, 1, \"png\");\n\t    tileManager = new AssetTileProvider(getContext(), config);\n\t    \n\t    drawable = new BitmapDrawable(Bitmap.createBitmap(config.getTileSize(), config.getTileSize(), Bitmap.Config.RGB_565));\n\t}\n\n\tprotected void tearDown() throws Exception {\n\t\tsuper.tearDown();\n\t}\n\t\n\t\n\tpublic void testRecalculateDrawableRect()\n\t{\n\t\tGrid grid = new Grid(new LinearLayout(getContext()), config, tileManager, MAX_ZOOM_LEVEL);\n\t\tCellImpl cell = new CellImpl(grid, tileManager, 6, 0, 0, config.getTileSize(), 1.0f);\n\t\tcell.setImage(drawable);\n\t\tcell.recalculateDrawableRect(0, 0);\n\t\t\n\t\tRect imageRect = cell.getDrawableRect();\n\t\tRect shouldBe = new Rect(0,0,256,256);\n\t\t\n\t\tassertEquals(shouldBe, imageRect);\n\t\t\n\t\tcell.setScale(2.0f);\n\t\timageRect = cell.getDrawableRect();\n\t\tshouldBe.set(0,0, 512, 512);\n\t\t\n\t\tassertEquals(shouldBe, imageRect);\n\t\t\n\t\tcell = new CellImpl(grid, tileManager, 11, 1, 1, config.getTileSize(), 1.0f);\n\t    drawable = new BitmapDrawable(Bitmap.createBitmap(config.getTileSize(), config.getTileSize(), Bitmap.Config.RGB_565));\n\t\tcell.setImage(drawable);\n\t\tcell.setScale(1.0f);\n\t\tcell.recalculateDrawableRect(0, 0);\n\t\t\n\t\tshouldBe.set(256, 256, 512, 512);\n\t\timageRect = cell.getDrawableRect();\n\t\t\n\t\tassertEquals(shouldBe, imageRect);\n\t}\n\t\n\t\n\tprivate void assertEquals(Rect r1, Rect r2) \n\t{\n\t\tassertEquals(r1.top,  r2.top);\n\t\tassertEquals(r1.left,  r2.left);\n\t\tassertEquals(r1.bottom, r2.bottom);\n\t\tassertEquals(r1.right,  r2.right);\n\t}\n\t\n\tprivate static class CellImpl extends Cell\n\t{\n\t\tpublic CellImpl(Grid parent, AssetTileProvider tileManager, int zoomLevel, int col, int row, int tileSize, float scale) {\n\t\t\tsuper(parent, tileManager, zoomLevel, col, row, tileSize, scale);\n\t\t}\n\t\t\n\t\t\n\t\t@Override\n\t\tprotected void recalculateDrawableRect(float dx, float dy) {\n\t\t\t// TODO Auto-generated method stub\n\t\t\tsuper.recalculateDrawableRect(dx, dy);\n\t\t}\n\t\t\n\t\t\n\t\tpublic void setImage(Drawable drawable) \n\t\t{\n\t\t\tthis.image = drawable;\n\t\t}\n\t\t\n\t\t\n\t\tpublic Rect getDrawableRect()\n\t\t{\n\t\t\treturn image.getBounds();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/androidTest/java/com/ls/widgets/map/GridTest.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map;\n\nimport android.content.Context;\nimport android.graphics.BitmapFactory;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.test.AndroidTestCase;\nimport android.view.View;\nimport android.widget.LinearLayout;\n\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.interfaces.TileManagerDelegate;\nimport com.ls.widgets.map.model.Grid;\nimport com.ls.widgets.map.providers.AssetTileProvider;\n\npublic class GridTest extends AndroidTestCase {\n\n\tOfflineMapConfig config;\n\tAssetTileProvider tileManager;\n\n\tprivate static final int MAP_ORIGINAL_WIDTH = 1520;\n\tprivate static final int MAP_ORIGINAL_HEIGHT = 920;\n\tprivate static final int MAX_ZOOM_LEVEL = 11;\n\t\n\t private int colCount[] = {1,1,1,1,1,1,1,1,1,2,3,6}; // col count on each zoom level\n\t private int rowCount[] = {1,1,1,1,1,1,1,1,1,1,2,4}; // row count on each zoom level\n\t private int widthOnZoomLevel[] = {1,2,3,6,12,24,48,95,190,380,760,1520}; // width of the grid on each zoom level in pixels\n\t private int heightOnZoomLevel[] = {1,1,2,4,8,15,29,58,115,230,460,920}; // height of the grid on each zoom level in pixels\n\t \n\t // scale on each zoom level\n\t private double scaleOnZoomLevel[] = {0.00048828125f, 0.0009765625f, 0.001953125f, 0.00390625f, 0.0078125f, 0.015625f, 0.03125f, 0.0625f, 0.125f, 0.25f, 0.5f, 1.0f};\n\tprivate BitmapDrawable drawable;\n\t\n\tprotected void setUp() throws Exception \n\t{\n\t\tsuper.setUp();\n\t\t\n\t\tconfig = new OfflineMapConfig(\"map\", MAP_ORIGINAL_WIDTH, MAP_ORIGINAL_HEIGHT, 256, 1, \"png\");\n\t\tdrawable = new BitmapDrawable(getContext().getResources(),\n                BitmapFactory.decodeResource(getContext().getResources(),\n\t\t\tcom.ls.widgets.map.test.R.drawable.maps_blue_dot));\n\n\t    tileManager = new TestTileManager(getContext(), config);\n\t}\n\n\tprotected void tearDown() throws Exception \n\t{\n\t\tsuper.tearDown();\n\t}\n\n\tpublic void testGetHeight() \n\t{\n\t\tfor (int i=0; i< heightOnZoomLevel.length; ++i) {\n\t\t\tGridToTest grid = new GridToTest(new LinearLayout(getContext()), config, tileManager, i);\n\t\t\tassertEquals(heightOnZoomLevel[i], grid.getHeight());\n\t\t}\n\t}\n\n\tpublic void testGetOriginalHeight() \n\t{\n\t\tGridToTest grid = new GridToTest(new LinearLayout(getContext()), config, tileManager, MAX_ZOOM_LEVEL);\n\t\tassertEquals(MAP_ORIGINAL_HEIGHT, grid.getOriginalHeight());\n\t}\n\n\tpublic void testGetOriginalWidth() \n\t{\n\t\tfor (int i=0; i<=MAX_ZOOM_LEVEL; ++i) {\n\t\t\tGridToTest grid = new GridToTest(new LinearLayout(getContext()), config, tileManager, MAX_ZOOM_LEVEL);\n\t\t\tassertEquals(MAP_ORIGINAL_WIDTH, grid.getOriginalWidth());\n\t\t}\n\t}\n\n\tpublic void testGetWidth() \n\t{\n\t\tfor (int i=0; i<=MAX_ZOOM_LEVEL; ++i) {\n\t\t\tGridToTest grid = new GridToTest(new LinearLayout(getContext()), config, tileManager, i);\n\t\t\tassertEquals(widthOnZoomLevel[i], grid.getWidth());\n\t\t}\n\t}\n\n\tpublic void testGetMaxZoomLevel() \n\t{\n\t\tfor (int i=0; i<= MAX_ZOOM_LEVEL; ++i) {\n\t\t\tGridToTest grid = new GridToTest(new LinearLayout(getContext()), config, tileManager, i);\n\t\t\tassertEquals(MAX_ZOOM_LEVEL, grid.getMaxZoomLevel());\n\t\t}\n\t}\n\n\tpublic void testGetMinZoomLevel() \n\t{\n\t\tfor (int i=0; i<= MAX_ZOOM_LEVEL; ++i) {\n\t\t\tGridToTest grid = new GridToTest(new LinearLayout(getContext()), config, tileManager, i);\n\t\t\tassertEquals(0, grid.getMinZoomLevel());\n\t\t}\n\t}\n\t\n\tpublic void testGetColCount()\n\t{\n\t\tfor (int i=0; i<colCount.length; ++i) {\n\t\t\tGridToTest grid = new GridToTest(new LinearLayout(getContext()), config, tileManager, i);\n\t\t\t\n\t\t\tassertEquals(colCount[i], grid.getColCountTest());\n\t\t}\n\t}\n\t\n\t\n\tpublic void testGetRowCount()\n\t{\n\t\tfor (int i=0; i<rowCount.length; ++i) {\n\t\t\tGridToTest grid = new GridToTest(new LinearLayout(getContext()), config, tileManager, i);\n\t\t\t\n\t\t\tassertEquals(rowCount[i], grid.getRowCountTest());\n\t\t}\n\t}\n\t\n\t\n\tpublic void testGetScale()\n\t{\n\t\tfor (int i=0; i<scaleOnZoomLevel.length; ++i) {\n\t\t\tGridToTest grid = new GridToTest(new LinearLayout(getContext()), config, tileManager, i);\n\t\t\t\n\t\t\tassertEquals(scaleOnZoomLevel[i], grid.getScale());\n\t\t}\n\t}\n\t\n\n\tpublic void testSetSoftScale()\n\t{\n\t\tfinal float scales[] = {0.125f, 0.25f, 0.5f, 2.0f, 4.0f, 8.0f};\n\t\t\n\t\tfor (int zoom_level=7; zoom_level<=MAX_ZOOM_LEVEL; ++zoom_level) {\n\t\t\tGridToTest grid = new GridToTest(new LinearLayout(getContext()), config, tileManager, zoom_level);\n\t\t\t\n\t\t\tfor (int i=0; i<scales.length; ++i) {\n\t\t\t\tgrid.setSoftScale(1.0f);\n\t\t\t\tint width1 = grid.getWidth();\n\t\t\t\tgrid.setSoftScale(scales[i]);\n\t\t\t\tint width2 = grid.getWidth();\n\t\t\t\t\n\t\t\t\tdouble scale = grid.getSoftScale();\n\t\t\t\tassertEquals(scales[i], (float)scale);\n\t\t\t\t\n\t\t\t\tassertEquals(\"ZL: \" + zoom_level + \", Original W: \" + width1 + \", Scaled W: \" + width2 + \", scale: \" + scales[i],\n\t\t\t\t(int)Math.ceil((float)width1 * scales[i]), width2);\n\t\t\t}\n\t\t}\n\t}\n\t\n\n\tprivate static class GridToTest extends Grid\n\t{\n\t\tpublic GridToTest(View parent, OfflineMapConfig config, AssetTileProvider tileManager,int initZoomLevel)\n\t\t{\n\t\t\tsuper(parent, config, tileManager, initZoomLevel);\n\t\t}\n\t\t\n\t\t\n\t\tpublic int getColCountTest()\n\t\t{\n\t\t\treturn getColCount();\n\t\t}\n\t\t\n\t\t\n\t\tpublic int getRowCountTest()\n\t\t{\n\t\t\treturn getRowCount();\n\t\t}\n\t}\n\t\n\t\n\tprivate class TestTileManager extends AssetTileProvider\n\t{\n\n\t\tpublic TestTileManager(Context context, OfflineMapConfig config) {\n\t\t\tsuper(context, config);\n\t\t\t\n\t\t}\n\n\t\t@Override\n\t\tpublic void requestTile(int zoomLevel, int col, int row,\n\t\t\t\tTileManagerDelegate delegate) {\n\t\t\tdelegate.onTileReady(zoomLevel, col, row, drawable);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/androidTest/java/com/ls/widgets/map/MapLayerTest.java",
    "content": "/*************************************************************************\r\n* Copyright (c) 2015 Lemberg Solutions\r\n*\r\n* Licensed under the Apache License, Version 2.0 (the \"License\");\r\n* you may not use this file except in compliance with the License.\r\n* You may obtain a copy of the License at\r\n*\r\n*    http://www.apache.org/licenses/LICENSE-2.0\r\n*\r\n* Unless required by applicable law or agreed to in writing, software\r\n* distributed under the License is distributed on an \"AS IS\" BASIS,\r\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n* See the License for the specific language governing permissions and\r\n* limitations under the License.\r\n**************************************************************************/\r\n\r\npackage com.ls.widgets.map;\r\n\r\nimport java.util.ArrayList;\r\n\r\nimport android.R;\r\nimport android.graphics.Bitmap;\r\nimport android.graphics.BitmapFactory;\r\nimport android.graphics.Canvas;\r\nimport android.graphics.Matrix;\r\nimport android.graphics.Paint;\r\nimport android.graphics.Rect;\r\nimport android.graphics.RectF;\r\nimport android.graphics.drawable.BitmapDrawable;\r\nimport android.graphics.drawable.Drawable;\r\nimport android.test.AndroidTestCase;\r\n\r\nimport com.ls.widgets.map.MapWidget;\r\nimport com.ls.widgets.map.interfaces.Layer;\r\nimport com.ls.widgets.map.model.MapLayer;\r\nimport com.ls.widgets.map.model.MapObject;\r\n\r\npublic class MapLayerTest extends AndroidTestCase\r\n{\r\n\tprivate MapWidget map;\r\n\tprivate Layer layer;\r\n\tprivate Drawable drawable;\r\n\tprivate FakeCanvas canvas;\r\n\t\r\n\t@Override\r\n\tprotected void setUp() throws Exception \r\n\t{\r\n\t\tmap = new MapWidget(getContext(), \"map\", 11);\r\n\t\tdrawable = new BitmapDrawable(BitmapFactory.decodeResource(getContext().getResources(), R.drawable.presence_online));\r\n\r\n\t\tlayer = map.createLayer(1);\r\n\t\tcanvas = new FakeCanvas();\r\n\t\t\r\n\t\tsuper.setUp();\r\n\t}\r\n\t\r\n\t\r\n\t@Override\r\n\tprotected void tearDown() throws Exception \r\n\t{\r\n\t\tmap.removeLayer(1);\r\n\t\tsuper.tearDown();\r\n\t}\r\n\r\n\r\n\tpublic void testAddMapObject()\r\n\t{\r\n\t\tfor (int i=-1000; i <= 1000; ++i) {\r\n\t\t\tMapObject object = new MapObject(i,\r\n\t\t\t\t\t\t\t\t\t\t\tdrawable,\r\n\t\t\t\t\t\t\t\t\t\t\t0, 0);\r\n\t\t\tlayer.addMapObject(object);\r\n\t\t\tMapObject received = layer.getMapObject(i);\r\n\t\t\t\r\n\t\t\tassertSame(object, received);\r\n\t\t}\r\n\t\t\r\n\t\tlayer.clearAll();\r\n\t}\r\n\t\r\n\t\r\n\tpublic void testRemoveMapObject()\r\n\t{\r\n\t\tfor (int i=0; i <= 100; ++i) {\r\n\t\t\tMapObject object = new MapObject(i,\r\n\t\t\t\t\t\t\t\t\t\t\tdrawable,\r\n\t\t\t\t\t\t\t\t\t\t\t0, 0);\r\n\t\t\tlayer.addMapObject(object);\r\n\t\t}\r\n\t\t\r\n\t\tfor (int i=0; i <= 100; ++i) {\r\n\t\t\tlayer.removeMapObject(i);\r\n\t\t\tMapObject object = layer.getMapObject(i);\r\n\t\t\tassertNull(\"Failed for \" + i + \" element\", object);\r\n\t\t}\r\n\t}\r\n\r\n\t\r\n\tpublic void testGetMapObject()\r\n\t{\r\n\t\tMapObject object1 = new MapObject(1,drawable, 0, 0);\r\n\t\tMapObject object4 = new MapObject(4,drawable, 4, 4);\r\n\t\tMapObject object16 = new MapObject(16,drawable, 16, 16);\r\n\t\t\r\n\t\tlayer.addMapObject(object1);\r\n\t\tlayer.addMapObject(object16);\r\n\t\tlayer.addMapObject(object4);\r\n\t\t\r\n\t\tMapObject obj = layer.getMapObject(16);\r\n\t\tassertSame(object16, obj);\r\n\t\tassertEquals(16, obj.getX());\r\n\t\tassertEquals(16, obj.getY());\r\n\t\t\r\n\t\tobj = layer.getMapObject(1);\r\n\t\tassertSame(object1, obj);\r\n\t\tassertEquals(0, obj.getX());\r\n\t\tassertEquals(0, obj.getY());\r\n\t\t\r\n\t\tobj = layer.getMapObject(4);\r\n\t\tassertSame(object4, obj);\r\n\t\tassertEquals(4, obj.getX());\r\n\t\tassertEquals(4, obj.getY());\r\n\t}\r\n\t\r\n\t\r\n\tpublic void testIsVisible()\r\n\t{\r\n\t\t// Test default state\r\n\t\tassertTrue(layer.isVisible());\r\n\t\t\r\n\t\t// Test invisible state\r\n\t\tlayer.setVisible(false);\r\n\t\tassertFalse(layer.isVisible());\r\n\t\t\r\n\t\t// Test visible state\r\n\t\tlayer.setVisible(true);\r\n\t\tassertTrue(layer.isVisible());\r\n\r\n\t\tfor (int i=0; i <= 20; ++i) {\r\n\t\t\tMapObject object = new MapObject(i,\r\n\t\t\t\t\t\t\t\t\t\t\tdrawable,\r\n\t\t\t\t\t\t\t\t\t\t\t0, 0);\r\n\t\t\tlayer.addMapObject(object);\r\n\t\t}\t\t\r\n\t\t\r\n\t\tlayer.setVisible(true);\r\n\r\n\t\tcanvas.setDrawPerformed(false);\r\n\t\t((MapLayer)layer).draw(canvas, new Rect(0,0, 480, 800));\r\n\t\tassertTrue(canvas.drawPerformed);\r\n\t\t\r\n\t\tlayer.setVisible(false);\r\n\t\tcanvas.setDrawPerformed(false);\r\n\t\t((MapLayer)layer).draw(canvas, new Rect(0,0, 480, 800));\r\n\t\tassertFalse(canvas.drawPerformed);\r\n\t\t\r\n\t\tlayer.setVisible(true);\r\n\t\tcanvas.setDrawPerformed(false);\r\n\t\t((MapLayer)layer).draw(canvas, new Rect(480,0, 800, 800));\r\n\t\tassertFalse(canvas.drawPerformed);\r\n\t}\r\n\t\r\n\t\r\n\tpublic void testGetMapObjectByIndexInt()\r\n\t{\r\n\t\tfor (int i=0; i < 100; ++i) {\r\n\t\t\tMapObject object = new MapObject(i,\r\n\t\t\t\t\t\t\t\t\t\t\tdrawable,\r\n\t\t\t\t\t\t\t\t\t\t\t0, 0);\r\n\t\t\tlayer.addMapObject(object);\r\n\t\t}\r\n\t\t\r\n\t\tint count = layer.getMapObjectCount();\r\n\t\t\r\n\t\tassertEquals(100, count);\r\n\t\t\r\n\t\tMapObject object = layer.getMapObject(5);\r\n\t\tassertEquals(object.getId(), 5);\r\n\t}\r\n\t\r\n\tpublic void testGetTouched()\r\n\t{\r\n//\t\tgetTouchedTest1(true);\r\n//\t\tlayer.clearAll();\r\n//\t\tgetTouchedTest1(false);\r\n//\t\tlayer.clearAll();\r\n\t\t\r\n\t\tgetTouchedTest2(true);\r\n\t\tlayer.clearAll();\r\n\t\tgetTouchedTest2(false);\r\n\t}\r\n\t\r\n\t\r\n\tpublic void testSetScale()\r\n\t{\r\n\t\tfor (int i=0; i < 200; ++i) {\r\n\t\t\tMapObject object = new MapObject(i,\r\n\t\t\t\t\t\t\t\t\t\tdrawable,\r\n\t\t\t\t\t\t\t\t\t\t20, 10);\r\n\t\t\tlayer.addMapObject(object);\r\n\t\t}\r\n\t\t\r\n\t\tfloat scaleToTest[] = {0.5f, 1.0f, 2.0f};\r\n\t\tint resultsX[] = {10, 20, 40};\r\n\t\tint resultsY[] = {5, 10, 20};\r\n\t\t\r\n\t\tfor (int j=0; j<scaleToTest.length; ++j) {\r\n\t\t\t((MapLayer)layer).setScale(scaleToTest[j]);\r\n\t\t\t\r\n\t\t\tfor (int i=0; i < 200; ++i) {\r\n\t\t\t\tMapObject obj = layer.getMapObject(i);\r\n\t\t\t\tassertNotNull(obj);\r\n\t\t\t\r\n\t\t\t\tassertEquals(20, obj.getX());\r\n\t\t\t\tassertEquals(10, obj.getY());\r\n\t\t\t\tassertEquals(resultsX[j], obj.getXScaled());\r\n\t\t\t\tassertEquals(resultsY[j], obj.getYScaled());\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\r\n//\tprivate void getTouchedTest1(boolean touchable) \r\n//\t{\r\n//\t\tint counter = 0; \r\n//\t\tint width = drawable.getIntrinsicWidth();\r\n//\t\tint height = drawable.getIntrinsicHeight();\r\n//\t\t\r\n//\t\tgetTouchedGenerateMapObjects(touchable, width, height);\r\n//\t\t\r\n//\t\tcounter = 0;\r\n//\t\tfor (int i=0; i < 480/width; ++i) {\r\n//\t\t\tfor (int j=0; j < 800/height; ++j) {\r\n//\t\t\t\tint touchedX = (int)((float)i*(float)width+(float)width/2.0f);\r\n//\t\t\t\tint touchedY = (int)((float)j*(float)height+(float)height/2.0f);\r\n//\t\t\t\tArrayList<Object> touchedIds = ((MapLayer)layer).getTouched(touchedX, touchedY);\r\n//\r\n//\t\t\t\tif (touchable) {\r\n//\t\t\t\t\tassertEquals(1, touchedIds.size());\r\n//\t\t\t\t} else {\r\n//\t\t\t\t\tassertEquals(0, touchedIds.size());\r\n//\t\t\t\t}\r\n//\t\t\t\t\r\n//\t\t\t\tif (touchable) {\r\n//\t\t\t\t\tObject id = touchedIds.get(0);\r\n//\t\t\t\t\tassertEquals(counter, id);\r\n//\t\t\t\t}\r\n//\r\n//\t\t\t\tcounter += 1;\r\n//\t\t\t}\r\n//\t\t}\r\n//\t}\r\n\t\r\n\t\r\n\tprivate void getTouchedTest2(boolean touchable) \r\n\t{\r\n\t\tint counter = 0; \r\n\t\tint width = drawable.getIntrinsicWidth();\r\n\t\tint height = drawable.getIntrinsicHeight();\r\n\t\t\r\n\t\tgetTouchedGenerateMapObjects(touchable, width, height);\r\n\t\t\r\n\t\tcounter = 0;\r\n\t\tfor (int i=0; i < 480/width; ++i) {\r\n\t\t\tfor (int j=0; j < 800/height; ++j) {\r\n\t\t\t\tint touchedX = (int)((float)i*(float)width+(float)width/2.0f);\r\n\t\t\t\tint touchedY = (int)((float)j*(float)height+(float)height/2.0f);\r\n\t\t\t\tArrayList<Object> touchedIds = ((MapLayer)layer).getTouched(new Rect(touchedX - 2, touchedY - 2, touchedX + 2, touchedY + 2));\r\n\r\n\t\t\t\tif (touchable) {\r\n\t\t\t\t\tassertEquals(1, touchedIds.size());\r\n\t\t\t\t} else {\r\n\t\t\t\t\tassertEquals(0, touchedIds.size());\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (touchable) {\r\n\t\t\t\t\tObject id = touchedIds.get(0);\r\n\t\t\t\t\tassertEquals(counter, id);\r\n\t\t\t\t}\r\n\t\t\t\tcounter += 1;\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tArrayList<Object> touchedIds = ((MapLayer)layer).getTouched(new Rect(0, 0, width * 2, height * 2));\r\n\t\t\r\n\t\tif (touchable) {\r\n\t\t\tassertEquals(4, touchedIds.size());\r\n\t\t} else {\r\n\t\t\tassertEquals(0, touchedIds.size());\r\n\t\t}\r\n\t}\r\n\r\n\r\n\tprivate void getTouchedGenerateMapObjects(boolean touchable,\r\n\t\t\tint width, int height) \r\n\t{\r\n\t\tint counter = 0;\r\n\t\tfor (int i=0; i < 480/width; ++i) {\r\n\t\t\tfor (int j=0; j < 800/height; ++j) {\r\n\t\t\t\tMapObject object = new MapObject(counter,\r\n\t\t\t\t\t\t\t\t\t\t\tdrawable,\r\n\t\t\t\t\t\t\t\t\t\t\ti*width, j*height, touchable);\r\n\t\t\t\tlayer.addMapObject(object);\r\n\t\t\t\t\r\n\t\t\t\tcounter += 1;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t\r\n\tprivate static class FakeCanvas extends Canvas\r\n\t{\r\n\t\tprivate boolean drawPerformed;\r\n\t\t\r\n\t\tpublic FakeCanvas()\r\n\t\t{\r\n\t\t\tdrawPerformed = false;\r\n\t\t}\r\n\t\t\r\n\t\t@Override\r\n\t\tpublic void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) \r\n\t\t{\r\n\t\t\tsuper.drawBitmap(bitmap, left, top, paint);\r\n\t\t\tdrawPerformed = true;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {\r\n\t\t\tsuper.drawBitmap(bitmap, matrix, paint);\r\n\t\t\tdrawPerformed = true;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {\r\n\t\t\tsuper.drawBitmap(bitmap, src, dst, paint);\r\n\t\t\tdrawPerformed = true;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {\r\n\t\t\tsuper.drawBitmap(bitmap, src, dst, paint);\r\n\t\t\tdrawPerformed = true;\r\n\t\t}\r\n\t\t\r\n\t\t\r\n\t\tpublic void setDrawPerformed(boolean performed)\r\n\t\t{\r\n\t\t\tdrawPerformed = performed;\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/androidTest/java/com/ls/widgets/map/MapObjectTest.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.interfaces.Layer;\nimport com.ls.widgets.map.model.MapLayer;\nimport com.ls.widgets.map.model.MapObject;\nimport com.ls.widgets.map.utils.Size;\n\nimport android.R;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Point;\nimport android.graphics.Rect;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.test.AndroidTestCase;\n\npublic class MapObjectTest extends AndroidTestCase\n{\n    \n    \n    private MapWidget map;\n    private MapLayer layer;\n    private Drawable drawable1;\n    private Drawable drawable2;\n    private FakeMapObject scalableObject;\n    private FakeMapObject nonScalableObject;\n    private Size originalDrawableSize;\n\n  \n    protected void setUp() throws Exception\n    {\n        super.setUp();\n        \n//        map = new MapWidget(getContext(), \"map\", 11);\n        drawable1 = new BitmapDrawable(BitmapFactory.decodeResource(getContext().getResources(), R.drawable.presence_online));\n        drawable2 = new BitmapDrawable(BitmapFactory.decodeResource(getContext().getResources(), R.drawable.presence_online));\n\n        originalDrawableSize = new Size(drawable1.getIntrinsicWidth(), drawable1.getIntrinsicHeight());\n//        layer = map.createLayer(1);   \n        \n        scalableObject = new FakeMapObject(\"1\", drawable1, 10, 10, 0, 0, true, true);\n        nonScalableObject = new FakeMapObject(\"2\", drawable2, 100, 100, 0, 0, true, false);\n    }\n\n\n    protected void tearDown() throws Exception\n    {\n       // map.removeAllLayers();\n        \n        super.tearDown();\n    }\n\n\n    public void testMapObjectObjectDrawableIntIntIntIntBooleanBoolean()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testGetDrawable()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testSetDrawable()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testDraw()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testGetId()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testIsTouchedIntInt()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testIsTouchedRect()\n    {      \n        assertEquals(true, nonScalableObject.isTouchable());\n        \n        Rect touchRect = new Rect(100,100,101,101);\n        \n        assertEquals(true, nonScalableObject.isTouched(touchRect));\n        \n        touchRect.set(100, 99, 101, 100);\n        \n        assertEquals(false, nonScalableObject.isTouched(touchRect));\n        \n        Rect drawableRect = nonScalableObject.getDrawable().getBounds();\n        Rect touchableRect = nonScalableObject.getTouchArea();\n        \n        assertEquals(drawableRect.width(), touchableRect.width());\n        \n        nonScalableObject.setNewScale(2.0f);\n        \n        assertEquals(drawableRect.width(), touchableRect.width() / 2);\n    }\n\n\n    public void testGetXScaled()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testGetYScaled()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testGetX()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testGetY()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testIsTouchable()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testGetBounds()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testMoveTo()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testSetScale()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n\n    public void testSetParent()\n    {\n        fail(\"Not yet implemented\");\n    }\n\n    private class FakeMapObject extends MapObject {\n\n        public FakeMapObject(Object id, Drawable drawable, int x, int y, int pivotX, int pivotY, boolean isTouchable,\n                boolean isScalable)\n        {\n            super(id, drawable, x, y, pivotX, pivotY, isTouchable, isScalable);\n        }\n        \n        \n        public void setNewScale(float scale)\n        {\n            this.scale = scale;\n            recalculateBounds();        \n        }\n        \n        \n        public Rect getTouchArea()\n        {\n            return this.touchRect;\n        }\n        \n\n\n    }\n    \n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/androidTest/java/com/ls/widgets/map/MapWidgetTest.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map;\n\nimport java.util.ArrayList;\n\nimport android.content.Context;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Point;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.test.AndroidTestCase;\nimport android.util.Log;\nimport android.view.animation.Animation.AnimationListener;\n\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.interfaces.Layer;\nimport com.ls.widgets.map.interfaces.MapEventsListener;\nimport com.ls.widgets.map.interfaces.TileManagerDelegate;\nimport com.ls.widgets.map.model.MapObject;\nimport com.ls.widgets.map.providers.AssetTileProvider;\n\npublic class MapWidgetTest\n        extends AndroidTestCase {\n    private TestMapWidget map;\n    private BitmapDrawable drawable;\n\n    @Override\n    protected void setUp() throws Exception {\n        map = new TestMapWidget(getContext(), \"map\", 11);\n        map.setScale(1.0f);\n        drawable = new BitmapDrawable(getContext().getResources(),\n                BitmapFactory.decodeResource(getContext().getResources(),\n                        com.ls.widgets.map.test.R.drawable.maps_blue_dot));\n        super.setUp();\n    }\n\n\n    @Override\n    protected void tearDown() throws Exception {\n        map.removeAllLayers();\n        map.startProcessing();\n        super.tearDown();\n    }\n\n\n    public void testCreateLayer() {\n        int layerIds[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};\n        Layer layers[] = new Layer[layerIds.length];\n\n        for (int i = 0; i < layerIds.length; ++i) {\n            layers[i] = map.createLayer(layerIds[i]);\n        }\n\n        for (int i = 0; i < layerIds.length; ++i) {\n            Layer layer = map.getLayerById(Integer.valueOf(i));\n\n            assertNotNull(layer);\n            assertSame(layers[i], layer);\n        }\n\n        boolean ok = false;\n        try {\n            map.createLayer(0);\n        } catch (IllegalArgumentException e) {\n            ok = true;\n        }\n\n        assertTrue(ok);\n    }\n\n\n    public void testRemoveLayer() {\n        for (int i = -100; i <= 100; ++i) {\n            map.createLayer(i);\n        }\n\n        for (int i = -100; i <= 100; ++i) {\n\n            Layer layer = map.getLayerById(i);\n            assertNotNull(layer);\n\n            map.removeLayer(i);\n\n            layer = map.getLayerById(i);\n            assertNull(layer);\n        }\n\n        try {\n            map.removeLayer(0);\n        } catch (Exception e) {\n            fail();\n        }\n    }\n\n\n    public void testGetLayer() {\n        int layerIds[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19};\n        Layer layers[] = new Layer[layerIds.length];\n\n        for (int i = 0; i < layerIds.length; ++i) {\n            layers[i] = map.createLayer(layerIds[i]);\n        }\n\n        for (int i = 0; i < layerIds.length; ++i) {\n            Layer layer = map.getLayer(i);\n            assertSame(layers[i], layer);\n        }\n\n        boolean ok = false;\n        try {\n            map.getLayer(layerIds.length);\n        } catch (IndexOutOfBoundsException e) {\n            ok = true;\n        }\n\n        assertTrue(ok);\n    }\n\n\n    public void testGetLayerById() {\n        int layerIds[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19};\n        Layer layers[] = new Layer[layerIds.length];\n\n        for (int i = 0; i < layerIds.length; ++i) {\n            layers[i] = map.createLayer(layerIds[i]);\n        }\n\n        for (int i = 0; i < layerIds.length; ++i) {\n            Layer layer = map.getLayerById(layerIds[i]);\n            assertSame(layers[i], layer);\n        }\n\n        assertNull(map.getLayerById(0));\n    }\n\n\n    public void testGetLayerCount() {\n        for (int j = 0; j < 100; ++j) {\n            for (int i = 0; i < j; ++i) {\n                map.createLayer(i);\n            }\n\n            assertEquals(map.getLayerCount(), j);\n            map.removeAllLayers();\n        }\n    }\n\n\n    public void testGetMapHeight() {\n        int height = map.getConfig().getImageHeight();\n\n        for (int i = 1; i <= 11; ++i) {\n            assertEquals(\"i:\" + i, height, map.getMapHeight());\n            map.zoomOut();\n            height = (int) Math.ceil(height / 2.0f);\n        }\n    }\n\n\n    public void testGetMapWidth() {\n        int width = map.getConfig().getImageWidth();\n\n        for (int i = 1; i <= 11; ++i) {\n            assertEquals(\"i:\" + i, width, map.getMapWidth());\n            map.zoomOut();\n            width = (int) Math.ceil(width / 2.0f);\n        }\n    }\n\n\n    public void testGetOriginalMapWidth() {\n        int width = map.getConfig().getImageWidth();\n\n        for (int i = 1; i <= 11; ++i) {\n            assertEquals(width, map.getOriginalMapWidth());\n            map.zoomOut();\n        }\n    }\n\n\n    public void testGetOriginalMapHeight() {\n        int height = map.getConfig().getImageHeight();\n\n        for (int i = 1; i <= 11; ++i) {\n            assertEquals(height, map.getOriginalMapHeight());\n            map.zoomOut();\n        }\n    }\n\n\n    public void testGetConfig() {\n        OfflineMapConfig config = map.getConfig();\n        assertNotNull(config);\n\n        config.setMaxZoomLevelLimit(1);\n        config = map.getConfig();\n        assertTrue(config.getMaxZoomLevelLimit() == 1);\n    }\n\n\n    public void testGetScale() {\n        float scalesUp[] = {1.0f, 2.0f, 4.0f, 8.0f, 16f, 32f};\n        float scalesDown[] = {1.0f, 0.5f, 0.25f, 0.125f};\n        map.setAnimationEnabled(false);\n\n        for (int i = 0; i < scalesUp.length; ++i) {\n            assertEquals(\"i=\" + i, scalesUp[i], map.getScale());\n            map.zoomIn();\n        }\n\n        for (int i = 0; i < scalesUp.length; ++i) {\n            map.zoomOut();\n        }\n\n        for (int i = 0; i < scalesDown.length; ++i) {\n            assertEquals(scalesDown[i], map.getScale());\n            map.zoomOut();\n        }\n\n        for (int i = 0; i < 20; i++) {\n            double testScale = 0.1;\n            final double step = 0.1;\n\n            while (testScale < 3.0f) {\n                float prevScale = map.getScale();\n                int prevWidth = map.getMapWidth();\n\n                Log.d(\"MapWidgetTest\", \"ZL: \" + map.getZoomLevel() + \", scale: \" + map.getScale() + \", width: \" + map.getMapWidth() + \", testScale: \" + testScale);\n\n                map.setScale((float) testScale);\n\n                assertEquals(\"ZL: \" + map.getZoomLevel() + \", prevScale: \" + prevScale + \", CurScale:\" + (float) testScale + \", prevWidth: \" + prevWidth,\n                        (float) (prevScale * testScale), map.getScale());\n\n                map.setScale(1.0f);\n\n                testScale += step;\n            }\n\n            map.zoomIn();\n        }\n    }\n\n\n    public void testGetZoomLevel() {\n        map.setAnimationEnabled(false);\n\n        // Test lower bound\n        for (int i = 11; i >= -11; --i) {\n            int zl = map.getZoomLevel();\n\n            if (i >= 0) {\n                assertEquals(i, zl);\n            }\n\n            map.zoomOut();\n        }\n\n        assertEquals(0, map.getZoomLevel());\n\n        // Test regular zoom with software zoom is enabled\n        for (int i = 0; i <= 22; ++i) {\n            int zl = map.getZoomLevel();\n            assertEquals(i, zl);\n\n            map.zoomIn();\n        }\n\n        // Test upper bound when software zoom is disabled\n        map = new TestMapWidget(getContext(), \"map\", 1);\n        map.setScale(1.0f);\n        map.setAnimationEnabled(false);\n\n        OfflineMapConfig conf = map.getConfig();\n        conf.setSoftwareZoomEnabled(false);\n\n        for (int i = 1; i <= 22; ++i) {\n            int zl = map.getZoomLevel();\n\n            if (i <= 11) {\n                assertEquals(i, zl);\n            } else {\n                assertEquals(11, zl);\n            }\n\n            map.zoomIn();\n        }\n    }\n\n\n    public void testRemoveAllLayers() {\n        for (int i = -50; i < 50; ++i) {\n            map.createLayer(i);\n        }\n\n        assertEquals(100, map.getLayerCount());\n        map.removeAllLayers();\n\n        for (int i = -50; i < 50; ++i) {\n            assertNull(\"i:\" + i, map.getLayerById(i));\n        }\n    }\n\n    public void testClearLayers() {\n        int count = 50;\n        MapObject[] objects = generateMapObjects(count);\n        ArrayList<Layer> layers = new ArrayList<Layer>(10);\n\n\n        for (int i = -5; i < 5; ++i) {\n            Layer layer = map.createLayer(i);\n\n            for (MapObject object : objects) {\n                layer.addMapObject(object);\n            }\n\n            layers.add(layer);\n\n            assertEquals(count, layer.getMapObjectCount());\n        }\n\n        map.clearLayers();\n\n        for (Layer layer : layers) {\n            assertEquals(0, layer.getMapObjectCount());\n        }\n    }\n\n\n    public void testSetMinZoomLevel() {\n        for (int j = 10; j >= 0; --j) {\n            map = new TestMapWidget(getContext(), \"map\", 11);\n            map.setAnimationEnabled(false);\n            map.setMinZoomLevel(j);\n\n            for (int i = j; i >= 0; --i) {\n                map.zoomOut();\n\n                int zl = map.getZoomLevel();\n\n                if (zl < j) {\n                    fail(\"ZL: \" + zl + \", j: \" + j);\n                }\n            }\n        }\n    }\n\n\n    public void testSetMaxZoomLevel() {\n        for (int j = 2; j <= 11; ++j) {\n            map = new TestMapWidget(getContext(), \"map\", 1);\n            map.setAnimationEnabled(false);\n            map.setMaxZoomLevel(j);\n\n            for (int i = 2; i <= 11; ++i) {\n                map.zoomIn();\n\n                int zl = map.getZoomLevel();\n\n                if (zl > j) {\n                    fail(\"ZL: \" + zl + \", j: \" + j);\n                }\n            }\n        }\n    }\n\n\n    public void testSetScale() {\n        map = new TestMapWidget(getContext(), \"map\", 1);\n        map.setAnimationEnabled(false);\n\n        float scalesUp[] = {1.0f, 2.0f, 4.0f, 8.0f, 16f, 32f};\n        float scalesDown[] = {1.0f, 0.5f, 0.25f, 0.125f};\n\n        for (int j = 0; j < 15; ++j) {\n            for (int i = 0; i < scalesDown.length; ++i) {\n                float oldScale = map.getScale();\n                map.setScale(scalesDown[i]);\n                float newScale = map.getScale();\n\n                assertEquals(\"zl:\" + map.getZoomLevel() + \", i:\" + i + \", os:\" + oldScale + \", ns:\" + newScale,\n                        scalesDown[i], newScale / oldScale);\n\n                map.setScale(1.0f);\n            }\n\n\n            for (int i = 0; i < scalesUp.length; ++i) {\n                float oldScale = map.getScale();\n                map.setScale(scalesUp[i]);\n                float newScale = map.getScale();\n\n                assertEquals(\"zl:\" + map.getZoomLevel(), scalesUp[i], newScale / oldScale);\n\n                map.setScale(1.0f);\n            }\n\n            map.zoomIn();\n        }\n    }\n\n\n    public void testUseSoftwareZoom() {\n        map.setAnimationEnabled(false);\n        map.setUseSoftwareZoom(false);\n\n        for (int i = 0; i < 10; ++i) {\n            map.zoomIn();\n        }\n\n        assertEquals(11, map.getZoomLevel());\n\n        map.setUseSoftwareZoom(true);\n\n        for (int i = 0; i < 10; ++i) {\n            map.zoomIn();\n        }\n\n        assertEquals(11 + 10, map.getZoomLevel());\n    }\n\n\n    public void testZoomIn() {\n        map = new TestMapWidget(getContext(), \"map\", 1);\n        map.setAnimationEnabled(false);\n        TestMapEventsListener listener = new TestMapEventsListener();\n\n        for (int i = 2; i <= 13; ++i) {\n            map.addMapEventsListener(listener);\n\n            float oldScale = map.getScale();\n\n            map.zoomIn();\n\n            float newScale = map.getScale();\n\n            assertTrue(\"I:\" + i + \", zoomIn: \" + listener.counters[TestMapEventsListener.PRE_ZOOM_IN] +\n                            \" \" + listener.counters[TestMapEventsListener.POST_ZOOM_IN],\n                    listener.zoomInValid());\n\n            assertEquals(\"i:\" + i, 2.0f, newScale / oldScale);\n\n            map.removeMapEventsListener(listener);\n            listener.clearCounters();\n        }\n    }\n\n\n    public void testZoomOut() {\n        map.setAnimationEnabled(false);\n        TestMapEventsListener listener = new TestMapEventsListener();\n        for (int i = 2; i <= 11; ++i) {\n\n            map.addMapEventsListener(listener);\n\n            float oldScale = map.getScale();\n            map.zoomOut();\n\n            float newScale = map.getScale();\n\n            assertTrue(\"I:\" + i + \", zoomOut: \" + listener.counters[TestMapEventsListener.PRE_ZOOM_OUT] +\n                    \" \" + listener.counters[TestMapEventsListener.POST_ZOOM_OUT], listener.zoomOutValid());\n\n            assertEquals(2.0f, oldScale / newScale);\n\n            map.removeMapEventsListener(listener);\n            listener.clearCounters();\n        }\n    }\n\n// FIXME: Temporarily disabled\n//    public void testAnimatedZoomIn() {\n//        map = new TestMapWidget(getContext(), \"map\", 1);\n//        map.setAnimationEnabled(true);\n//        final Object event = new Object();\n//\n//        TestMapEventsListener listener = new TestMapEventsListener() {\n//            @Override\n//            public void onPostZoomIn() {\n//                super.onPostZoomIn();\n//\n//                synchronized (event) {\n//                    event.notify();\n//                }\n//            }\n//        };\n//\n//\n//        for (int i = 2; i <= 11; ++i) {\n//            map.addMapEventsListener(listener);\n//            float oldScale = map.getScale();\n//            map.zoomIn();\n//\n//            synchronized (event) {\n//                try {\n//                    event.wait(3000);\n//                } catch (InterruptedException e) {\n//                    fail(e.toString());\n//                    e.printStackTrace();\n//                }\n//            }\n//\n//            float newScale = map.getScale();\n//            map.removeMapEventsListener(listener);\n//            assertTrue(\"I:\" + i + \", zoomIn: \" + listener.counters[TestMapEventsListener.PRE_ZOOM_IN] +\n//                            \" \" + listener.counters[TestMapEventsListener.POST_ZOOM_IN],\n//                    listener.zoomInValid());\n//            assertEquals(2.0f, newScale / oldScale);\n//            listener.clearCounters();\n//        }\n//    }\n\n\n    public void testAnimatedZoomOut() {\n        map.setAnimationEnabled(true);\n\n        TestMapEventsListener listener = new TestMapEventsListener();\n\n\n        for (int i = 2; i <= 11; ++i) {\n            map.addMapEventsListener(listener);\n\n            float oldScale = map.getScale();\n\n            map.zoomOut();\n\n            float newScale = map.getScale();\n\n            map.removeMapEventsListener(listener);\n\n            assertTrue(\"I:\" + i + \", zoomOut: \" + listener.counters[TestMapEventsListener.PRE_ZOOM_OUT] +\n                            \" \" + listener.counters[TestMapEventsListener.POST_ZOOM_OUT],\n                    listener.zoomOutValid());\n\n            assertEquals(2.0f, oldScale / newScale);\n\n            listener.clearCounters();\n        }\n    }\n\n\n    private MapObject[] generateMapObjects(int count) {\n        MapObject[] result = new MapObject[count];\n\n        for (int i = 0; i < count; ++i) {\n            MapObject object = new MapObject(i, drawable, new Point(0, 0));\n            result[i] = object;\n        }\n\n        return result;\n    }\n\n\n    private class TestMapEventsListener implements MapEventsListener {\n        public static final int PRE_ZOOM_IN = 0;\n        public static final int PRE_ZOOM_OUT = 1;\n        public static final int POST_ZOOM_IN = 2;\n        public static final int POST_ZOOM_OUT = 3;\n\n        private int counters[];\n\n        public TestMapEventsListener() {\n            counters = new int[]{0, 0, 0, 0};\n        }\n\n        @Override\n        public void onPreZoomIn() {\n            counters[PRE_ZOOM_IN] += 1;\n        }\n\n        @Override\n        public void onPostZoomIn() {\n            counters[POST_ZOOM_IN] += 1;\n        }\n\n        @Override\n        public void onPreZoomOut() {\n            counters[PRE_ZOOM_OUT] += 1;\n        }\n\n        @Override\n        public void onPostZoomOut() {\n            counters[POST_ZOOM_OUT] += 1;\n        }\n\n\n        public void clearCounters() {\n            counters = new int[]{0, 0, 0, 0};\n        }\n\n\n        public boolean zoomInValid() {\n            return counters[PRE_ZOOM_IN] == 1 && counters[POST_ZOOM_IN] == 1;\n        }\n\n        public boolean zoomOutValid() {\n            return counters[PRE_ZOOM_OUT] == 1 && counters[POST_ZOOM_OUT] == 1;\n        }\n    }\n\n\n    private class TestMapWidget extends MapWidget {\n\n        public TestMapWidget(Context context, String rootMapFolder) {\n            super(context, rootMapFolder);\n\n            this.tileProvider = new TestTileManager(context, this.getConfig());\n            this.setTileProvider(tileProvider);\n        }\n\n        public TestMapWidget(Context context, String rootMapFolder, int initialZl) {\n            super(context, rootMapFolder, initialZl);\n\n            this.tileProvider = new TestTileManager(context, this.getConfig());\n\n            this.setTileProvider(tileProvider);\n        }\n\n\n        @Override\n        protected void animateZoomIn(final AnimationListener listener, float pivotX,\n                                     float pivotY) {\n            (new Thread(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        Thread.sleep(300);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n\n                    post(new Runnable() {\n                        public void run() {\n                            onAnimationEnd();\n                        }\n                    });\n\n                }\n            })).start();\n        }\n\n        @Override\n        protected void animateZoomOut(final AnimationListener listener) {\n            (new Thread(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        Thread.sleep(300);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n\n                    post(new Runnable() {\n                        public void run() {\n                            onAnimationEnd();\n                        }\n                    });\n                    //onAnimationEnd();\n                    //listener.onAnimationEnd(null);\n                }\n            })).start();\n        }\n\n        public void startProcessing() {\n            super.startProcessingRequests();\n        }\n    }\n\n\n    private class TestTileManager extends AssetTileProvider {\n\n        public TestTileManager(Context context, OfflineMapConfig config) {\n            super(context, config);\n        }\n\n        @Override\n        public void requestTile(int zoomLevel, int col, int row,\n                                TileManagerDelegate delegate) {\n            delegate.onTileReady(zoomLevel, col, row, drawable);\n        }\n\n    }\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/androidTest/java/com/ls/widgets/map/OfflineMapConfigTest.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map;\n\nimport android.test.AndroidTestCase;\n\nimport com.ls.widgets.map.config.OfflineMapConfig;\n\npublic class OfflineMapConfigTest extends AndroidTestCase {\n\n\tprivate static final int TEST_IMAGE_WIDTH = 1024;\n\tprivate static final int TEST_IMAGE_HEIGHT = 768;\n\tprivate static final int TEST_TILE_SIZE = 256;\n\tprivate static final int TEST_OVERLAP = 1;\n\tprivate static final String TEST_IMAGE_FORMAT = \"png\";\n\tprivate static final String MAP_ROOT_PATH = \"map\";\n\t\n\tprivate OfflineMapConfig config;\n\t\n\tprotected void setUp() throws Exception \n\t{\n\t\tconfig = new OfflineMapConfig(MAP_ROOT_PATH, TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT, TEST_TILE_SIZE, TEST_OVERLAP, TEST_IMAGE_FORMAT);\n\t\tsuper.setUp();\n\n\t}\n\n\tprotected void tearDown() throws Exception \n\t{\n\t\tsuper.tearDown();\n\t}\n\t\n\t\n\tpublic void testDefaults()\n\t{\n\t\tassertEquals(0, config.getMaxZoomLevelLimit());\n\t\tassertEquals(0, config.getMinZoomLevelLimit());\n\t\tassertEquals(5, config.getTouchAreaSize());\n\t\tassertEquals(64, config.getTrackballScrollStepX());\n\t\tassertEquals(64, config.getTrackballScrollStepY());\n\t\tassertEquals(false, config.isPinchZoomEnabled());\n\t\tassertEquals(false, config.isFlingEnabled());\n\t\tassertEquals(true, config.isSoftwareZoomEnabled());\n\t\tassertEquals(true, config.isZoomBtnsVisible());\n\t}\n\t\n\t\n\tpublic void testConstructor()\n\t{\n\t\tassertEquals(TEST_IMAGE_WIDTH, config.getImageWidth());\n\t\tassertEquals(TEST_IMAGE_HEIGHT, config.getImageHeight());\n\t\tassertEquals(TEST_TILE_SIZE, config.getTileSize());\n\t\tassertEquals(TEST_OVERLAP, config.getOverlap());\n\t\tassertEquals(TEST_IMAGE_FORMAT, config.getImageFormat());\n\t}\n\t\n\t\n\tpublic void testCopyConstructor()\n\t{\n\t\t// If this exception is thrown, please, update this test in order to test new members or\n\t\t// throw the tests for removed fields out.\n\t\tassertEquals(19, config.getClass().getDeclaredFields().length);\n\t\t\n\t\tconfig.setFlingEnabled(true);\n\t\tconfig.setMaxZoomLevelLimit(15);\n\t\tconfig.setMinZoomLevelLimit(10);\n\t\tconfig.setPinchZoomEnabled(true);\n\t\tconfig.setMapCenteringEnabled(true);\n\t\tconfig.setSoftwareZoomEnabled(false);\n\t\tconfig.setTouchAreaSize(10);\n\t\tconfig.setTrackballScrollStepX(25);\n\t\tconfig.setTrackballScrollStepY(30);\n\t\tconfig.setZoomBtnsVisible(false);\n\t\t\n\t\tOfflineMapConfig testConfig = new OfflineMapConfig(config);\n\t\t\n\t\tassertEquals(MAP_ROOT_PATH, testConfig.getMapRootPath());\n\t\tassertEquals(true, testConfig.isFlingEnabled());\n\t\tassertEquals(15, testConfig.getMaxZoomLevelLimit());\n\t\tassertEquals(10, testConfig.getMinZoomLevelLimit());\n\t\tassertEquals(true, testConfig.isPinchZoomEnabled());\n\t\tassertEquals(true, testConfig.isMapCenteringEnabled());\n\t\tassertEquals(false, testConfig.isSoftwareZoomEnabled());\n\t\tassertEquals(10, testConfig.getTouchAreaSize());\n\t\tassertEquals(25, testConfig.getTrackballScrollStepX());\n\t\tassertEquals(30, testConfig.getTrackballScrollStepY());\n\t\tassertEquals(false, testConfig.isZoomBtnsVisible());\n\t\t\n\t\tassertNotSame(config, testConfig);\n\t}\n\t\n\t\n\tpublic void testFlingEnabledOption()\n\t{\n\t\tconfig.setFlingEnabled(true);\n\t\tassertEquals(true, config.isFlingEnabled());\n\t\t\n\t\tconfig.setFlingEnabled(false);\n\t\tassertEquals(false, config.isFlingEnabled());\n\t}\n\t\n\t\n\tpublic void testMaxZoomLevelLimitOption()\n\t{\n\t\tfor (int i=-1000; i<0; ++i) {\n\t\t\tboolean result = false;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tconfig.setMaxZoomLevelLimit(i);\n\t\t\t} catch (IllegalArgumentException e) {\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t\t\n\t\t\tassertTrue(\"Exception was not thrown for i=\" + i, result);\n\t\t}\n\t\t\n\t\tfor (int i=0; i<1000; ++i) {\n\t\t\tconfig.setMaxZoomLevelLimit(i);\n\t\t\tassertEquals(i, config.getMaxZoomLevelLimit());\n\t\t}\n\t}\n\t\n\t\n\tpublic void testMinZoomLevelLimitOption()\n\t{\n\t\tfor (int i=-1000; i<0; ++i) {\n\t\t\tboolean result = false;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tconfig.setMinZoomLevelLimit(i);\n\t\t\t} catch (IllegalArgumentException e) {\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t\t\n\t\t\tassertTrue(\"Exception was not thrown for i=\" + i, result);\n\t\t}\n\t\t\n\t\tfor (int i=0; i<1000; ++i) {\n\t\t\tconfig.setMinZoomLevelLimit(i);\n\t\t\tassertEquals(i, config.getMinZoomLevelLimit());\n\t\t}\n\t}\n\t\n\t\n\tpublic void testPinchZoomEnabledOption()\n\t{\n\t\tconfig.setPinchZoomEnabled(true);\n\t\tassertEquals(true, config.isPinchZoomEnabled());\n\t\t\n\t\tconfig.setPinchZoomEnabled(false);\n\t\tassertEquals(false, config.isPinchZoomEnabled());\n\t}\n\t\n\t\n\tpublic void testSoftwareZoomEnabledOption()\n\t{\n\t\tconfig.setSoftwareZoomEnabled(true);\n\t\tassertEquals(true, config.isSoftwareZoomEnabled());\n\t\t\n\t\tconfig.setSoftwareZoomEnabled(false);\n\t\tassertEquals(false, config.isSoftwareZoomEnabled());\n\t}\n\t\n\t\n\tpublic void testTouchAreaSizeOption()\n\t{\n\t\tfor (int i=-1000; i<=0; ++i) {\n\t\t\tboolean result = false;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tconfig.setTouchAreaSize(i);\n\t\t\t} catch (IllegalArgumentException e) {\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t\t\n\t\t\tassertTrue(\"Exception was not thrown for i=\" + i, result);\n\t\t}\n\t\t\n\t\tfor (int i=1; i<1000; ++i) {\n\t\t\tconfig.setTouchAreaSize(i);\n\t\t\tassertEquals(i, config.getTouchAreaSize());\n\t\t}\n\t}\n\t\n\t\n\tpublic void testTrackballScrollStepXOption()\n\t{\n\t\tfor (int i=-1000; i< 0; ++i) {\n\t\t\tboolean result = false;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tconfig.setTrackballScrollStepX(i);\n\t\t\t} catch (IllegalArgumentException e) {\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t\t\n\t\t\tassertTrue(\"Exception was not thrown for i=\" + i, result);\n\t\t}\n\t\t\n\t\tfor (int i=0; i<1000; ++i) {\n\t\t\tconfig.setTrackballScrollStepX(i);\n\t\t\tassertEquals(i, config.getTrackballScrollStepX());\n\t\t}\n\t}\n\t\n\t\n\tpublic void testTrackballScrollStepYOption()\n\t{\n\t\tfor (int i=-1000; i< 0; ++i) {\n\t\t\tboolean result = false;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tconfig.setTrackballScrollStepY(i);\n\t\t\t} catch (IllegalArgumentException e) {\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t\t\n\t\t\tassertTrue(\"Exception was not thrown for i=\" + i, result);\n\t\t}\n\t\t\n\t\tfor (int i=0; i<1000; ++i) {\n\t\t\tconfig.setTrackballScrollStepX(i);\n\t\t\tassertEquals(i, config.getTrackballScrollStepX());\n\t\t}\n\t}\n\t\n\t\n\tpublic void testZoomBtnsVisibleOption()\n\t{\n\t\tconfig.setZoomBtnsVisible(true);\n\t\tassertEquals(true, config.isZoomBtnsVisible());\n\t\t\n\t\tconfig.setZoomBtnsVisible(false);\n\t\tassertEquals(false, config.isZoomBtnsVisible());\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/androidTest/java/com/ls/widgets/map/OfflineMapUtilTest.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map;\n\nimport android.test.AndroidTestCase;\n\nimport com.ls.widgets.map.utils.OfflineMapUtil;\n\npublic class OfflineMapUtilTest extends AndroidTestCase\n{\n\n\tprivate float imageSizesAtZoomLevel[] = {1,2,3,6,12,24,47,94,188,375,750,1500,3000,6000};\n\t// Zoom Level                   0  1  2  3  4   5   6   7    8    9    10    11    12    13\n\tprivate int zoomLevelStart[] = {1, 2, 3, 5, 9,  17, 33, 65,  129, 257, 513,  1025, 2049, 4097};\n\tprivate int zoomLevelEnd[]   = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192};\n\n\tpublic void testGetScaledImageSize()\n\t{\n\t\tfor (int i=0; i<imageSizesAtZoomLevel.length; ++i) {\n\t\t\tfloat imageSize = OfflineMapUtil.getScaledImageSize(imageSizesAtZoomLevel.length-1, i, 6000);\n\t\t\t\n\t\t\tassertEquals(imageSizesAtZoomLevel[i], imageSize);\n\t\t}\n\t}\n\t\n\t\n\tpublic void testGetMaxZoomLevel()\n\t{\n\t\tfor (int i = 0; i<zoomLevelStart.length; ++i) {\n\t\t\tfor (int zls=zoomLevelStart[i]; zls <= zoomLevelEnd[i]; ++ zls) {\n\t\t\t\tassertEquals(i,  OfflineMapUtil.getMaxZoomLevel(zls,zls));\n\t\t\t}\n\t\t}\n\t\t\t\n\t\tfor (int i = 0; i<zoomLevelStart.length; ++i) {\n\t\t\tfor (int zls=zoomLevelStart[i]; zls <= zoomLevelEnd[i]; ++ zls) {\n\t\t\t\tassertEquals(i,  OfflineMapUtil.getMaxZoomLevel(zls,1));\n\t\t\t}\n\t\t}\n\t\t\n\t\tfor (int i = 0; i<zoomLevelStart.length; ++i) {\n\t\t\tfor (int zls=zoomLevelStart[i]; zls <= zoomLevelEnd[i]; ++ zls) {\n\t\t\t\tassertEquals(i,  OfflineMapUtil.getMaxZoomLevel(1,zls));\n\t\t\t}\n\t\t}\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.ls.widgets.map\">\n</manifest>\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/MapWidget.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.xml.sax.SAXException;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Paint.Style;\nimport android.graphics.Point;\nimport android.graphics.PointF;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.location.Location;\nimport android.os.Bundle;\nimport android.os.Looper;\nimport android.util.Log;\nimport android.view.GestureDetector;\nimport android.view.GestureDetector.SimpleOnGestureListener;\nimport android.view.KeyEvent;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup.LayoutParams;\nimport android.view.ViewTreeObserver;\nimport android.view.ViewTreeObserver.OnGlobalLayoutListener;\nimport android.view.animation.Animation;\nimport android.view.animation.Animation.AnimationListener;\nimport android.view.animation.DecelerateInterpolator;\nimport android.view.animation.ScaleAnimation;\nimport android.view.animation.TranslateAnimation;\nimport android.widget.Scroller;\nimport android.widget.ZoomButtonsController;\nimport android.widget.ZoomButtonsController.OnZoomListener;\n\nimport com.ls.widgets.map.config.GPSConfig;\nimport com.ls.widgets.map.config.MapConfigParser;\nimport com.ls.widgets.map.config.MapGraphicsConfig;\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.events.MapScrolledEvent;\nimport com.ls.widgets.map.events.MapTouchedEvent;\nimport com.ls.widgets.map.events.ObjectTouchEvent;\nimport com.ls.widgets.map.interfaces.Layer;\nimport com.ls.widgets.map.interfaces.MapEventsListener;\nimport com.ls.widgets.map.interfaces.MapLocationListener;\nimport com.ls.widgets.map.interfaces.OnGridReadyListener;\nimport com.ls.widgets.map.interfaces.OnLocationChangedListener;\nimport com.ls.widgets.map.interfaces.OnMapDoubleTapListener;\nimport com.ls.widgets.map.interfaces.OnMapLongClickListener;\nimport com.ls.widgets.map.interfaces.OnMapScrollListener;\nimport com.ls.widgets.map.interfaces.OnMapTilesFinishedLoadingListener;\nimport com.ls.widgets.map.interfaces.OnMapTouchListener;\nimport com.ls.widgets.map.location.PositionMarker;\nimport com.ls.widgets.map.model.Grid;\nimport com.ls.widgets.map.model.MapLayer;\nimport com.ls.widgets.map.providers.AssetTileProvider;\nimport com.ls.widgets.map.providers.ExternalStorageTileProvider;\nimport com.ls.widgets.map.providers.GPSLocationProvider;\nimport com.ls.widgets.map.providers.TileProvider;\nimport com.ls.widgets.map.utils.Graphics;\nimport com.ls.widgets.map.utils.MathUtils;\nimport com.ls.widgets.map.utils.OfflineMapUtil;\nimport com.ls.widgets.map.utils.PivotFactory;\nimport com.ls.widgets.map.utils.PivotFactory.PivotPosition;\nimport com.ls.widgets.map.utils.Resources;\nimport com.ls.widgets.map.utils.TransformUtils;\n\npublic class MapWidget extends View implements MapLocationListener {\n\tprivate static final String MSG_MAP_DATA_IS_CORRUPTED_OR_MISSING = \"Map data is corrupted or missing.\";\n\n\tprivate final static String TAG = \"MAP WIDGET\";\n\n\tprivate final static long POS_PIN_ID = 1;\n\n\tprivate enum Mode {\n\t\tNONE, ZOOMED, ZOOM\n\t};\n\n\tprivate OfflineMapConfig config;\n\tprivate ZoomButtonsController zoomBtnsController;\n\n\tprivate Grid grid;\n\tprivate Grid prevGrid;\n\n\tprivate Paint paint;\n\n\tprivate float scale;\n\tprivate double pinchZoomScale;\n\n\tprivate boolean doNotZoom;\n\tprivate boolean isAnimationEnabled;\n\tprivate boolean byUser;\n\n\t// Represents layers in the map\n\tprivate MapLayer topmostLayer;\n\tprivate ArrayList<MapLayer> layers;\n\tprivate Map<Long, Layer> layersMap;\n\n\t// Provider that handles loading of map tiles.\n\tprotected TileProvider tileProvider;\n\tprotected GPSLocationProvider locationProvider;\n\n\t// Listeners\n\tprivate OnMapTouchListener mapTouchListener;\n\tprivate OnMapTilesFinishedLoadingListener mapTilesReadyListener;\n\tprivate OnMapScrollListener mapScrollListener;\n\tprivate ArrayList<MapEventsListener> mapEventsListeners;\n\tprivate OnLocationChangedListener locationChangeListener;\n\tprivate OnLongClickListener longClickListener;\n\tprivate OnMapLongClickListener mapLongClicklistener;\n\tprivate OnMapDoubleTapListener onDoubleTapListener;\n\tprivate OnTouchListener onTouchListener;\n\t\n\tprivate Mode mode;\n\n\t// Smooth scrolling\n\tprivate GestureDetector gestureDetector;\n\tprivate Scroller scroller;\n\n\t// debug\n\tprivate boolean debugEnabled = false;\n\tprivate RectF lastTouchedRect;\n\n\tprivate boolean isZooming;\n\tprivate boolean isDestroying;\n\tprivate boolean userTouching;\n\tprivate double pinchStartDistance;\n\tprivate int mapPivotX;\n\tprivate int mapPivotY;\n\n\tprivate static Bitmap logo;\n\tprivate Rect drawingRect;\n\n\tprivate Runnable restoreScrollPosRunnable;\n\tprivate Runnable performAfterZoom;\n\tprivate Runnable performAfterTranslate;\n\n\tprivate boolean requestCenterMap;\n\n\n\n\n\t/**\n\t * Creates instance of map widget.\n\t * \n\t * @param context\n\t *            - context\n\t * @param rootMapFolder\n\t *            - folder that contains map resources inside your assets.\n\t * @param initialZoomLevel\n\t *            - initial zoom level.\n\t */\n\tpublic MapWidget(Context context, String rootMapFolder, int initialZoomLevel) {\n\t\tthis(null, context, rootMapFolder, initialZoomLevel);\n\t}\n\n\t/**\n\t * Creates instance of map widget.\n\t * \n\t * @param context\n\t *            - context\n\t * @param rootMapFolder\n\t *            - instance of File that points to the map resources which are\n\t *            located on the external storage.\n\t * @param initialZoomLevel\n\t *            - initial zoom level\n\t */\n\tpublic MapWidget(Context context, File rootMapFolder, int initialZoomLevel) {\n\t\tthis(null, context, rootMapFolder, initialZoomLevel);\n\t}\n\n\t/**\n\t * Creates instance of map widget. Zoom level will be set to 10.\n\t * \n\t * @param context\n\t *            - Context\n\t * @param rootMapFolder\n\t *            - folder that contains map resources inside your assets.\n\t */\n\tpublic MapWidget(Context context, String rootMapFolder) {\n\t\tthis(null, context, rootMapFolder, 10);\n\t}\n\n\t/**\n\t * Creates instance of map widget. Zoom level will be set to 10.\n\t * \n\t * @param context\n\t *            - Context\n\t * @param rootMapFolder\n\t *            - instance of File that points to the map resources which are\n\t *            located on the external storage.\n\t */\n\tpublic MapWidget(Context context, File rootMapFolder) {\n\t\tthis(null, context, rootMapFolder, 10);\n\t}\n\n\t/**\n\t * Creates instance of map widget.\n\t * \n\t * @param bundle\n\t *            - bundle that were used to save map widget's state.\n\t * @param context\n\t *            - Context\n\t * @param rootMapFolder\n\t *            - instance of File that points to the map resources which are\n\t *            located on the external storage.\n\t * @param initialZoomLevel\n\t *            - zoom level that will be set in case if bundle doesn't\n\t *            contain previously saved state.\n\t */\n\tpublic MapWidget(Bundle bundle, Context context, File rootMapFolder,\n\t\t\tint initialZoomLevel) {\n\t\tsuper(context);\n\n\t\tinitCommonStuff(context);\n\n\t\tString configPath = OfflineMapUtil.getConfigFilePath(rootMapFolder\n\t\t\t\t.getAbsolutePath());\n\n\t\ttry {\n\t\t\tMapConfigParser configParser = new MapConfigParser(\n\t\t\t\t\trootMapFolder.getAbsolutePath());\n\n\t\t\tconfig = configParser.parse(context, new File(configPath));\n\n\t\t\tif (config != null) {\n\t\t\t\ttileProvider = new ExternalStorageTileProvider(config);\n\t\t\t\tint maxZoomLevel = OfflineMapUtil.getMaxZoomLevel(\n\t\t\t\t\t\tconfig.getImageWidth(), config.getImageHeight());\n\t\t\t\tint zoomLevel = initialZoomLevel;\n\t\t\t\tfloat scale = 1.0f;\n\n\t\t\t\tif (bundle != null) {\n\t\t\t\t\tif (bundle.containsKey(\"com.ls.zoomLevel\"))\n\t\t\t\t\t\tzoomLevel = bundle.getInt(\"com.ls.zoomLevel\");\n\n\t\t\t\t\tif (bundle.containsKey(\"com.ls.scale\"))\n\t\t\t\t\t\tscale = bundle.getFloat(\"com.ls.scale\");\n\t\t\t\t}\n\n\t\t\t\tif (zoomLevel > maxZoomLevel) {\n\t\t\t\t\tgrid = new Grid(this, config, tileProvider, maxZoomLevel);\n\t\t\t\t\tif (scale == 1.0f) {\n\t\t\t\t\t\tscale = (float) Math.pow(2, zoomLevel - maxZoomLevel);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tgrid = new Grid(this, config, tileProvider, zoomLevel);\n\t\t\t\t}\n\n\t\t\t\tthis.scale = scale;\n\t\t\t\tgrid.setInternalScale(scale);\n\n\t\t\t\tinitPositionPin();\n\t\t\t\trestoreMapPosition(bundle);\n\t\t\t}\n\t\t} catch (SAXException e) {\n\t\t\tLog.e(TAG, \"Exception: \" + e);\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\tLog.e(TAG, \"Exception: \" + e);\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * Creates instance of map widget.\n\t * \n\t * @param bundle\n\t *            - bundle that were used to save map widget's state.\n\t * @param context\n\t *            - Context\n\t * @param rootMapFolder\n\t *            - folder that contains map resources inside your assets.\n\t * @param initialZoomLevel\n\t *            - zoom level that will be set in case if bundle doesn't\n\t *            contain previously saved state.\n\t */\n\tpublic MapWidget(Bundle bundle, Context context, String rootMapFolder,\n\t\t\tint initialZoomLevel) {\n\t\tsuper(context);\n\n\t\tinitCommonStuff(context);\n\n\t\tString configPath = OfflineMapUtil.getConfigFilePath(rootMapFolder);\n\n\t\ttry {\n\t\t\tMapConfigParser configParser = new MapConfigParser(rootMapFolder);\n\n\t\t\tconfig = configParser.parse(context, configPath);\n\t\t\ttileProvider = new AssetTileProvider(getContext(), config);\n\n\t\t\tint maxZoomLevel = OfflineMapUtil.getMaxZoomLevel(\n\t\t\t\t\tconfig.getImageWidth(), config.getImageHeight());\n\t\t\tint zoomLevel = initialZoomLevel;\n\t\t\tfloat scale = 1.0f;\n\n\t\t\tif (bundle != null) {\n\t\t\t\tif (bundle.containsKey(\"com.ls.zoomLevel\"))\n\t\t\t\t\tzoomLevel = bundle.getInt(\"com.ls.zoomLevel\");\n\n\t\t\t\tif (bundle.containsKey(\"com.ls.scale\"))\n\t\t\t\t\tscale = bundle.getFloat(\"com.ls.scale\");\n\t\t\t}\n\n\t\t\tif (zoomLevel > maxZoomLevel) {\n\t\t\t\tgrid = new Grid(this, config, tileProvider, maxZoomLevel);\n\t\t\t\tif (scale == 1.0f) {\n\t\t\t\t\tscale = (float) Math.pow(2, zoomLevel - maxZoomLevel);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tgrid = new Grid(this, config, tileProvider, zoomLevel);\n\t\t\t}\n\n\t\t\tthis.scale = scale;\n\t\t\tgrid.setInternalScale(scale);\n\n\t\t\tinitPositionPin();\n\t\t\trestoreMapPosition(bundle);\n\t\t} catch (SAXException e) {\n\t\t\tLog.e(TAG, \"Exception: \" + e);\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\tLog.e(TAG, \"Exception: \" + e);\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tprivate void restoreMapPosition(Bundle bundle) {\n\t\tif (bundle != null && bundle.containsKey(\"com.ls.curPosOnMapX\")) {\n\t\t\tfinal int mapX = (int) bundle.getFloat(\"com.ls.curPosOnMapX\");\n\t\t\tfinal int mapY = (int) bundle.getFloat(\"com.ls.curPosOnMapY\");\n\n\t\t\tLog.d(\"MapWidget\", \"Restored pos: [\" + mapX + \",\" + mapY + \"]\");\n\n\t\t\trestoreScrollPosRunnable = new Runnable() {\n\t\t\t\tpublic void run() {\n\t\t\t\t\tjumpTo(new Point(mapX, mapY));\n\t\t\t\t};\n\t\t\t};\n\n\t\t} else {\n\t\t\tdoCorrectPosition(false, false);\n\t\t}\n\t}\n\n\tprivate void initCommonStuff(Context context) {\n\t\tscale = 1.0f;\n\t\tmode = Mode.NONE;\n\t\tdrawingRect = new Rect();\n\t\tisAnimationEnabled = true;\n\t\trequestCenterMap = false;\n\t\tuserTouching = false;\n\n\t\tthis.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,\n\t\t\t\tLayoutParams.FILL_PARENT));\n\n\t\tsetBackgroundDrawable(null);\n\n\t\tthis.setClickable(true);\n\t\tthis.setEnabled(true);\n\t\tthis.setFocusable(true);\n\n\t\tinitializeZoomBtnsController();\n\n\t\tgestureDetector = new GestureDetector(context, new MyGestureDetector());\n\t\tdecelerateInterpolator = new DecelerateInterpolator(1.5f);\n\n\t\tscroller = new Scroller(context, decelerateInterpolator);\n\n\t\ttopmostLayer = new MapLayer(1, this);\n\t\ttopmostLayer.setVisible(false);\n\n\t\tlayers = new ArrayList<MapLayer>();\n\t\tlayersMap = new HashMap<Long, Layer>();\n\t\tmapEventsListeners = new ArrayList<MapEventsListener>();\n\n\t\tpaint = new Paint();\n\t\tpaint.setColor(Color.RED);\n\t\tpaint.setStyle(Style.STROKE);\n\t\tpaint.setStrokeWidth(1);\n\n\t\tif (Resources.LOGO != null) {\n\t\t\tlogo = BitmapFactory.decodeByteArray(Resources.LOGO, 0,\n\t\t\t\t\tResources.LOGO.length);\n\t\t}\n\n\t\tlocationProvider = null;\n\t\tperformAfterTranslate = null;\n\t}\n\n\tprivate void initPositionPin() {\n\t\tBitmapDrawable arrow = new BitmapDrawable(getResources(),\n\t\t\t\tBitmapFactory.decodeByteArray(Graphics.BLUE_ARROW, 0,\n\t\t\t\t\t\tGraphics.BLUE_ARROW.length));\n\n\t\tBitmapDrawable dot = new BitmapDrawable(getResources(),\n\t\t\t\tBitmapFactory.decodeByteArray(\n\t\t\t\tGraphics.BLUE_DOT, 0, Graphics.BLUE_DOT.length));\n\t\tPositionMarker pin = new PositionMarker(this, POS_PIN_ID, dot, arrow);\n\n\t\ttopmostLayer.addMapObject(pin);\n\t}\n\n\t@Override\n\tprotected void onSizeChanged(int w, int h, int oldw, int oldh) {\n\t\tsuper.onSizeChanged(w, h, oldw, oldh);\n\n\t\tif (w == 0 && h == 0)\n\t\t\treturn;\n\n\t\tif (restoreScrollPosRunnable != null) {\n\t\t\trestoreScrollPosRunnable.run();\n\t\t\trestoreScrollPosRunnable = null;\n\t\t}\n\t}\n\n\tprotected void setTileProvider(TileProvider tileManager) {\n\t\tif (grid != null) {\n\t\t\tgrid.setTileProvider(tileManager);\n\t\t}\n\t}\n\n\t/**\n\t * Adds listener for map events.\n\t * \n\t * @param listener\n\t *            - instance of MapEventListener\n\t */\n\tpublic void addMapEventsListener(MapEventsListener listener) {\n\t\tif (mapEventsListeners == null) {\n\t\t\tmapEventsListeners = new ArrayList<MapEventsListener>();\n\t\t}\n\n\t\tmapEventsListeners.add(listener);\n\t}\n\n\t/**\n\t * Creates new map layer with a given id.\n\t * \n\t * @param theLayerId\n\t *            - id of the new layer\n\t * @return returns instance of the MapLayer or null if error occured.\n\t * @throws IllegalArgumentException\n\t *             when layer with the given id exists already.\n\t */\n\tpublic MapLayer createLayer(long theLayerId) {\n\t\tif (this.layersMap.containsKey(theLayerId)) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Attempt to create layer with duplicated ID\");\n\t\t}\n\n\t\ttry {\n\t\t\tMapLayer layer = new MapLayer(theLayerId, this);\n\n\t\t\tlayers.add(layer);\n\t\t\tlayersMap.put(theLayerId, layer);\n\n\t\t\treturn layer;\n\t\t} catch (Exception e) {\n\t\t\tLog.e(\"MapWidget\", \"Exception: \" + e);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Removes layer with the given id from the map.\n\t * \n\t * @param theLayerId\n\t *            the id of previously created layer.\n\t */\n\tpublic void removeLayer(long theLayerId) {\n\t\tLayer layer = layersMap.remove(theLayerId);\n\t\tlayers.remove(layer);\n\t}\n\n\t/**\n\t * Removes all layers from the map.\n\t */\n\tpublic void removeAllLayers() {\n\t\tlayers.clear();\n\t\tlayersMap.clear();\n\t}\n\n\t/**\n\t * Centers the map horizontally\n\t */\n\tpublic void centerMapHorizontally() {\n\t\tif (grid.getWidth() > getWidth()) {\n\t\t\tint dx = (getWidth() - grid.getWidth()) / 2;\n\t\t\tscrollBy(-dx, 0);\n\t\t}\n\t}\n\n\t/**\n\t * Returns map layer by index.\n\t * \n\t * @param index\n\t *            the index of the layer\n\t * @return instance of Layer\n\t * @throws ArrayIndexOutOfBoundsException\n\t *             when index is out of bounds.\n\t */\n\tpublic Layer getLayer(int index) {\n\t\treturn layers.get(index);\n\t}\n\n\t/**\n\t * Returns map layer by layer id.\n\t * \n\t * @param id\n\t *            - layer id\n\t * @return instance of Layer\n\t */\n\tpublic Layer getLayerById(long id) {\n\t\treturn layersMap.get(id);\n\t}\n\n\t/**\n\t * Returns total layer count\n\t * \n\t * @return layer count\n\t */\n\tpublic int getLayerCount() {\n\t\treturn layers.size();\n\t}\n\n\t/**\n\t * Returns height of the map taking current scale into account.\n\t * \n\t * @return height of the map in pixels.\n\t */\n\tpublic int getMapHeight() {\n\t\tif (grid != null) {\n\t\t\treturn grid.getHeight();\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Returns width of the map taking current scale into account.\n\t * \n\t * @return width of the map in pixels.\n\t */\n\tpublic int getMapWidth() {\n\t\tif (grid != null) {\n\t\t\treturn grid.getWidth();\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Returns the height of the map on the max zoom level.\n\t * \n\t * @return original map height in pixels.\n\t */\n\tpublic int getOriginalMapHeight() {\n\t\tif (grid != null) {\n\t\t\treturn grid.getOriginalHeight();\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Returns the width of the map on the max zoom level.\n\t * \n\t * @return original map width in pixels.\n\t */\n\tpublic int getOriginalMapWidth() {\n\t\tif (grid != null) {\n\t\t\treturn grid.getOriginalWidth();\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Returns the copy of the map widget's configuration\n\t * \n\t * @return instance of OfflineMapConfig class.\n\t */\n\tpublic OfflineMapConfig getConfig() {\n\t\treturn config;\n\t}\n\n\t/**\n\t * Returns the current scale of the map.\n\t * \n\t * @return float that represents the scale of the map. 1.0 = max zoom level.\n\t *         0.5 - map is scaled down to half of it's size.\n\t */\n\tpublic float getScale() {\n\t\tif (grid != null) {\n\t\t\treturn (float) grid.getScale();\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Returns current zoom level of the map.\n\t * \n\t * @return current zoom level of the map. Should be greater than 0.\n\t */\n\tpublic int getZoomLevel() {\n\t\tif (grid == null) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tdouble scale = grid.getScale();\n\t\tint zoomLevel = grid.getZoomLevel();\n\n\t\tif (scale <= 1.0f) {\n\t\t\treturn zoomLevel;\n\t\t} else {\n\t\t\treturn OfflineMapUtil.getMaxZoomLevel(grid.getWidth(),\n\t\t\t\t\tgrid.getHeight());\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean onKeyDown(int keyCode, KeyEvent event) {\n\t\tif (config == null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tint keyCode2 = event.getKeyCode();\n\n\t\tswitch (keyCode2) {\n\t\tcase KeyEvent.KEYCODE_DPAD_LEFT:\n\t\t\tscrollBy(-config.getTrackballScrollStepX(), 0);\n\t\t\treturn true;\n\t\tcase KeyEvent.KEYCODE_DPAD_RIGHT:\n\t\t\tscrollBy(config.getTrackballScrollStepX(), 0);\n\t\t\treturn true;\n\t\tcase KeyEvent.KEYCODE_DPAD_UP:\n\t\t\tscrollBy(0, -config.getTrackballScrollStepY());\n\t\t\treturn true;\n\t\tcase KeyEvent.KEYCODE_DPAD_DOWN:\n\t\t\tscrollBy(0, config.getTrackballScrollStepY());\n\t\t\treturn true;\n\t\tcase KeyEvent.KEYCODE_I:\n\t\t\tzoomIn();\n\t\t\treturn true;\n\t\tcase KeyEvent.KEYCODE_O:\n\t\t\tzoomOut();\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic boolean onTouchEvent(MotionEvent event) {\n\t\tif (config == null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (isDestroying) {\n\t\t\tLog.w(\"MapWidget\", \"Map is destroying... OnTouch skipped\");\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tif (this.onTouchListener != null) {\n\t\t//\tthis.onTouchListener.onTouch(this, event);\n\t\t}\n\t\tboolean result = false;\n\t\t\n\t\tsuper.onTouchEvent(event);\n\n\t\tgestureDetector.onTouchEvent(event);\n\n\t\tint action = event.getAction();\n\t\tint actionCode = action & MotionEvent.ACTION_MASK;\n\n\t\tif (actionCode == MotionEvent.ACTION_DOWN) {\n\t\t\tbyUser = true;\n\t\t\tuserTouching = true;\n\t\t\ttry {\n\t\t\t\tif (config.isZoomBtnsVisible()) {\n\t\t\t\t\tzoomBtnsController.setVisible(true);\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.w(\"MapWidget\", \"Exception e: \" + e);\n\t\t\t}\n\n\t\t\ttileProvider.pauseProcessingCommands();\n\n\t\t\tresult = true;\n\t\t} else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) {\n\t\t\tif (config.isPinchZoomEnabled()) {\n\t\t\t\tmode = Mode.ZOOM;\n\t\t\t\tdoNotZoom = false;\n\t\n\t\t\t\tfloat x1 = event.getX(0);\n\t\t\t\tfloat y1 = event.getY(0);\n\t\t\t\tfloat x2 = event.getX(1);\n\t\t\t\tfloat y2 = event.getY(1);\n\t\n\t\t\t\tpinchStartDistance = MathUtils.distance(x1, y1, x2, y2);\n\t\n\t\t\t\tPointF mapPivot = MathUtils.middle(x1, y1, x2, y2);\n\t\n\t\t\t\tmapPivotX = (int) (mapPivot.x);\n\t\t\t\tmapPivotY = (int) (mapPivot.y);\n\t\n\t\t\t\tresult =  true;\n\t\t\t}\n\t\t} else if (actionCode == MotionEvent.ACTION_MOVE) {\n\t\t\tif (zoomBtnsController != null && config.isZoomBtnsVisible()\n\t\t\t\t\t&& !zoomBtnsController.isVisible())\n\t\t\t\tzoomBtnsController.setVisible(true);\n\n\n\t\t\tif (mode == Mode.ZOOM) {\n\t\t\t\tfloat x1 = event.getX(0);\n\t\t\t\tfloat y1 = event.getY(0);\n\t\t\t\tfloat x2 = event.getX(1);\n\t\t\t\tfloat y2 = event.getY(1);\n\n\t\t\t\tdouble pinchDistance = MathUtils.distance(x1, y1, x2, y2);\n\n\t\t\t\tif (pinchStartDistance != 0) {\n\t\t\t\t\tpinchZoomScale = pinchDistance / pinchStartDistance;\n\n\t\t\t\t\tif (pinchZoomScale >= 1.025) {\n\t\t\t\t\t\tmode = Mode.ZOOMED;\n\t\t\t\t\t\tzoomIn(mapPivotX, mapPivotY);\n\t\t\t\t\t} else if (pinchZoomScale <= 0.975) {\n\t\t\t\t\t\tmode = Mode.ZOOMED;\n\t\t\t\t\t\tzoomOut();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult = true;\n\t\t} else if (actionCode == MotionEvent.ACTION_POINTER_UP) {\n\t\t\tmode = Mode.NONE;\n\t\t\tresult = true;\n\t\t} else if (actionCode == MotionEvent.ACTION_UP) {\n\n\t\t\tbyUser = false;\n\t\t\tuserTouching = false;\n\n\t\t\tif (!isZooming) {\n\t\t\t\tdoCorrectPosition();\n\t\t\t}\n\n\t\t\tresult = true;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Removes map event listener from the map.\n\t * \n\t * @param listener\n\t *            instance of the MapEventsListener\n\t */\n\tpublic void removeMapEventsListener(MapEventsListener listener) {\n\t\tif (mapEventsListeners != null) {\n\t\t\tmapEventsListeners.remove(listener);\n\t\t}\n\t}\n\n\t/**\n\t * Removes all map event listeners.\n\t */\n\tpublic void removeAllMapEventsListeners() {\n\t\tif (mapEventsListeners != null) {\n\t\t\tmapEventsListeners.clear();\n\t\t}\n\n\t\tmapEventsListeners = new ArrayList<MapEventsListener>();\n\t}\n\n\t/**\n\t * Removes all graphical object from all layers\n\t */\n\tpublic void clearLayers() {\n\n\t\tif (Looper.myLooper() == null) {\n\t\t\tthrow new IllegalThreadStateException(\n\t\t\t\t\t\"Should be called from UI thread\");\n\t\t}\n\n\t\tfor (int i = layers.size() - 1; i >= 0; --i) {\n\t\t\tlayers.get(i).clearAll();\n\t\t}\n\n\t\tlayers.clear();\n\t}\n\n\t\n\t/**\n\t * Sets touch listener to the map.\n\t * \n\t * @param mapTouchListener\n\t *            instance of OnMapTouchListener.\n\t */\n\tpublic void setOnMapTouchListener(OnMapTouchListener mapTouchListener) {\n\t\tthis.mapTouchListener = mapTouchListener;\n\t}\n\n\t\n\t/**\n\t * Sets the listener to handle long click on the map.\n\t * @param onMapLongClickListener - instance of {@link OnMapLongClickListener}. Can be null.\n\t */\n\tpublic void setOnMapLongClickListener(OnMapLongClickListener onMapLongClickListener) \n\t{\n\t\tthis.mapLongClicklistener = onMapLongClickListener;\n\t}\n\t\n\t\n\t/**\n\t * Sets the listener that will be called when all visible tiles has been\n\t * loaded and displayed.\n\t * \n\t * @param listener\n\t *            instance of OnMapTilesFinishedLoadingListener or null.\n\t */\n\tpublic void setOnMapTilesFinishLoadingListener(\n\t\t\tOnMapTilesFinishedLoadingListener listener) {\n\t\tthis.mapTilesReadyListener = listener;\n\n\t\tif (grid != null) {\n\t\t\tgrid.setOnReadyListener(new OnGridReadyListener() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onReady() {\n\t\t\t\t\tif (mapTilesReadyListener != null) {\n\t\t\t\t\t\tmapTilesReadyListener.onMapTilesFinishedLoading();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Sets scroll listener to the map.\n\t * \n\t * @param mapScrollListener\n\t *            instance of OnMapScrollListener.\n\t */\n\tpublic void setOnMapScrolledListener(OnMapScrollListener mapScrollListener) {\n\t\tthis.mapScrollListener = mapScrollListener;\n\t}\n\n\t/**\n\t * Sets listener for retrieving the location\n\t * \n\t * @param listener\n\t *            - instance of OnLocationChangedListener. May be null.\n\t */\n\tpublic void setOnLocationChangedListener(OnLocationChangedListener listener) {\n\t\tthis.locationChangeListener = listener;\n\t}\n\n\n\t/**\n\t * Sets the listener to handle long click event.\n\t * \n\t * @param listener\n\t *            instance of OnLongClickListener. Can be null.\n\t * @see android.view.View.OnLongClickListener\n\t */\n\t@Override\n\tpublic void setOnLongClickListener(OnLongClickListener listener) {\n\t\tthis.longClickListener = listener;\n\t}\n\n\n\t/**\n\t * Sets the listener to handle double tap event.\n\t * @param listener instance of OnMapDoubleTapListener. Can be null.\n\t * @see com.ls.widgets.map.interfaces.OnMapDoubleTapListener\n\t */\n\tpublic void setOnDoubleTapListener(OnMapDoubleTapListener listener) \n\t{\n\t\tthis.onDoubleTapListener = listener;\n\t}\n\t\n\t\n\t/**\n\t * Sets the listener to handle touch events\n\t * @param listener instance of OnTouchListener\n\t * @see android.view.View.OnTouchListener\n\t */\n\t@Override\n\tpublic void setOnTouchListener(OnTouchListener listener) \n\t{\n\t\tsuper.setOnTouchListener(listener);\n\t}\n\n\t/**\n\t * Enables or disables the standard zoom controls.\n\t * \n\t * @param enabled\n\t *            true in order to make zoom controls visible, otherwise false.\n\t */\n\tpublic void setZoomButtonsVisible(boolean enabled) {\n\t\tif (config != null) {\n\t\t\tconfig.setZoomBtnsVisible(enabled);\n\n\t\t\tif (enabled) {\n\t\t\t\tif (zoomBtnsController == null) {\n\t\t\t\t\tinitializeZoomBtnsController();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (zoomBtnsController != null) {\n\t\t\t\t\tzoomBtnsController.setVisible(false);\n\t\t\t\t\tzoomBtnsController.setOnZoomListener(null);\n\t\t\t\t\tzoomBtnsController = null;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tLog.w(TAG, \"Ignored. Map is not initialized properly.\");\n\t\t}\n\t}\n\n\t/**\n\t * Sets the min zoom level the user can zoom out to.\n\t * \n\t * @param minZoomLevel\n\t *            int from 0 to count of zoom levels.\n\t */\n\tpublic void setMinZoomLevel(int minZoomLevel) {\n\t\tif (config == null) {\n\t\t\tLog.w(TAG,\n\t\t\t\t\t\"setMinZoomLevel skipped. MapWidget is not initialized properly\");\n\t\t\treturn;\n\t\t}\n\n\t\tint maxAvailableZoomLevel = grid.getMaxZoomLevel();\n\t\tint minAvailableZoomLevel = grid.getMinZoomLevel();\n\n\t\tif (minZoomLevel < minAvailableZoomLevel) {\n\t\t\tLog.w(TAG, \"There is no \" + minZoomLevel + \" zoom level. Will use \"\n\t\t\t\t\t+ minAvailableZoomLevel + \" as min zoom level.\");\n\t\t\tconfig.setMinZoomLevelLimit(minZoomLevel);\n\t\t} else if (minZoomLevel > maxAvailableZoomLevel) {\n\t\t\tLog.w(TAG,\n\t\t\t\t\t\"Min zoom level should be less than max zoom level. Min zoom level: \"\n\t\t\t\t\t\t\t+ minAvailableZoomLevel + \" Max zoom level: \"\n\t\t\t\t\t\t\t+ maxAvailableZoomLevel + \", \"\n\t\t\t\t\t\t\t+ \" You are setting: \"\n\t\t\t\t\t\t\t+ config.getMaxZoomLevelLimit()\n\t\t\t\t\t\t\t+ \" as min zoom level.\");\n\t\t\tLog.w(TAG, \"Will use max zoom level as min zoom level.\");\n\t\t\tconfig.setMinZoomLevelLimit(maxAvailableZoomLevel);\n\t\t} else {\n\t\t\tconfig.setMinZoomLevelLimit(minZoomLevel);\n\t\t}\n\n\t\tupdateZoomButtons();\n\t}\n\n\t/**\n\t * The max zoom level the user can zoom in to.\n\t * \n\t * @param maxZoomLevel\n\t *            int from 0 to max zoom levels.\n\t */\n\tpublic void setMaxZoomLevel(int maxZoomLevel) {\n\t\tif (config == null) {\n\t\t\tLog.w(TAG,\n\t\t\t\t\t\"setMaxZoomLevel skipped. MapWidget was not initialized properly\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (grid == null) {\n\t\t\tthrow new IllegalStateException();\n\t\t}\n\n\t\tint maxAvailableZoomLevel = grid.getMaxZoomLevel();\n\t\tint minAvailableZoomLevel = grid.getMinZoomLevel();\n\n\t\tif (!config.isSoftwareZoomEnabled()\n\t\t\t\t&& maxZoomLevel > maxAvailableZoomLevel) {\n\t\t\tLog.w(TAG, \"There is no \" + maxZoomLevel + \" zoom level. Will use \"\n\t\t\t\t\t+ maxAvailableZoomLevel + \" as max zoom level.\");\n\t\t\tconfig.setMaxZoomLevelLimit(maxAvailableZoomLevel);\n\t\t} else if (maxZoomLevel < minAvailableZoomLevel) {\n\t\t\tLog.w(TAG,\n\t\t\t\t\t\"Max zoom level should be greater than min zoom level. Min zoom level: \"\n\t\t\t\t\t\t\t+ minAvailableZoomLevel + \" Max zoom level: \"\n\t\t\t\t\t\t\t+ maxAvailableZoomLevel + \", \"\n\t\t\t\t\t\t\t+ \" you are setting: \" + maxZoomLevel\n\t\t\t\t\t\t\t+ \" as max zoom level.\");\n\t\t\tLog.w(TAG, \"Will use min zoom level as max zoom level.\");\n\t\t\tconfig.setMaxZoomLevelLimit(minAvailableZoomLevel);\n\t\t} else {\n\t\t\tconfig.setMaxZoomLevelLimit(maxZoomLevel);\n\t\t}\n\n\t\tupdateZoomButtons();\n\t}\n\n\t/**\n\t * Set's the scale to the map. Map will be scaled by resizing the existing\n\t * tiles. Zoom level will be preserved.\n\t * \n\t * @param scale\n\t *            scale value. 2.0 means that you want to make map two times\n\t *            bigger.\n\t */\n\tpublic void setScale(float scale) {\n\n\t\tif (Looper.myLooper() == null) {\n\t\t\tthrow new IllegalThreadStateException(\n\t\t\t\t\t\"Should be called from UI thread\");\n\t\t}\n\n\t\tif (grid == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tgrid.setSoftScale(scale);\n\t\tsetScaleToOtherDrawables((float) getScale());\n\t\tinvalidate();\n\t}\n\n\t/**\n\t * Enables the map to keep zooming in when no more zoom levels left.\n\t * Software scale will be used.\n\t * \n\t * @param useSoftwareZoom\n\t *            true if you want to enable software zoom, false otherwise.\n\t */\n\tpublic void setUseSoftwareZoom(boolean useSoftwareZoom) {\n\t\tif (config != null) {\n\t\t\tconfig.setSoftwareZoomEnabled(useSoftwareZoom);\n\t\t}\n\t}\n\n\t/**\n\t * Enables/disables the zoom in/zoom out animations\n\t * \n\t * @param isEnabled\n\t *            true if you want to enable the animations, false otherwise.\n\t */\n\tpublic void setAnimationEnabled(boolean isEnabled) {\n\t\tthis.isAnimationEnabled = isEnabled;\n\t}\n\n\t/**\n\t * Sets the size of the touch area when user touches the map.\n\t * \n\t * @param pixels\n\t *            radius of the touch area in pixels\n\t */\n\tpublic void setTouchAreaSize(int pixels) {\n\t\tif (config != null) {\n\t\t\tconfig.setTouchAreaSize(pixels);\n\t\t}\n\t}\n\n\t/**\n\t * Zooms map in by one zoom level.\n\t */\n\n\tpublic void zoomIn() {\n\t\tfinal int pivotX = (getWidth() / 2);\n\t\tfinal int pivotY = (getHeight() / 2);\n\n\t\tzoomIn(pivotX, pivotY);\n\t}\n\n\t/**\n\t * Shows current position of the user on the map. You can configure the view\n\t * of the pointer. See MapWidget.getMapGraphicsConfig() for details. You can\n\t * configure the GPS receiver by setting configuration parameters before\n\t * setShowMyPosition is called. See MapWidget.getGPSConfig() for details.\n\t * <p>\n\t * \n\t * In order to calibrate the map you should add the calibration data to the\n\t * map.xml. Calibration data consists of two points - top left and bottom\n\t * right. X and Y is a coordinate of the point in your original map image in\n\t * pixels. lat and lon is latitude and longitude of the same point in real\n\t * world.<br>\n\t * \n\t * <pre>\n\t * For example, your map.xml may look like this:<br>\n\t * {@code\n\t * <Image TileSize=\"256\" Overlap=\"1\" Format=\"png\">\n\t * <Size Width=\"1918\" Height=\"978\"/>\n\t * <CalibrationRect> \n\t * \t<Point x=\"0\" y=\"0\" lat=\"42.924251753870685\" lon=\"-103.99658203125\" topLeft=\"1\"/>\n\t * \t<Point x=\"1918\" y=\"978\" lat=\"40.81380923056961\" lon=\"-98.3056640625\"/>\n\t * </CalibrationRect>\n\t * </Image>\n\t * }\n\t * </pre>\n\t * \n\t * @param show\n\t *            - set true in order to show the position marker on the map,\n\t *            false - in order to hide it.\n\t * @throws java.lang.IllegalStateException\n\t *             () in case if map is not calibrated.\n\t */\n\tpublic void setShowMyPosition(boolean show) {\n\t\tGPSConfig config = getConfig().getGpsConfig();\n\n\t\tif (!config.isMapCalibrated()) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Map is not calibrated in order to use gps positioning\");\n\t\t}\n\n\t\tif (show) {\n\t\t\tMapGraphicsConfig graphics = getConfig().getGraphicsConfig();\n\t\t\tPositionMarker marker = (PositionMarker) topmostLayer\n\t\t\t\t\t.getMapObject(POS_PIN_ID);\n\n\t\t\tif (graphics.getDotPointerDrawableId() != -1) {\n\t\t\t\tDrawable dot = getResources().getDrawable(\n\t\t\t\t\t\tgraphics.getDotPointerDrawableId());\n\t\t\t\tmarker.setDotPointer(dot, PivotFactory.createPivotPoint(dot,\n\t\t\t\t\t\tPivotPosition.PIVOT_CENTER));\n\t\t\t}\n\n\t\t\tif (graphics.getArrowPointerDrawableId() != -1) {\n\t\t\t\tDrawable arrow = getResources().getDrawable(\n\t\t\t\t\t\tgraphics.getArrowPointerDrawableId());\n\t\t\t\tmarker.setArrowPointer(arrow, PivotFactory.createPivotPoint(\n\t\t\t\t\t\tarrow, PivotPosition.PIVOT_CENTER));\n\t\t\t}\n\n\t\t\tmarker.setColor(graphics.getAccuracyAreaColor(),\n\t\t\t\t\tgraphics.getAccuracyAreaBorderColor());\n\n\t\t\tif (locationProvider == null) {\n\t\t\t\tlocationProvider = new GPSLocationProvider(this.getContext());\n\t\t\t\tlocationProvider.setMinRefreshTime(config.getMinTime());\n\t\t\t\tlocationProvider.setMinRefreshDistance(config.getMinDistance());\n\n\t\t\t\tlocationProvider.setMapLocationListener(this);\n\t\t\t}\n\n\t\t\tlocationProvider.start(config.getPassiveMode());\n\t\t} else {\n\t\t\tif (locationProvider != null) {\n\t\t\t\tlocationProvider.stop();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @return instance of MapGraphicsConfig or null, if map was not configured\n\t *         properly\n\t */\n\tpublic MapGraphicsConfig getMapGraphicsConfig() {\n\t\tif (config != null) {\n\t\t\treturn config.getGraphicsConfig();\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns GPSConfig object that will allow you to configure the GPS\n\t * receiver.\n\t * \n\t * @return instance of GPSConfig, or null if map configuration file doesn't\n\t *         contain GPS calibration data or file was not found.\n\t */\n\tpublic GPSConfig getGpsConfig() {\n\t\tif (config != null)\n\t\t\treturn config.getGpsConfig();\n\n\t\treturn null;\n\t}\n\n\tpublic void zoomIn(final int pivotX, final int pivotY) {\n\t\tif (doNotZoom) {\n\t\t\tLog.d(TAG, \"Zoom is in progress. Skipped...\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (config == null) {\n\t\t\tLog.w(TAG, \"Zoom in skipped. Map was not initialized properly\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (!config.isSoftwareZoomEnabled()\n\t\t\t\t&& getZoomLevel() == grid.getMaxZoomLevel()) {\n\t\t\treturn;\n\t\t} else if (config.isSoftwareZoomEnabled()\n\t\t\t\t&& config.getMaxZoomLevelLimit() != 0\n\t\t\t\t&& getZoomLevel() >= config.getMaxZoomLevelLimit()) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (Looper.myLooper() == null) {\n\t\t\tthrow new IllegalThreadStateException(\n\t\t\t\t\t\"Should be called from UI thread\");\n\t\t}\n\n\t\tnotifyAboutPreZoomIn(mapEventsListeners);\n\n\t\tisZooming = true;\n\t\tdoNotZoom = true;\n\n\t\tif (!isAnimationEnabled) {\n\t\t\tdoZoom(getZoomLevel() + 1, pivotX, pivotY);\n\t\t\tisZooming = false;\n\t\t\tdoCorrectPosition();\n\t\t\treturn;\n\t\t}\n\n\t\tperformAfterZoom = new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tdoZoom(getZoomLevel() + 1, pivotX, pivotY);\n\t\t\t\tisZooming = false;\n\t\t\t\tdoCorrectPosition(true);\n\t\t\t}\n\t\t};\n\n\t\tanimateZoomIn(null, pivotX, pivotY);\n\t}\n\n\t/**\n\t * Zooms map out by one zoom level.\n\t */\n\tpublic void zoomOut() {\n\t\tif (doNotZoom) {\n\t\t\tLog.d(TAG, \"Zoom is in progress. Skipped...\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (config == null) {\n\t\t\tLog.w(TAG, \"Zoom in skipped. Map was not initialized properly\");\n\t\t\treturn;\n\t\t}\n\n\t\tint currZoomLevel = getZoomLevel();\n\n\t\tif (currZoomLevel == 0\n\t\t\t\t|| currZoomLevel <= config.getMinZoomLevelLimit()) {\n\t\t\treturn;\n\t\t}\n\n\t\tdoNotZoom = true;\n\n\t\tif (grid == null) {\n\t\t\tLog.w(TAG, \"zoomOut() grid is null\");\n\t\t\tdoNotZoom = false;\n\t\t\treturn;\n\t\t}\n\n\t\tif (Looper.myLooper() == null) {\n\t\t\tthrow new IllegalThreadStateException(\n\t\t\t\t\t\"Should be called from UI thread\");\n\t\t}\n\n\t\tint pivotX = getWidth() / 2;\n\t\tint pivotY = getHeight() / 2;\n\n\t\tnotifyAboutPreZoomOut(mapEventsListeners);\n\n\t\tdoZoom(currZoomLevel - 1, pivotX, pivotY);\n\n\t\tif (!isAnimationEnabled) {\n\t\t\tdoNotZoom = false;\n\t\t\tisZooming = false;\n\t\t\tdoCorrectPosition();\n\t\t\treturn;\n\t\t}\n\n\t\tisZooming = true;\n\n\t\tperformAfterZoom = new Runnable() {\n\t\t\tpublic void run() {\n\t\t\t\tisZooming = false;\n\t\t\t\tdoCorrectPosition(true);\n\t\t\t}\n\t\t};\n\n\t\tanimateZoomOut(null);\n\t}\n\n\t@Override\n\tprotected void onAnimationEnd() {\n\t\tsuper.onAnimationEnd();\n\n\t\tAnimation animation = getAnimation();\n\t\tif (animation == null) {\n\t\t\tLog.w(TAG, \"Unknown animation has been finished.\");\n\t\t}\n\n\t\tif (animation instanceof ScaleAnimation && performAfterZoom != null) {\n\t\t\tperformAfterZoom.run();\n\t\t\tperformAfterZoom = null;\n\t\t}\n\n\t\tif (animation instanceof TranslateAnimation\n\t\t\t\t&& performAfterTranslate != null) {\n\t\t\tperformAfterTranslate.run();\n\t\t\tperformAfterTranslate = null;\n\t\t}\n\n\t}\n\n\t@Override\n\tprotected void onDraw(Canvas canvas) {\n\t\tthis.getDrawingRect(drawingRect);\n\n\t\tif (config != null) {\n\t\t\tif (prevGrid != null) {\n\t\t\t\tprevGrid.draw(canvas, paint, drawingRect);\n\t\t\t}\n\n\t\t\tif (grid != null) {\n\t\t\t\tgrid.draw(canvas, paint, drawingRect);\n\t\t\t}\n\n\t\t\tdrawLayers(canvas, drawingRect);\n\n\t\t\tif (logo != null) {\n\t\t\t\tcanvas.drawBitmap(logo,\n\t\t\t\t\t\tgetWidth() + getScrollX() - logo.getWidth() - 10,\n\t\t\t\t\t\tgetHeight() + getScrollY() - logo.getHeight() - 10,\n\t\t\t\t\t\tnull);\n\t\t\t}\n\t\t} else {\n\t\t\tscrollTo(0, 0);\n\t\t\tdrawMissingDataErrorMessage(canvas);\n\t\t}\n\t}\n\n\tprivate void drawMissingDataErrorMessage(Canvas canvas) {\n\t\tpaint.setTextSize(24);\n\t\tpaint.setStyle(Style.FILL);\n\t\tpaint.setAntiAlias(true);\n\t\tpaint.setSubpixelText(true);\n\t\tpaint.setColor(Color.BLACK);\n\t\tcanvas.drawPaint(paint);\n\n\t\tpaint.setColor(Color.WHITE);\n\t\tRect rect = new Rect();\n\t\tpaint.getTextBounds(MSG_MAP_DATA_IS_CORRUPTED_OR_MISSING, 0,\n\t\t\t\tMSG_MAP_DATA_IS_CORRUPTED_OR_MISSING.length(), rect);\n\n\t\tRect rect2 = canvas.getClipBounds();\n\n\t\tcanvas.drawText(MSG_MAP_DATA_IS_CORRUPTED_OR_MISSING,\n\t\t// (getWidth() - rect.width()) / 2, getHeight() / 2, paint);\n\t\t\t\t(rect2.width() - rect.width()) / 2, rect2.height() / 2, paint);\n\t}\n\n\t@Override\n\tprotected void onLayout(boolean changed, int left, int top, int right,\n\t\t\tint bottom) {\n\t\tsuper.onLayout(changed, left, top, right, bottom);\n\n\t\tif (requestCenterMap) {\n\t\t\trequestCenterMap = false;\n\n\t\t\tfinal ViewTreeObserver observer = this.getViewTreeObserver();\n\t\t\tif (observer.isAlive()) {\n\t\t\t\tobserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void onGlobalLayout() {\n\t\t\t\t\t\tdoCorrectPosition(true, false);\n\t\t\t\t\t\tjumpTo(getOriginalMapWidth() / 2,\n\t\t\t\t\t\t\t\tgetOriginalMapHeight() / 2);\n\n\t\t\t\t\t\tobserver.removeGlobalOnLayoutListener(this);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tdoCorrectPosition(false, false);\n\t\t}\n\t}\n\n\t@Override\n\tprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\t\tsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\t}\n\n\tstatic final MapScrolledEvent scrolledEvent = new MapScrolledEvent(0, 0);\n\n\tprivate DecelerateInterpolator decelerateInterpolator;\n\n\t@Override\n\tprotected void onScrollChanged(int horOrigin, int verOrigin, int oldl,\n\t\t\tint oldt) {\n\t\tsuper.onScrollChanged(horOrigin, verOrigin, oldl, oldt);\n\n\t\tif (mapScrollListener != null) {\n\t\t\tscrolledEvent.setData(oldl - horOrigin, oldt - verOrigin, byUser);\n\t\t\tmapScrollListener.onScrolledEvent(this, scrolledEvent);\n\t\t}\n\t}\n\n\tprotected void animateZoomIn(AnimationListener listener, float pivotX,\n\t\t\tfloat pivotY) {\n\t\tAnimation zoomInAnimation = getZoomInAnimation(pivotX, pivotY);\n\n\t\tif (listener != null) {\n\t\t\tzoomInAnimation.setAnimationListener(listener);\n\t\t}\n\n\t\tthis.startAnimation(zoomInAnimation);\n\t}\n\n\tprotected void animateZoomOut(AnimationListener listener) {\n\t\tAnimation zoomOutAnimation = null;\n\n\t\tif (zoomOutAnimation == null) {\n\t\t\tzoomOutAnimation = getZoomOutAnimation();\n\t\t}\n\n\t\tif (listener != null) {\n\t\t\tzoomOutAnimation.setAnimationListener(listener);\n\t\t}\n\n\t\tthis.startAnimation(zoomOutAnimation);\n\t}\n\n\tprivate void doCorrectPosition() {\n\t\tdoCorrectPosition(false);\n\t}\n\n\tprivate void doCorrectPosition(boolean force) {\n\t\tdoCorrectPosition(force, isAnimationEnabled);\n\t}\n\n\tprivate void doCorrectPosition(boolean force, boolean animate) {\n\t\tif (Looper.myLooper() == null)\n\t\t\tthrow new IllegalThreadStateException(\n\t\t\t\t\t\"Should be called from UI thread\");\n\n\t\tif (grid == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (isZooming)\n\t\t\treturn;\n\n\t\tif (!config.isMapCenteringEnabled() && !force) {\n\t\t\tonPositionCorrected();\n\t\t\treturn;\n\t\t}\n\n\t\tint viewWidth = getWidth();\n\t\tint viewHeight = getHeight();\n\n\t\tfloat fromX = 0.0f;\n\t\tfloat toX = 0.0f;\n\t\tfloat fromY = 0.0f;\n\t\tfloat toY = 0.0f;\n\n\t\tboolean positionCorrected = false;\n\t\tint gridWidth = getMapWidth();\n\t\tint gridHeight = getMapHeight();\n\n\t\tif (gridWidth > viewWidth) {\n\t\t\tint dx2 = gridWidth - getScrollX();\n\n\t\t\tif (getScrollX() < 0) {\n\t\t\t\tfromX = getScrollX() * -1;\n\t\t\t\tscrollTo(0, getScrollY());\n\t\t\t\tpositionCorrected = true;\n\t\t\t} else if (dx2 < viewWidth) {\n\t\t\t\tint gap = viewWidth - dx2;\n\t\t\t\tfromX = -gap;\n\t\t\t\tscrollTo((int) getScrollX() - gap, getScrollY());\n\t\t\t\tpositionCorrected = true;\n\t\t\t}\n\t\t} else {\n\t\t\ttoX = (viewWidth - gridWidth) / 2;\n\t\t\tfromX = ((-getScrollX()) - toX);\n\t\t\tscrollTo(-(int) toX, getScrollY());\n\t\t\tpositionCorrected = true;\n\t\t\ttoX = 0;\n\t\t}\n\n\t\tif (gridHeight > viewHeight) {\n\n\t\t\tint dy2 = gridHeight - getScrollY();\n\n\t\t\tif (getScrollY() < 0) {\n\t\t\t\tfromY = -getScrollY();\n\t\t\t\tscrollTo(getScrollX(), 0);\n\t\t\t\tpositionCorrected = true;\n\t\t\t} else if (dy2 < viewHeight) {\n\t\t\t\tint gap = viewHeight - dy2;\n\t\t\t\tfromY = -gap;\n\t\t\t\tscrollTo((int) getScrollX(), (int) (getScrollY() - gap));\n\t\t\t\tpositionCorrected = true;\n\t\t\t}\n\n\t\t} else {\n\t\t\ttoY = (viewHeight - gridHeight) / 2.0f;\n\t\t\tfromY = ((-getScrollY()) - toY);\n\t\t\tscrollTo(getScrollX(), -(int) toY);\n\t\t\tpositionCorrected = true;\n\t\t\ttoY = 0;\n\t\t}\n\n\t\tif (positionCorrected || force) {\n\n\t\t\tif (animate) {\n\t\t\t\tTranslateAnimation moveAnimation = new TranslateAnimation(\n\t\t\t\t\t\tfromX, toX, fromY, toY);\n\t\t\t\tperformAfterTranslate = new Runnable() {\n\t\t\t\t\tpublic void run() {\n\t\t\t\t\t\tonPositionCorrected();\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\tmoveAnimation.setDuration(500);\n\t\t\t\tmoveAnimation.setInterpolator(decelerateInterpolator);\n\t\t\t\tmoveAnimation.setFillAfter(true);\n\n\t\t\t\tthis.startAnimation(moveAnimation);\n\t\t\t} else {\n\t\t\t\tonPositionCorrected();\n\t\t\t}\n\t\t} else {\n\t\t\tonPositionCorrected();\n\t\t}\n\t}\n\n\tprivate void onPositionCorrected() {\n\t\tgrid.freeResources();\n\n\t\tif (!userTouching) {\n\t\t\ttileProvider.startProcessingCommands();\n\t\t}\n\t}\n\n\tprivate void doZoom(int zoomLevel, int pivotX, int pivotY) {\n\t\tif (grid == null) {\n\t\t\tdoNotZoom = false;\n\t\t\treturn;\n\t\t}\n\n\t\tint maxZoomLevel = OfflineMapUtil.getMaxZoomLevel(\n\t\t\t\tconfig.getImageWidth(), config.getImageHeight());\n\t\tint currZoomLevel = getZoomLevel();\n\n\t\tprevGrid = grid;\n\n\t\tprevGrid.setLoadTiles(false);\n\n\t\tfinal int gWidth = grid.getWidth();\n\t\tfinal int gHeight = grid.getHeight();\n\n\t\tfloat newScale = (float) Math.pow(2, zoomLevel - getZoomLevel());\n\n\t\t// Resolving offsets that we need to move the map in order pivot point\n\t\t// become in the center of the screen.\n\t\tfinal Rect currRect = new Rect(-getScrollX(), -getScrollY(), gWidth\n\t\t\t\t- getScrollX(), gHeight - getScrollY());\n\n\t\tfinal Rect transformed = TransformUtils.scaleRect(currRect, newScale,\n\t\t\t\tpivotX, pivotY);\n\n\t\tboolean zoomIn = zoomLevel > currZoomLevel;\n\n\t\tif ((zoomIn && currZoomLevel < maxZoomLevel)\n\t\t\t\t|| (!zoomIn && currZoomLevel > 0) && scale == 1.0f) {\n\n\t\t\tgrid = new Grid(this, config, tileProvider, zoomLevel);\n\n\t\t\tgrid.setOnReadyListener(new OnGridReadyListener() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onReady() {\n\t\t\t\t\tgrid.setOnReadyListener(null);\n\t\t\t\t\tprevGrid = null;\n\n\t\t\t\t\tif (mapTilesReadyListener != null) {\n\t\t\t\t\t\tmapTilesReadyListener.onMapTilesFinishedLoading();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tprevGrid.setInternalScale(newScale);\n\t\t} else {\n\t\t\tscale *= newScale;\n\n\t\t\tif (prevGrid != null) {\n\t\t\t\tprevGrid = null;\n\t\t\t}\n\n\t\t\tgrid.setOnReadyListener(null);\n\t\t\tgrid.setLoadTiles(false);\n\t\t\tgrid.setInternalScale(scale);\n\t\t\tgrid.setLoadTiles(true);\n\t\t}\n\n\t\tupdateZoomButtons();\n\t\tfloat scale_temp = getScale();\n\t\tsetScaleToOtherDrawables(scale_temp);\n\t\tscrollTo(-transformed.left, -transformed.top);\n\n\t\tdoNotZoom = false;\n\n\t\tif (zoomIn) {\n\t\t\tnotifyAboutPostZoomIn(mapEventsListeners);\n\t\t} else {\n\t\t\tnotifyAboutPostZoomOut(mapEventsListeners);\n\t\t}\n\t}\n\n\tprivate Animation getZoomInAnimation(float pivotX, float pivotY) {\n\t\tfloat fromX = 1.0f;\n\t\tfloat fromY = 1.0f;\n\t\tfloat toX = 2.0f;\n\t\tfloat toY = 2.0f;\n\n\t\tAnimation zoomInAnimation = new ScaleAnimation(fromX, toX, fromY, toY,\n\t\t\t\tpivotX, pivotY);\n\t\tzoomInAnimation.setDuration(500);\n\t\tzoomInAnimation.setInterpolator(decelerateInterpolator);\n\t\tzoomInAnimation.setFillAfter(true);\n\n\t\treturn zoomInAnimation;\n\t}\n\n\tprivate Animation getZoomOutAnimation() {\n\t\tfloat fromX = 2.0f;\n\t\tfloat fromY = 2.0f;\n\t\tfloat toX = 1.0f;\n\t\tfloat toY = 1.0f;\n\t\tfloat pivotX = getWidth() / 2.0f;\n\t\tfloat pivotY = getHeight() / 2.0f;\n\t\tAnimation zoomOutAnimation = new ScaleAnimation(fromX, toX, fromY, toY,\n\t\t\t\tpivotX, pivotY);\n\t\tzoomOutAnimation.setDuration(500);\n\t\tzoomOutAnimation.setInterpolator(decelerateInterpolator);\n\t\tzoomOutAnimation.setFillAfter(true);\n\n\t\treturn zoomOutAnimation;\n\t}\n\n\tstatic final Rect touchRect = new Rect();\n\n\tprivate ArrayList<ObjectTouchEvent> getTouchedElementIds(final int normX,\n\t\t\tfinal int normY) {\n\t\tArrayList<ObjectTouchEvent> result = new ArrayList<ObjectTouchEvent>();\n\n\t\tfloat d = 5.0f;\n\t\tif (config != null) {\n\t\t\td = (float) config.getTouchAreaSize() / 2.0f;\n\t\t}\n\n\t\ttouchRect.set((int) (normX - d), (int) (normY - d), (int) (normX + d),\n\t\t\t\t(int) (normY + d));\n\n\t\tfor (int i = layers.size() - 1; i >= 0; --i) {\n\t\t\tMapLayer layer = layers.get(i);\n\n\t\t\tif (layer.isVisible()) {\n\t\t\t\tArrayList<Object> tempResult = layer.getTouched(touchRect);\n\n\t\t\t\tfor (Object id : tempResult) {\n\t\t\t\t\tObjectTouchEvent touchEvent = new ObjectTouchEvent(id, layer.getId());\n\n\t\t\t\t\tresult.add(touchEvent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate void initializeZoomBtnsController() {\n\t\tzoomBtnsController = new ZoomButtonsController(this);\n\t\tzoomBtnsController.setOnZoomListener(new OnZoomListener()\n\t\t{\n\n\t\t\t@Override\n\t\t\tpublic void onVisibilityChanged(boolean arg0) {\n\t\t\t\t// Left unimplemented\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onZoom(boolean zoomIn) {\n\t\t\t\tif (zoomIn) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tzoomIn();\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tdoNotZoom = false;\n\t\t\t\t\t\tLog.e(\"MapWidget\", \"Exception while zoom in. \" + e);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tzoomOut();\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tdoNotZoom = false;\n\t\t\t\t\t\tLog.e(\"MapWidget\", \"Exception while zoom out. \" + e);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void drawLayers(Canvas canvas, Rect drawingRect) {\n\t\tint size = layers.size();\n\n\t\tfor (int i = 0; i < size; ++i) {\n\t\t\tMapLayer layer = layers.get(i);\n\t\t\tlayer.draw(canvas, drawingRect);\n\t\t}\n\n\t\ttopmostLayer.draw(canvas, drawingRect);\n\t}\n\n\tprivate void setScaleToOtherDrawables(float scale) {\n\t\tint size = layers.size();\n\n\t\ttopmostLayer.setScale(scale);\n\n\t\tfor (int i = 0; i < size; ++i) {\n\t\t\tMapLayer layer = layers.get(i);\n\t\t\tlayer.setScale(scale);\n\t\t}\n\t}\n\n\tprivate float translateXToMapCoordinate(float x) {\n\t\tfloat scale = getScale();\n\n\t\tif (scale != 0) {\n\t\t\treturn (x + (float) getScrollX()) / scale;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tprivate float translateYToMapCoordinate(float y) {\n\t\tfloat scale = getScale();\n\n\t\tif (scale != 0) {\n\t\t\treturn (y + (float) getScrollY()) / scale;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate void updateZoomButtons() {\n\t\tif (config == null || zoomBtnsController == null\n\t\t\t\t|| config.isZoomBtnsVisible() == false)\n\t\t\treturn;\n\n\t\tint currZoomLevel = getZoomLevel();\n\t\tint minZoomLevel = Math.max(config.getMinZoomLevelLimit(),\n\t\t\t\tgrid.getMinZoomLevel());\n\t\tint maxZoomLevel = grid.getMaxZoomLevel();\n\t\tint maxZoomLevelLimit = config.getMaxZoomLevelLimit();\n\n\t\tif (maxZoomLevelLimit != 0 && config.isSoftwareZoomEnabled()) {\n\t\t\tmaxZoomLevel = maxZoomLevelLimit;\n\t\t} else if (maxZoomLevelLimit != 0 && !config.isSoftwareZoomEnabled()) {\n\t\t\tmaxZoomLevel = Math.min(maxZoomLevelLimit, maxZoomLevel);\n\t\t}\n\n\t\tif (currZoomLevel == maxZoomLevel) {\n\t\t\t// At the max zoom level\n\t\t\t// zoomBtnsController.setZoomInEnabled(false);\n\t\t\tzoomBtnsController.setZoomOutEnabled(true);\n\n\t\t\tif (!config.isSoftwareZoomEnabled() || maxZoomLevelLimit != 0) {\n\t\t\t\tzoomBtnsController.setZoomInEnabled(false);\n\t\t\t}\n\n\t\t} else if (currZoomLevel == minZoomLevel) {\n\t\t\t// At the min zoom level\n\t\t\tzoomBtnsController.setZoomInEnabled(true);\n\t\t\tzoomBtnsController.setZoomOutEnabled(scale > 1);\n\t\t} else {\n\t\t\t// In the middle\n\t\t\tzoomBtnsController.setZoomInEnabled(true);\n\t\t\tzoomBtnsController.setZoomOutEnabled(true);\n\t\t}\n\t}\n\n\tprotected void startProcessingRequests() {\n\t\tisDestroying = false;\n\t\tif (!userTouching) {\n\t\t\ttileProvider.startProcessingCommands();\n\t\t}\n\t}\n\n\tprivate static final void notifyAboutPreZoomIn(\n\t\t\tArrayList<MapEventsListener> listeners) {\n\t\tfor (MapEventsListener listener : listeners) {\n\t\t\tif (listener != null) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener.onPreZoomIn();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.e(TAG, \"Exception \" + e + \" on willZoomIn\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tLog.w(TAG, \"WillZoomIn: Map Events listener is null\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static final void notifyAboutPostZoomIn(\n\t\t\tArrayList<MapEventsListener> listeners) {\n\t\tfor (MapEventsListener listener : listeners) {\n\t\t\tif (listener != null) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener.onPostZoomIn();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t\tLog.e(TAG, \"Exception \" + e + \" on didlZoomIn\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tLog.w(TAG, \"DidZoomIn: Map Events listener is null\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static final void notifyAboutPreZoomOut(\n\t\t\tArrayList<MapEventsListener> listeners) {\n\t\tfor (MapEventsListener listener : listeners) {\n\t\t\tif (listener != null) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener.onPreZoomOut();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t\tLog.e(TAG, \"Exception \" + e + \" on willZoomOut\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tLog.w(TAG, \"WillZoomOut: Map Events listener is null\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static final void notifyAboutPostZoomOut(\n\t\t\tArrayList<MapEventsListener> listeners) {\n\t\tfor (MapEventsListener listener : listeners) {\n\t\t\tif (listener != null) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener.onPostZoomOut();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.e(TAG, \"Exception \" + e + \" on didZoomOut\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tLog.w(TAG, \"DidZoomOut: Map Events listener is null\");\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tprotected void onAttachedToWindow() {\n\t\tsuper.onAttachedToWindow();\n\n\t\tif (tileProvider != null) {\n\t\t\ttileProvider.startProcessingCommands();\n\t\t} else {\n\t\t\tLog.e(TAG, \"Tile manager is not initialized\");\n\t\t}\n\t}\n\n\t@Override\n\tprotected void onDetachedFromWindow() {\n\t\tif (zoomBtnsController != null) {\n\t\t\tzoomBtnsController.setVisible(false);\n\t\t}\n\n\t\tif (tileProvider != null) {\n\t\t\ttileProvider.stopProcessingCommands();\n\t\t}\n\n\t\tif (locationProvider != null) {\n\t\t\tlocationProvider.stop();\n\t\t}\n\t\tsuper.onDetachedFromWindow();\n\t}\n\n\t@Override\n\tpublic void computeScroll() {\n\t\tif (scroller.computeScrollOffset()) {\n\t\t\tscrollTo(scroller.getCurrX(), scroller.getCurrY());\n\t\t\tinvalidate();\n\t\t}\n\n\t\tsuper.computeScroll();\n\t}\n\n\t@Override\n\tpublic void onMovePinTo(Location location) {\n\t\tPositionMarker pin = (PositionMarker) topmostLayer\n\t\t\t\t.getMapObject(POS_PIN_ID);\n\n\t\tif (pin != null) {\n\t\t\tpin.setAccuracy(location.getAccuracy());\n\t\t\tpin.setBearing(location.getBearing());\n\t\t\tpin.setBearingEnabled(location.hasBearing());\n\n\t\t\tpin.moveTo(location);\n\t\t}\n\n\t\tnotifyAboutLocationChanged(location);\n\t}\n\n\tprivate void notifyAboutLocationChanged(Location location) {\n\t\tif (locationChangeListener != null) {\n\t\t\ttry {\n\t\t\t\tlocationChangeListener.onLocationChanged(this, location);\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.w(TAG, \"Exception while executing onLocationChanged. \" + e);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Override\n\tpublic void onChangePinVisibility(boolean visible) {\n\t\ttopmostLayer.setVisible(visible);\n\t}\n\n\t/**\n\t * Scrolls the map to current location marker without animation. Location\n\t * marker should be visible in order for this method to work.\n\t */\n\tpublic void jumpToCurrentLocation() {\n\t\tif (!topmostLayer.isVisible()) {\n\t\t\tLog.i(TAG,\n\t\t\t\t\t\"Location marker is not visible. Jump to current location skipped\");\n\t\t\treturn;\n\t\t}\n\n\t\tPositionMarker pin = (PositionMarker) topmostLayer\n\t\t\t\t.getMapObject(POS_PIN_ID);\n\t\tPoint tempPoint = (pin.getPosition());\n\t\tjumpTo(tempPoint);\n\t}\n\n\t/**\n\t * Scrolls the map to current location marker using scroll animation.\n\t * Location marker should be visible in order for this method to work.\n\t */\n\tpublic void scrollToCurrentLocation() {\n\t\tif (!topmostLayer.isVisible()) {\n\t\t\tLog.i(TAG,\n\t\t\t\t\t\"Location pin is not visible. Scroll to current location skipped\");\n\t\t\treturn;\n\t\t}\n\n\t\tPositionMarker pin = (PositionMarker) topmostLayer\n\t\t\t\t.getMapObject(POS_PIN_ID);\n\t\tPoint tempPoint = (pin.getPosition());\n\t\tscrollMapTo(tempPoint);\n\t}\n\n\t/**\n\t * Scrolls the map to specific location without animation.\n\t * \n\t * @param location\n\t *            - instance of {@link android.location.Location} object.\n\t * @throws IllegalStateException\n\t *             if map was not calibrated. For more details see\n\t *             MapWidget.setShowMyPosition().\n\t */\n\tpublic void jumpTo(Location location) {\n\t\tif (config == null) {\n\t\t\tLog.w(TAG, \"Jump to skipped. Map is not initialized properly.\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (!config.getGpsConfig().isMapCalibrated()) {\n\t\t\tthrow new IllegalStateException(\"Map is not calibrated.\");\n\t\t}\n\n\t\tPoint point = new Point();\n\t\tgetGpsConfig().getCalibration().translate(location, point);\n\t\tpoint.set((int) (point.x * getScale()), (int) (point.y * getScale()));\n\n\t\tjumpTo(point);\n\t}\n\n\t/**\n\t * Scrolls the map to specific location.\n\t * \n\t * @param location\n\t *            - instance of Point. The coordinates of the point should be\n\t *            set in pixels in map coordinate system.\n\t */\n\tpublic void jumpTo(Point location) {\n\t\tjumpTo(location.x, location.y);\n\n\t\tdoCorrectPosition(false, false);\n\t}\n\n\t/**\n\t * Scrolls map to specific location\n\t * \n\t * @param x\n\t *            - x coordinate in map coordinate system.\n\t * @param y\n\t *            - y coordinate in map coordinate system.\n\t */\n\tpublic void jumpTo(int x, int y) {\n\t\tint width = getWidth();\n\t\tint height = getHeight();\n\n\t\tscrollTo((int) (x * getScale() - width / 2),\n\t\t\t\t(int) (y * getScale() - height / 2));\n\n\t\tdoCorrectPosition(false, false);\n\t}\n\n\t/**\n\t * Scrolls the map to specific location using scroll animation.\n\t * \n\t * @param location\n\t *            - instance of {@link android.location.Location}.\n\t * @throws IllegalStateException\n\t *             if map is not calibrated. For more details see\n\t *             MapWidget.setShowMyPosition().\n\t */\n\tpublic void scrollMapTo(Location location) {\n\t\tif (config == null) {\n\t\t\tLog.w(TAG, \"Jump to skipped. Map is not initialized properly.\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (!config.getGpsConfig().isMapCalibrated()) {\n\t\t\tthrow new IllegalStateException(\"Map is not calibrated.\");\n\t\t}\n\n\t\tPoint point = new Point();\n\t\tgetGpsConfig().getCalibration().translate(location, point);\n\t\tscrollMapTo(point.x, point.y);\n\t}\n\n\t/**\n\t * Scrolls the map to specific location using scroll animation.\n\t * \n\t * @param location\n\t *            - instance of {@link android.graphics.Point}. Coordinates of\n\t *            the point should be set in pixels in map coordinates.\n\t */\n\tpublic void scrollMapTo(Point location) {\n\t\tscrollMapTo(location.x, location.y);\n\t}\n\n\t/**\n\t * Scrolls the map to specific location using scroll animation.\n\t * \n\t * @param x\n\t *            - x coordinate of the point in map coordinates.\n\t * @param y\n\t *            - y coordinate of the point in map coordinates.\n\t */\n\tpublic void scrollMapTo(int x, int y) {\n\t\tif (!isAnimationEnabled) {\n\t\t\tjumpTo(x, y);\n\t\t\treturn;\n\t\t}\n\n\t\tint viewWidth = getWidth();\n\t\tint viewHeight = getHeight();\n\n\t\tif (isLayoutRequested())\n\t\t\treturn;\n\n\t\tint mapHeight = getMapHeight();\n\t\tint mapWidth = getMapWidth();\n\t\tfloat mapScale = getScale();\n\t\tint scrollX = getScrollX();\n\t\tint scrollY = getScrollY();\n\n\t\tint newX = (int) (x * mapScale) - viewWidth / 2;\n\t\tint newY = (int) (y * mapScale) - viewHeight / 2;\n\n\t\tif (viewHeight < mapHeight && newY + viewHeight > mapHeight) {\n\t\t\tnewY -= (newY + viewHeight - mapHeight);\n\t\t}\n\n\t\tif (mapWidth > viewWidth && newX + viewWidth > mapWidth) {\n\t\t\tnewX -= (newX + viewWidth - mapWidth);\n\t\t}\n\n\t\tif (newX < 0) {\n\t\t\tnewX = 0;\n\t\t}\n\n\t\tif (newY < 0) {\n\t\t\tnewY = 0;\n\t\t}\n\n\t\tif (viewHeight > mapHeight)\n\t\t\tnewY = scrollY;\n\n\t\tif (viewWidth > mapWidth) {\n\t\t\tnewX = scrollX;\n\t\t}\n\n\t\tscroller.abortAnimation();\n\t\tscroller.startScroll(scrollX, scrollY, newX - scrollX, newY - scrollY,\n\t\t\t\t500);\n\t\tinvalidate();\n\t}\n\n\tstatic MapTouchedEvent mapTouchedEvent = new MapTouchedEvent();\n\tprivate class MyGestureDetector extends SimpleOnGestureListener {\n\t\t\n\t\t@Override\n\t\tpublic boolean onDoubleTap(MotionEvent e) {\n\t\t\tboolean result = false;\n\t\t\t\n\t\t\tif (onDoubleTapListener != null) {\n\t\t\t\tupdateMapTouchedEvent(e);\n\t\t\t\tresult = onDoubleTapListener.onDoubleTap(MapWidget.this, mapTouchedEvent);\n\t\t\t}\n\t\t\t\n\t\t\tif (result == false) {\n\t\t\t\tfloat pivotX = e.getX();\n\t\t\t\tfloat pivotY = e.getY();\n\t\t\t\tzoomIn((int) pivotX, (int) pivotY);\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t\t\n\t\t\treturn result;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,\n\t\t\t\tfloat velocityY) {\n\t\t\tif (config == null) {\n\t\t\t\tLog.w(TAG, \"Jump to skipped. Map is not initialized properly.\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (!config.isFlingEnabled() || isZooming) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tint speed = 800;\n\t\t\tif (Math.abs(velocityX) > speed) {\n\t\t\t\tif (velocityX > 0) {\n\t\t\t\t\tvelocityX = speed;\n\t\t\t\t} else {\n\t\t\t\t\tvelocityX = -speed;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Math.abs(velocityY) > speed) {\n\t\t\t\tif (velocityY > 0) {\n\t\t\t\t\tvelocityY = speed;\n\t\t\t\t} else {\n\t\t\t\t\tvelocityY = -speed;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tint minX = 0;\n\t\t\tint minY = 0;\n\t\t\tint maxX = 0;\n\t\t\tint maxY = 0;\n\n\t\t\tif (config.isMapCenteringEnabled()) {\n\t\t\t\tminX = (getWidth() - getMapWidth()) / 2;\n\t\t\t\tminY = (getHeight() - getMapHeight()) / 2;\n\t\t\t\tmaxX = (int) getMapWidth() - getWidth();\n\t\t\t\tmaxY = (int) getMapHeight() - getHeight();\n\n\t\t\t\tif (minX < 0) {\n\t\t\t\t\tminX = 0;\n\t\t\t\t}\n\n\t\t\t\tif (minY < 0) {\n\t\t\t\t\tminY = 0;\n\t\t\t\t}\n\n\t\t\t\tminX *= -1;\n\t\t\t\tminY *= -1;\n\t\t\t} else {\n\t\t\t\tminX = -getMapWidth();\n\t\t\t\tminY = -getMapHeight();\n\t\t\t\tmaxX = getMapWidth();\n\t\t\t\tmaxY = getMapHeight();\n\n\t\t\t\tif (minX > -getWidth()) {\n\t\t\t\t\tminX = -getWidth();\n\t\t\t\t}\n\n\t\t\t\tif (minY > -getHeight()) {\n\t\t\t\t\tminY = -getHeight();\n\t\t\t\t}\n\n\t\t\t\tif (maxY < getHeight()) {\n\t\t\t\t\tmaxY = getHeight();\n\t\t\t\t}\n\n\t\t\t\tif (maxX < getWidth()) {\n\t\t\t\t\tmaxX = getWidth();\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tscroller.fling(getScrollX(), getScrollY(), -(int) (velocityX),\n\t\t\t\t\t-(int) (velocityY), minX, // MinX\n\t\t\t\t\tmaxX, // MaxX\n\t\t\t\t\tminY, // MinY\n\t\t\t\t\tmaxY); // MaxY\n\n\t\t\tinvalidate();\n\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean onDown(MotionEvent e) {\n\t\t\tif (!scroller.isFinished()) { // is flinging\n\t\t\t\tscroller.forceFinished(true); // to stop flinging on touch\n\t\t\t}\n\t\t\treturn true; // else won't work\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean onScroll(MotionEvent e1, MotionEvent e2,\n\t\t\t\tfloat distanceX, float distanceY) {\n\t\t\tif (mode != Mode.NONE || isZooming)\n\t\t\t\treturn false;\n\n\t\t\tscrollBy((int) distanceX, (int) distanceY);\n\n\t\t\t// invalidate();\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic boolean onSingleTapConfirmed(MotionEvent event) {\n\t\t\tif (mapTouchListener != null) {\n\t\t\t\t{\n\t\t\t\t\tupdateMapTouchedEvent(event);\n\n\t\t\t\t\tif (debugEnabled) {\n\t\t\t\t\t\tlastTouchedRect = new RectF(\n\t\t\t\t\t\t\t\ttranslateXToMapCoordinate(event.getX()),\n\t\t\t\t\t\t\t\ttranslateYToMapCoordinate(event.getY()),\n\t\t\t\t\t\t\t\ttranslateXToMapCoordinate(event.getX()) + 10,\n\t\t\t\t\t\t\t\ttranslateYToMapCoordinate(event.getY() + 10));\n\t\t\t\t\t}\n\n\t\t\t\t\tmapTouchListener.onTouch(MapWidget.this, mapTouchedEvent);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\t\n\t\t@Override\n\t\tpublic void onLongPress(MotionEvent e) \n\t\t{\n\t\t\tif (longClickListener != null) {\n\t\t\t\tlongClickListener.onLongClick(MapWidget.this);\n\t\t\t}\n\t\t\t\n\t\t\tif (mapLongClicklistener != null) {\n\t\t\t\tupdateMapTouchedEvent(e);\n\t\t\t\tmapLongClicklistener.onLongClick(MapWidget.this, mapTouchedEvent);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Saves mapWidget internal state, that can be restored from onCreate();\n\t * \n\t * @param bundle\n\t */\n\tpublic void saveState(Bundle bundle) {\n\t\tfloat currPosOnMapX = translateXToMapCoordinate(getWidth() / 2.0f);\n\t\tfloat currPosOnMapY = translateYToMapCoordinate(getHeight() / 2.0f);\n\n\t\tbundle.putFloat(\"com.ls.curPosOnMapX\", currPosOnMapX);\n\t\tbundle.putFloat(\"com.ls.curPosOnMapY\", currPosOnMapY);\n\t\tif (grid != null) {\n\t\t\tbundle.putInt(\"com.ls.zoomLevel\", grid.getZoomLevel());\n\t\t}\n\t\tbundle.putFloat(\"com.ls.scale\", scale);\n\n\t\tLog.d(\"MapWidget\", \"Saved point pos: [\" + currPosOnMapX + \", \"\n\t\t\t\t+ currPosOnMapY + \" ]\");\n\t}\n\n\t/**\n\t * Centers the map.\n\t */\n\tpublic void centerMap() {\n\t\tint width = getWidth();\n\t\tint height = getHeight();\n\n\t\tif (width == 0 || height == 0) {\n\t\t\trequestCenterMap = true;\n\t\t} else {\n\t\t\tdoCorrectPosition(true, isAnimationEnabled);\n\t\t\tjumpTo(getOriginalMapWidth() / 2, getOriginalMapHeight() / 2);\n\t\t}\n\t}\n\t\n\n\tprivate void updateMapTouchedEvent(MotionEvent event) \n\t{\n\t\tArrayList<ObjectTouchEvent> touchedElementIds = getTouchedElementIds(\n\t\t\t\t(int) event.getX() + getScrollX(),\n\t\t\t\t(int) event.getY() + getScrollY());\n\t\t\n\t\tmapTouchedEvent.setScreenX((int) event.getX());\n\t\tmapTouchedEvent.setScreenY((int) event.getY());\n\t\tmapTouchedEvent\n\t\t\t\t.setMapX((int) translateXToMapCoordinate(event\n\t\t\t\t\t\t.getX())); // X coordinate in map's\n\t\t// coordinates\n\t\tmapTouchedEvent\n\t\t\t\t.setMapY((int) translateYToMapCoordinate(event\n\t\t\t\t\t\t.getY())); // Y coordinate in map's\n\t\t// coordinates\n\t\tmapTouchedEvent.setTouchedObjectEvents(touchedElementIds);\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/commands/GetTileTask.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.commands;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport android.content.res.Resources;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.BitmapFactory.Options;\nimport android.graphics.Color;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.ColorDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.TransitionDrawable;\nimport android.os.AsyncTask;\n\npublic class GetTileTask extends AsyncTask<Integer, Integer, Boolean> {\n\n\tprivate InputStream is;\n\tprivate Drawable result;\n\tprivate static final Drawable transparent = new ColorDrawable(Color.TRANSPARENT);\n\t\n\tpublic GetTileTask(InputStream is)\n\t{\n\t\tthis.is = is;\n\t}\n\t\n\t\n\tpublic Drawable getResult()\n\t{\n\t\treturn result;\n\t}\n\t\n\t\n\tpublic void closeStream() throws IOException\n\t{\n         is.close();\n\t}\n\t\n\t@Override\n\tprotected Boolean doInBackground(Integer... params) \n\t{\n\t\tBitmapDrawable tileDrawable = null;\n\t\t\n\t\ttry {\n\t\t\tBitmap bitmap = BitmapFactory.decodeStream(is);\n\t\t\n\t\t\tif (bitmap != null) {\n\t\t\t\ttileDrawable = (BitmapDrawable) new BitmapDrawable(bitmap);\n\t\t\t\tresult = new TransitionDrawable(new Drawable[]{transparent, tileDrawable});\n\t\t\t\tresult.setBounds(0, 0, tileDrawable.getBitmap().getWidth(), tileDrawable.getBitmap().getHeight());\n\t\t\t\treturn Boolean.TRUE;\n\t\t\t} else {\n\t\t\t\treturn Boolean.FALSE;\n\t\t\t}\n\t\t} catch (OutOfMemoryError e) {\n\t\t\treturn Boolean.FALSE;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/commands/MapCommand.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.commands;\n\nimport com.ls.widgets.map.config.OfflineMapConfig;\n\npublic abstract class MapCommand\n\timplements Runnable\n{\n\tprivate OfflineMapConfig config;\n\tprivate MapCommandDelegate delegate;\n\t\n\tpublic MapCommand(OfflineMapConfig config, MapCommandDelegate delegate)\n\t{\n\t\tthis.config = config;\n\t\tthis.delegate = delegate;\n\t}\n\n\tpublic OfflineMapConfig getConfig() {\n\t\treturn config;\n\t}\n\t\n\tpublic void onSuccess(Object data)\n\t{\n\t\tif (delegate != null)\n\t\t\tdelegate.onSuccess(data);\n\t}\n\t\n\tpublic void onError(Exception e)\n\t{\n\t\te.printStackTrace();\n\t\tif (delegate != null)\n\t\t\tdelegate.onError(e);\n\t}\n}\n\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/commands/MapCommandDelegate.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.commands;\n\npublic interface MapCommandDelegate \n{\n\tpublic void onSuccess(Object data);\n\tpublic void onError(Exception e);\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/config/GPSConfig.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.config;\n\nimport com.ls.widgets.map.utils.MapCalibrationData;\n\n/**\n * GPSConfig class allows to configure the location aware aspects of the MapWidget.\n * Do not create this class directly. Instead use MapWidget.getGPSConfig() method.\n */\n\npublic class GPSConfig\n{\n    private final static int DEFAULT_MIN_TIME = 1000;\n    private final static int DEFAULT_MIN_DISTANCE = 10;\n    \n    private boolean passiveMode;\n    private int minTime;\n    private int minDistance;\n    private MapCalibrationData calibrationData;\n    \n    \n    public GPSConfig()\n    {\n        passiveMode = false;\n        minTime = DEFAULT_MIN_TIME;\n        minDistance = DEFAULT_MIN_DISTANCE;\n    }\n \n    \n    public boolean getPassiveMode()\n    {\n        return passiveMode;\n    }\n\n\n    /**\n     * Tells the map to not use GPS by itself, it will use \"passive\" location provider in order to display user's position.\n     * You will need to call this method before call to setShowMyPosition.\n     * @param passiveMode - true if you want the map to work in passive mode, false otherwise.\n     */\n    public void setPassiveMode(boolean passiveMode)\n    {\n        this.passiveMode = passiveMode;\n    }\n\n\n    /**\n     * Sets the calibration data for the map. This calibration data contains the top left and bottom right coordinate of the corners of the map.\n     * @param geoArea - instance of RectGeo class.\n     */\n    public void setGeoArea(MapCalibrationData geoArea) \n    {\n        this.calibrationData = geoArea; \n    }\n    \n    \n    /**\n     * Sets the GPS sensor update time interval and distance.\n     * @param minTime the minimum time interval for notifications, in milliseconds. This field is only used as a hint to conserve power, and actual time between location updates may be greater or lesser than this value.\n     * @param minDistance the minimum distance interval for notifications, in meters\n     */\n    public void setGPSUpdateInterval(int minTime, int minDistance)\n    {\n       this.minTime = minTime;\n       this.minDistance = minDistance;\n    }\n    \n    \n    /**\n     * Returns minimal refresh time in milliseconds.\n     */\n    public int getMinTime()\n    {\n        return minTime;\n    }\n    \n    \n    /**\n     * @return Returns minimal refresh distance in meters. Min distance is a distance that user should pass\n     * in order to receive location update.\n     */\n    public int getMinDistance()\n    {\n        return minDistance;\n    }\n    \n    \n    /**\n     * Returns calibration data for the map.\n     * @return instance of MapCalibratinData.\n     */\n    public MapCalibrationData getCalibration()\n    {\n        return calibrationData;\n    }\n    \n    /**\n     * @return Returns true if config contains calibration data, false otherwise.\n     */\n    public boolean isMapCalibrated()\n    {\n        return calibrationData != null;\n    }\n}\n\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/config/MapConfigParser.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.config;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.FactoryConfigurationError;\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.SAXException;\n\nimport android.content.Context;\nimport android.graphics.Point;\nimport android.graphics.Rect;\nimport android.location.Location;\nimport android.os.Debug;\nimport android.util.DebugUtils;\nimport android.util.Log;\nimport android.util.Pair;\n\nimport com.ls.widgets.map.utils.MapCalibrationData;\n\npublic class MapConfigParser \n{\n\t\n\tprivate int imageWidth;\n\tprivate int imageHeight;\n\tprivate int tileSize;\n\tprivate int overlap;\n\tprivate String imageFormat;\n\tprivate String rootMapFolder;\n\t\n\tprivate MapCalibrationData geoArea;\n\t\n\tpublic MapConfigParser(String mapRoot)\n\t{\n\t\tthis.rootMapFolder = mapRoot;\n\t}\n\n\tpublic OfflineMapConfig parse(Context context, File configFile) throws IOException, SAXException\n\t{   \n        InputStream is = null;\n        \n        try {\n            if (configFile.exists()) { \n                is = new FileInputStream(configFile);\n            \n                return parse(is);\n            } else {\n                Log.e(\"MapConfigParser\", \"Map config file not found.\");\n                return null;\n            }\n        } catch (ParserConfigurationException e) {\n            Log.e(\"MapConfigParser\", \"Exception: \" + e);\n            e.printStackTrace();\n        } catch (FactoryConfigurationError e) {\n            Log.e(\"MapConfigParser\", \"Exception: \" + e);\n            e.printStackTrace();\n        } finally {\n            if (is != null) {\n                is.close();\n            }\n        }\n        \n        return null;\n\t}\n\t\n\tpublic OfflineMapConfig parse(Context context, String configPath) throws IOException, SAXException\n\t{\n\t\tInputStream is = null;\n\n\t\ttry {\n\t\t\tis = context.getAssets().open(configPath);\n            \n\t\t\treturn parse(is);\n\n\t\t} catch (ParserConfigurationException e) {\n\t\t\tLog.e(\"MapConfigParser\", \"Exception: \" + e);\n\t\t\te.printStackTrace();\n\t\t} catch (FactoryConfigurationError e) {\n\t\t\tLog.e(\"MapConfigParser\", \"Exception: \" + e);\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (is != null) {\n\t\t\t\tis.close();\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n\n    private OfflineMapConfig parse(InputStream is) throws ParserConfigurationException, FactoryConfigurationError,\n            SAXException, IOException\n    {\n        DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();\n        Document doc = docBuilder.parse(is); \n        \n        NodeList images = doc.getElementsByTagName(\"Image\");\n        Node image = images.item(0);\n        \n        NamedNodeMap attributes = image.getAttributes();\n        \n        Node tileSizeNode = attributes.getNamedItem(\"TileSize\");\n        Node overlapNode = attributes.getNamedItem(\"Overlap\");\n        Node formatNode = attributes.getNamedItem(\"Format\");\n        \n        Node sizeNode = null;\n        Node geoAreaNode = null;\n        NodeList childNodes = image.getChildNodes();\n        \n        for (int i=0; i<childNodes.getLength(); ++i) {\n        \tNode node = childNodes.item(i);\n        \tif (node != null && node.getNodeName().equals(\"Size\")) {\n        \t\tsizeNode = node;\n        \t}\n        \t\n        \tif (node != null && node.getNodeName().equals(\"CalibrationRect\")) {\n        \t\tgeoAreaNode = node;\n        \t}\n        }\n        \n        attributes = sizeNode.getAttributes();\n        \n        Node widthNode = attributes.getNamedItem(\"Width\");\n        Node heightNode = attributes.getNamedItem(\"Height\");\n        \n        \n        if (geoAreaNode != null) {\n        \tNodeList pointNodes = geoAreaNode.getChildNodes();\n        \t\n        \tPair<Point, Location> topLeft = null;\n        \tPair<Point, Location> bottomRight = null;\n        \t\n        \tfor (int i=0; i<pointNodes.getLength(); ++i) {\n        \t\tNode node = pointNodes.item(i);\n        \t\t\n        \t\tif (node != null && node.getNodeName().equals(\"Point\")) {\n        \t\t\tNamedNodeMap attrs = node.getAttributes();\n        \t\t\tNode topLeftAttr = attrs.getNamedItem(\"topLeft\");\n        \t\t\t\n        \t\t\tNode latNode = attrs.getNamedItem(\"lat\");\n        \t\t\tNode lonNode = attrs.getNamedItem(\"lon\");\n        \t\t\tNode xNode = attrs.getNamedItem(\"x\");\n        \t\t\tNode yNode = attrs.getNamedItem(\"y\");\n        \t\t\t\n        \t\t\tif (latNode != null && lonNode != null) {\n        \t\t\t\tdouble lat = Double.parseDouble(latNode.getNodeValue());\n        \t\t\t\tdouble lon = Double.parseDouble(lonNode.getNodeValue());\n        \t\t\t\tint x = Integer.parseInt(xNode.getNodeValue());\n        \t\t\t\tint y = Integer.parseInt(yNode.getNodeValue());\n        \t\t\t\t\t\n        \t\t\t\tif (topLeftAttr != null && topLeftAttr.getNodeValue().equals(\"1\")) {\n        \t\t\t\t\t// Top left point\n        \t\t\t\t\ttopLeft = new Pair<Point, Location>(new Point(), new Location(\"config\"));\n        \t\t\t\t\ttopLeft.first.set(x, y);\n        \t\t\t\t\ttopLeft.second.setLatitude(lat);\n        \t\t\t\t\ttopLeft.second.setLongitude(lon);\n        \t\t\t\t} else {\n        \t\t\t\t\t// bottom right point\n        \t\t\t\t\tbottomRight = new Pair<Point, Location>(new Point(), new Location(\"config\"));\n        \t\t\t\t\tbottomRight.first.set(x, y);\n        \t\t\t\t\tbottomRight.second.setLatitude(lat);\n        \t\t\t\t\tbottomRight.second.setLongitude(lon);\n        \t\t\t\t}\n        \t\t\t}\n        \t\t}\n        \t}\n        \t\n        \tif (topLeft != null && bottomRight != null) {\n        \t\t\tgeoArea = new MapCalibrationData(topLeft, bottomRight);\n        \t} else {\n        \t\tLog.w(\"MapConfigParser\", \"No geo area is set\");\n        \t}\n        } else {\n        \tLog.w(\"MapConfigParser\", \"GeoArea is not configured.\");\n        }\n\n        \n        if (tileSizeNode != null) {\n        \ttileSize = Integer.parseInt(tileSizeNode.getNodeValue());\n        }\n        \n        if (overlapNode != null) {\n        \toverlap = Integer.parseInt(overlapNode.getNodeValue());\n        }\n        \n        if (formatNode != null) {\n        \timageFormat = formatNode.getNodeValue();\n        }\n        \n        if (widthNode != null) {\n        \timageWidth = Integer.parseInt(widthNode.getNodeValue());\n        }\n        \n        if (heightNode != null) {\n        \timageHeight = Integer.parseInt(heightNode.getNodeValue());\n        }\n        \n        OfflineMapConfig config = new OfflineMapConfig(rootMapFolder, imageWidth, imageHeight, tileSize, overlap, imageFormat);\n        \n        config.getGpsConfig().setGeoArea(geoArea);\n        \n        return config;\n    }\n\t \n\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/config/MapGraphicsConfig.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.config;\n\n/**\n * Allows to configure the appearance of the map aspects.\n */\n\npublic class MapGraphicsConfig \n{\n    public static final int DEFAULT_ACCURACY_AREA_COLOR = 0x331767e9;\n    public static final int DEFAULT_ACCURACY_AREA_BORDER_COLOR = 0xFF1767e9;\n    \n\tprivate int dotPointerDrawableId;\n\tprivate int arrowPointerDrawableId;\n\t\n\tprivate int accuracyAreaColor;\n\tprivate int accuracyAreaBorderColor;\n\t\n\t\n\tpublic MapGraphicsConfig()\n\t{\n\t\tdotPointerDrawableId = -1;\n\t\tarrowPointerDrawableId = -1;\n\t\taccuracyAreaColor = DEFAULT_ACCURACY_AREA_COLOR;\n\t\taccuracyAreaBorderColor = DEFAULT_ACCURACY_AREA_BORDER_COLOR;\n\t}\n\n\t\n\tpublic int getDotPointerDrawableId() \n\t{\n\t\treturn dotPointerDrawableId;\n\t}\n\n\t/**\n\t * Configures the location pointer look when no bearing is available.\n\t * @param dotPointerDrawableId - id of the drawable resource.\n\t */\n\tpublic void setDotPointerDrawableId(int dotPointerDrawableId) \n\t{\n\t\tthis.dotPointerDrawableId = dotPointerDrawableId;\n\t}\n\n\t\n\tpublic int getArrowPointerDrawableId() \n\t{\n\t\treturn arrowPointerDrawableId;\n\t}\n\n\t\n\t/**\n\t * Configures the location pointer look when bearing is available.\n\t * @param dotPointerDrawableId - id of the drawable resource.\n\t */\n\tpublic void setArrowPointerDrawableId(int arrowPointerDrawableId) \n\t{\n\t\tthis.arrowPointerDrawableId = arrowPointerDrawableId;\n\t}\n\n\t\n\tpublic int getAccuracyAreaColor() \n\t{\n\t\treturn accuracyAreaColor;\n\t}\n\n\t\n\t/**\n\t * Configures the accuracy area color of location pointer. Use this template to set the color: 0xAARRGGBB.\n\t * AA - alpha channel, RR - red component, GG - green component, BB - blue component.\n\t * @param accuracyAreaColor - color.\n\t */\n\tpublic void setAccuracyAreaColor(int accuracyAreaColor) \n\t{\n\t\tthis.accuracyAreaColor = accuracyAreaColor;\n\t}\n\n\t\n\tpublic int getAccuracyAreaBorderColor() \n\t{\n\t\treturn accuracyAreaBorderColor;\n\t}\n\n\n\t/**\n\t * Configures the accuracy area border color.\n\t * @param accuracyAreaBorderColor - color.\n\t */\n\tpublic void setAccuracyAreaBorderColor(int accuracyAreaBorderColor) \n\t{\n\t\tthis.accuracyAreaBorderColor = accuracyAreaBorderColor;\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/config/OfflineMap.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.config;\n\npublic class OfflineMap \n{\n\tpublic static final String MAP_ROOT = \"map\";\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/config/OfflineMapConfig.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.config;\n\nimport android.graphics.Rect;\n\npublic class OfflineMapConfig \n{\n    private String rootMapFolder;\n    \n\tprivate int imageWidth;\n\tprivate int imageHeight;\n\t\n\tprivate Rect imageBounds;\n\tprivate int tileSize;\n\tprivate int overlap;\n\tprivate String imageFormat;\n\t\n\tprivate boolean flingEnabled;\n\tprivate boolean mapCenteringEnabled;\n\tprivate boolean pinchZoomEnabled;\n\tprivate boolean zoomBtnsVisible;\n\t\n\tprivate int trackballScrollStepX;\n\tprivate int trackballScrollStepY;\n\t\n\tprivate int minZoomLevelLimit;\n\tprivate int maxZoomLevelLimit;\n\t\n\tprivate int touchAreaSize;\n\t\n\tprivate boolean softwareZoomEnabled;\n\t\n\tprivate GPSConfig gpsConfig;\n\tprivate MapGraphicsConfig mapGraphics;\n\t\n\t\n\tpublic OfflineMapConfig(String rootMapFolder, int imageWidth, int imageHeight, int tileSize, int overlap, String imageFormat)\n\t{\n\t\t// Default values\n\t\tthis.trackballScrollStepX = this.trackballScrollStepY = 64;\n\t\tthis.minZoomLevelLimit = 0;\n\t\tthis.maxZoomLevelLimit = 0;\n\t\tthis.touchAreaSize = 5;\n\t\tthis.softwareZoomEnabled = true;\n\t\tthis.flingEnabled = false;\n\t\tthis.zoomBtnsVisible = true;\n\t\tthis.mapCenteringEnabled = true;\n\t\t\n\t\t// Other values\n\t\tthis.rootMapFolder = rootMapFolder;\n\t\tthis.imageFormat = imageFormat;\n\t\tthis.imageWidth = imageWidth;\n\t\tthis.imageHeight = imageHeight;\n\t\tthis.imageBounds = new Rect(0,0, imageWidth, imageHeight);\n\t\tthis.tileSize = tileSize;\n\t\tthis.overlap = overlap;\n\t\t\n\t\tgpsConfig = new GPSConfig();\n\t\tmapGraphics = new MapGraphicsConfig();\t\n\t}\n\t\n\t\n\tpublic OfflineMapConfig(OfflineMapConfig config)\n\t{\n\t\tthis.rootMapFolder = config.rootMapFolder;\n\t\tthis.imageWidth = config.imageWidth;\n\t\tthis.imageHeight = config.imageHeight;\n\t\tthis.tileSize = config.tileSize;\n\t\tthis.overlap = config.overlap;\n\t\tthis.imageFormat = config.imageFormat;\n\t\tthis.flingEnabled = config.flingEnabled;\n\t\tthis.mapCenteringEnabled = config.mapCenteringEnabled;\n\t\tthis.pinchZoomEnabled = config.pinchZoomEnabled;\n\t\tthis.zoomBtnsVisible = config.zoomBtnsVisible;\n\t\tthis.trackballScrollStepX = config.trackballScrollStepX;\n\t\tthis.trackballScrollStepY = config.trackballScrollStepY;\n\t\tthis.minZoomLevelLimit = config.minZoomLevelLimit;\n\t\tthis.maxZoomLevelLimit = config.maxZoomLevelLimit;\n\t\tthis.softwareZoomEnabled = config.softwareZoomEnabled;\n\t\tthis.touchAreaSize = config.touchAreaSize;\n\t}\n\t\t\n\t/**\n\t * Returns original map image width in pixels \n\t * @return\n\t */\n\tpublic int getImageWidth() \n\t{\n\t\treturn imageWidth;\n\t}\n\n\n\t/**\n\t * Returns original map image height in pixels\n\t * @return\n\t */\n\tpublic int getImageHeight() \n\t{\n\t\treturn imageHeight;\n\t}\n\t\n\t\n\tpublic Rect getImageRect() \n\t{\n\t\treturn imageBounds;\n\t}\n\n\n\t/**\n\t * Returns size of a tile in pixels.\n\t * @return\n\t */\n\tpublic int getTileSize() \n\t{\n\t\treturn tileSize;\n\t}\n\n\n\tpublic int getOverlap() \n\t{\n\t\treturn overlap;\n\t}\n\n\n\tpublic String getImageFormat() \n\t{\n\t\treturn imageFormat;\n\t}\n\n\n\tpublic boolean isFlingEnabled() \n\t{\n\t\treturn flingEnabled;\n\t}\n\n\t\n\t/**\n\t * Controls inertial scrolling.\n\t * @param flingEnabled true to enable fling, false otherwise.\n\t */\n\tpublic void setFlingEnabled(boolean flingEnabled) \n\t{\n\t\tthis.flingEnabled = flingEnabled;\n\t}\n\n\n\tpublic boolean isMapCenteringEnabled()\n\t{\n\t\treturn this.mapCenteringEnabled;\n\t}\n\t\n\t\n\t/**\n\t * Controls the ability to center the map.\n\t * @param enabled - if set to true map will center itself if it is smaller than screen.\n\t */\n\tpublic void setMapCenteringEnabled(boolean enabled)\n\t{\n\t\tthis.mapCenteringEnabled = enabled;\n\t}\n\t\n\t\n\tpublic boolean isPinchZoomEnabled() \n\t{\n\t\treturn pinchZoomEnabled;\n\t}\n\n\n\t/**\n\t * Controls pinch zoom gesture.\n\t * @param pinchZoomEnabled - true to enable pinch zoom gesture, false otherwise.\n\t */\n\tpublic void setPinchZoomEnabled(boolean pinchZoomEnabled) \n\t{\n\t\tthis.pinchZoomEnabled = pinchZoomEnabled;\n\t}\n\n\n\tpublic boolean isZoomBtnsVisible() \n\t{\n\t\treturn zoomBtnsVisible;\n\t}\n\n\n\t/**\n\t * Controls standard zoom buttons visibility.\n\t * @param zoomBtnsVisible - true to make standard zoom buttons visible, false otherwise.\n\t */\n\tpublic void setZoomBtnsVisible(boolean zoomBtnsVisible) \n\t{\n\t\tthis.zoomBtnsVisible = zoomBtnsVisible;\n\t}\n\n\n\tpublic int getTrackballScrollStepX() \n\t{\n\t\treturn trackballScrollStepX;\n\t}\n\n\n\t/**\n\t * Set's track ball scroll step by X axis.\n\t * @param trackballScrollStepX scroll step in pixels.\n\t * @throws IllegalArgumentException if trackballScrollStepX < 0\n\t */\n\tpublic void setTrackballScrollStepX(int trackballScrollStepX) \n\t{\n\t\tif (trackballScrollStepX < 0) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t\t\n\t\tthis.trackballScrollStepX = trackballScrollStepX;\n\t}\n\n\n\tpublic int getTrackballScrollStepY() \n\t{\n\t\treturn trackballScrollStepY;\n\t}\n\n\t\n\t/**\n\t * Set's track ball scroll step by Y axis.\n\t * @param trackballScrollStepY - scroll step in pixels.\n\t * @throws IllegalArgumentException if trackballScrollStepY < 0\n\t */\n\tpublic void setTrackballScrollStepY(int trackballScrollStepY) \n\t{\n\t\tif (trackballScrollStepY < 0) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t\t\n\t\tthis.trackballScrollStepY = trackballScrollStepY;\n\t}\n\n\n\tpublic int getMinZoomLevelLimit() \n\t{\n\t\treturn minZoomLevelLimit;\n\t}\n\n\n\t/**\n\t * Sets minimal zoom level the user can zoom out to.\n\t * @param minZoomLevelLimit - represents zoom level number.\n\t * @throws IllegalArgumentException if minZoomLevelLimit < 0\n\t */\n\tpublic void setMinZoomLevelLimit(int minZoomLevelLimit) \n\t{\n\t\tif (minZoomLevelLimit < 0) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t\t\n\t\tthis.minZoomLevelLimit = minZoomLevelLimit;\n\t}\n\n\n\tpublic int getMaxZoomLevelLimit() \n\t{\n\t\treturn maxZoomLevelLimit;\n\t}\n\n\n\t/**\n\t * Sets max zoom level the user can zoom in to.\n\t * @param maxZoomLevelLimit - zoom level number.\n\t * @throws IllegalArgumentException if maxZoomLevelLimit < 0\n\t */\n\tpublic void setMaxZoomLevelLimit(int maxZoomLevelLimit) \n\t{\n\t\tif (maxZoomLevelLimit < 0) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t\t\n\t\tthis.maxZoomLevelLimit = maxZoomLevelLimit;\n\t}\n\n\t\n\tpublic String getMapRootPath()\n\t{\n\t\treturn rootMapFolder;\n\t}\n\n\t\n\tpublic boolean isSoftwareZoomEnabled() \n\t{\n\t\treturn softwareZoomEnabled;\n\t}\n\n\t\n\t/**\n\t * Controls the ability to use software zoom if there is no zoom levels left during zooming in.  \n\t * @param softwareZoomEnabled - Set true if you want to use software zoom, false otherwise.\n\t */\n\tpublic void setSoftwareZoomEnabled(boolean softwareZoomEnabled) \n\t{\n\t\tthis.softwareZoomEnabled = softwareZoomEnabled;\n\t}\n\n\n\tpublic int getTouchAreaSize()\n\t{\n\t\treturn touchAreaSize;\n\t}\n\n\n\t/**\n\t * Sets touch area size\n\t * @param touchAreaSize - area size in pixels. Used when detecting objects that were hit by the user with a finger.\n\t * @throws IllegalArgumentException when touchAreaSize <= 0\n\t */\n\tpublic void setTouchAreaSize(int touchAreaSize) \n\t{\n\t\tif (touchAreaSize <= 0)\n\t\t\tthrow new IllegalArgumentException();\n\t\t\n\t\tthis.touchAreaSize = touchAreaSize;\n\t}\n\n\n\t/**\n\t * You can use {@link GPSConfig} in order to control GPS sensor settings.\n\t * Please note, that you need to configure the GPS sensor before calling {@code MapWidget.setShowMyPosition(true);} \n\t * @return instance of {@link GPSConfig} class.\n\t */\n    public GPSConfig getGpsConfig()\n    {\n        return gpsConfig;\n    }\n    \n    \n    /**\n     * You can use MapGraphicsConfig in order to configure the look of the position marker.\n     * @return instance of {@link MapGraphicsConfig}\n     */\n    public MapGraphicsConfig getGraphicsConfig()\n    {\n    \treturn mapGraphics;\n    }\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/events/MapScrolledEvent.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.events;\n\n/**\n * Represents scroll event. Event will be fired when map is scrolled.\n */\npublic class MapScrolledEvent \n{\n\tprivate int dx;\n\tprivate int dy;\n\tboolean byUser;\n\t\n\tpublic MapScrolledEvent(int originX, int originY)\n\t{\n\t\tthis.dx = originX;\n\t\tthis.dy = originY;\n\t}\n\t\n\tpublic void setData(int dx, int dy, boolean byUser)\n\t{\n\t    this.dx = dx;\n\t    this.dy = dy;\n\t    this.byUser = byUser;\n\t}\n\t\n\t/**\n\t * @return\n\t * Returns the number of pixels the map was scrolled from it's last position by X axis.\n\t */\n\tpublic int getDX() \n\t{\n\t\treturn dx;\n\t}\n\t\n\t/**\n\t * @return\n\t * Returns the number of pixels the map was scrolled from it's last position by Y axis.\n\t */\t\n\tpublic int getDY() \n\t{\n\t\treturn dy;\n\t}\n\t\n\t/**\n\t * @returns Returns true if map scroll was caused by the user, false otherwise.\n\t */\n\tpublic boolean isByUser()\n\t{\n\t    return byUser;\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/events/MapTouchedEvent.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.events;\n\nimport java.util.ArrayList;\n\n/**\n * <h1>Class Overview</h1><p>\n * MapTouchedEvent represents the touch event that occurs on the map widget.\n * It contains the position of the touch in map coordinates, screen coordinates and a list of object touch events. \n */\npublic class MapTouchedEvent \n{\n\tprivate int screenX;\n\tprivate int screenY;\n\tprivate int mapX;\n\tprivate int mapY;\n\t\n\tprivate ArrayList<ObjectTouchEvent> touchedObjectIds;\n\t\n\t/**\n\t * Returns the X coordinate of a point where user has touched in screen coordinates. \n\t * It means that you can use this value to display something on the screen without coordinate transformation.\n\t * @return X coordinate of a point in screen coordinates.\n\t */\n\tpublic int getScreenX() \n\t{\n\t\treturn screenX;\n\t}\n\t\n\tpublic void setScreenX(int screenX) \n\t{\n\t\tthis.screenX = screenX;\n\t}\n\t\n\t/**\n\t * Returns the Y coordinate of a point where user has touched in screen coordinates. \n\t * It means that you can use this value to display something on the screen without coordinate transformation.\n\t * @return Y coordinate of a point in screen coordinates.\n\t */\n\tpublic int getScreenY() \n\t{\n\t\treturn screenY;\n\t}\n\t\n\tpublic void setScreenY(int screenY) \n\t{\n\t\tthis.screenY = screenY;\n\t}\n\t\n\t/**\n\t * Returns the X coordinate of a point where user has touched in your original image coordinates.\n\t * @return X coordinate of a point in map coordinates.\n\t */\n\tpublic int getMapX() \n\t{\n\t\treturn mapX;\n\t}\n\t\n\tpublic void setMapX(int mapX) \n\t{\n\t\tthis.mapX = mapX;\n\t}\n\t\n\t/**\n\t * Returns the Y coordinate of a point where user has touched in your original image coordinates.\n\t * @return Y coordinate of a point in map coordinates.\n\t */\n\tpublic int getMapY() \n\t{\n\t\treturn mapY;\n\t}\n\t\n\t\n\tpublic void setMapY(int mapY) \n\t{\n\t\tthis.mapY = mapY;\n\t}\n\t\n\t\n\t/**\n\t * @return ArrayList of ObjectTouchEvent objects.\n\t * @deprecated Use getTouchedObjectEvents() instead.\n\t */\n\tpublic ArrayList<ObjectTouchEvent> getTouchedObjectIds() \n\t{\n\t\treturn touchedObjectIds;\n\t}\n\t\n\t\n\t/**\n\t * Returns the list of ObjectTouchEvent objects. If user has touched the map\n\t * where no map objects are located - this will be an empty list. If user\n\t * touched on map object - array will contain ObjectTouchEvent for each\n\t * touched object.\n\t * \n\t * @return ArrayList of ObjectTouchEvent objects.\n\t */\n\tpublic ArrayList<ObjectTouchEvent> getTouchedObjectEvents() \n\t{\n\t\treturn touchedObjectIds;\n\t}\n\t\n\t\n\tpublic void setTouchedObjectEvents(ArrayList<ObjectTouchEvent> touchedObjectIds) \n\t{\n\t\tthis.touchedObjectIds = touchedObjectIds;\n\t}\n\n}\n\n\n\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/events/ObjectTouchEvent.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.events;\n\n/**\n * Object touch event occurs when user touches the map object.\n */\npublic class ObjectTouchEvent\n{\n\tprivate Object objectId;\n\tprivate long layerId;\n\t\n\tpublic ObjectTouchEvent(Object id, long layerId)\n\t{\n\t\tthis.objectId = id;\n\t\tthis.layerId = layerId;\n\t}\n\t\n\t/**\n\t * @return\n\t * Returns the ID of the map object.\n\t */\n\tpublic Object getObjectId() \n\t{\n\t\treturn objectId;\n\t}\n\t\n\t\n\tpublic void setObjectId(Object objectId) \n\t{\n\t\tthis.objectId = objectId;\n\t}\n\t\n\t\n\t/**\n\t * @return\n\t * Returns the ID of the layer where map object is located. \n\t */\n\tpublic long getLayerId() \n\t{\n\t\treturn layerId;\n\t}\n\t\n\t\n\tpublic void setLayerId(int layerId) \n\t{\n\t\tthis.layerId = layerId;\n\t}\n}"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/Layer.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\nimport com.ls.widgets.map.model.MapObject;\n\npublic interface Layer \n{\n\t/**\n\t * Adds map object to the layer.\n\t * @param mapObject - map object.\n\t */\n\tpublic void addMapObject(MapObject mapObject);\n\t\n\t/**\n\t * Removes map object from the layer.\n\t * @param id - id of the map object.\n\t */\n\tpublic void removeMapObject(Object id);\n\t\n\t/**\n\t * Returns map object.\n\t * @param id - id of the map object.\n\t */\n\tpublic MapObject getMapObject(Object id);\n\t\n\n\t/**\n\t * Returns map object by index\n\t * @param index\n\t * @return instance of MapObject\n\t */\n\tpublic MapObject getMapObjectByIndex(int index);\n\t\n\t/**\n\t * Returns the count of map objects on the layer\n\t * @return number of map objects\n\t */\n\tpublic int getMapObjectCount();\n\t\n\t/**\n\t * Removes all map objects from the layer.\n\t */\n\tpublic void clearAll();\n\t\n\t/**\n\t * Shows whether the layer is visible or not.\n\t * @return - true if layer is visible, false otherwise.\n\t */\n\tpublic boolean isVisible();\n\n\t/**\n\t * Sets layer visibility. \n\t * @param visible - true if layer should be visible, false otherwise.\n\t */\n\tpublic void setVisible(boolean visible);\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/MapEventsListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\npublic interface MapEventsListener \n{\n    /**\n     * Is called before zoom in.\n     */\n\tpublic void onPreZoomIn();\n\t\n\t/**\n\t * Is called when zoom in finished.\n\t */\n\tpublic void onPostZoomIn();\n\t\n\t/**\n\t * Is called before zoom out.\n\t */\n\tpublic void onPreZoomOut();\n\t\n\t/**\n\t * Is called when zoom out is finished.\n\t */\n\tpublic void onPostZoomOut();\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/MapLocationListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\nimport android.location.Location;\n\npublic interface MapLocationListener \n{\n\tpublic void onMovePinTo(Location location);\n\tpublic void onChangePinVisibility(boolean visible);\n\t\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/OnGridReadyListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\npublic interface OnGridReadyListener \n{\n\tpublic void onReady();\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/OnLocationChangedListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\nimport com.ls.widgets.map.MapWidget;\n\nimport android.location.Location;\n\npublic interface OnLocationChangedListener\n{\n    public void onLocationChanged(MapWidget v, Location location);\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/OnMapDoubleTapListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.events.MapTouchedEvent;\n\n/**\n * <h1>Interface overview</h1><p>\n * Used for receiving notifications when MapWidget view is double tapped.\n */\npublic interface OnMapDoubleTapListener \n{\n\t/**\n\t * Will be called if user double taps the map widget.\n\t * @param v - map widget that was double tapped.\n\t * @param event - instance of {@link MapTouchedEvent}.\n\t * @return true - if you want to intercept this event and provide your own implementation.<br>\n\t * false - if you want to leave the default map widget behavior.\n\t */\n\tpublic boolean onDoubleTap(MapWidget v, MapTouchedEvent event);\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/OnMapLongClickListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.events.MapTouchedEvent;\n\npublic interface OnMapLongClickListener \n{\n\tpublic boolean onLongClick(MapWidget v, MapTouchedEvent e);\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/OnMapScrollListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.events.MapScrolledEvent;\n\npublic interface OnMapScrollListener \n{\n\tpublic void onScrolledEvent(MapWidget v, MapScrolledEvent event);\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/OnMapTilesFinishedLoadingListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\npublic interface OnMapTilesFinishedLoadingListener \n{\n\tvoid onMapTilesFinishedLoading();\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/OnMapTouchListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.events.MapTouchedEvent;\n\npublic interface OnMapTouchListener \n{\n\tpublic void onTouch(MapWidget v, MapTouchedEvent event); \n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/interfaces/TileManagerDelegate.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.interfaces;\n\nimport android.graphics.drawable.Drawable;\n\npublic interface TileManagerDelegate \n{\n\tpublic void onTileReady(int zoomLevel, int col, int row, Drawable drawable);\n\tpublic void onError(Exception e);\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/location/PositionMarker.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\n\npackage com.ls.widgets.map.location;\n\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.Paint.Style;\nimport android.graphics.Point;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.ShapeDrawable;\nimport android.graphics.drawable.shapes.OvalShape;\nimport android.graphics.drawable.shapes.Shape;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.config.GPSConfig;\nimport com.ls.widgets.map.model.MapObject;\nimport com.ls.widgets.map.utils.MapCalibrationData;\nimport com.ls.widgets.map.utils.PivotFactory;\nimport com.ls.widgets.map.utils.PivotFactory.PivotPosition;\n\npublic class PositionMarker extends MapObject\n{\n    private float accuracy;\n    private float bearing;\n    private boolean hasBearing;\n    \n    private float accuracyRadius;\n    private float pixelsInMeter;\n    private double centerX;\n    private double centerY;\n\n    private ShapeDrawable accuracyDrawable;\n    \n    private Paint accuracyBorderPaint;\n    private Drawable arrowPointerDrawable;\n    private Drawable roundPointerDrawable;\n    \n    private MapWidget context;\n\tprivate Point roundPointerPivotPoint;\n\tprivate Point arrowPointerPivotPoint;\n\n    public PositionMarker(MapWidget context, Object id, Drawable roundPointerDrawable, Drawable arrowPointerDrawable)\n    {\n        super(id, null, new Point(0, 0), false, false);\n        this.context = context;\n        \n        accuracy = 500;\n        pixelsInMeter = 0;\n        \n        hasBearing = false;\n        arrowPointerPivotPoint = null;\n        roundPointerPivotPoint= null;\n        \n        this.context = context;\n        \n        Shape accuracyShape = new OvalShape();\n        accuracyShape.resize(getAccuracyDiameter(), getAccuracyDiameter());\n        \n        accuracyDrawable = new ShapeDrawable(accuracyShape);     \n        this.roundPointerDrawable = roundPointerDrawable;\n        this.arrowPointerDrawable = arrowPointerDrawable;\n        \n        Paint accuracyAreaPaint = accuracyDrawable.getPaint();\n        accuracyAreaPaint.setStyle(Style.FILL);\n\n        accuracyBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        accuracyBorderPaint.setStyle(Style.STROKE);\n        \n        setDrawable(roundPointerDrawable);\n    }\n\n\n    private float calculatePixelsInMeter(MapWidget context)\n    {\n        if (context == null)\n            return 0;\n        \n        GPSConfig config = context.getGpsConfig();\n      \n        if (config != null && config.isMapCalibrated()) {\n        \tMapCalibrationData geoArea = config.getCalibration();\n        \treturn context.getConfig().getImageWidth() / geoArea.getWidthInMeters();\n        }\n        \n        return 0;\n    }\n\n    \n    /**\n     * Sets the color of accuracy area and border.\n     * @param color - Color\n     */\n    public void setColor(int area, int border)\n    {\n        Paint accuracyAreaPaint = accuracyDrawable.getPaint();\n        accuracyAreaPaint.setColor(area);\n        accuracyBorderPaint.setColor(border);\n    }\n\n\n    /**\n     * Sets the size of accuracy area.\n     * @param accuracy - accuracy in meters. You can get this value from android.location.Location\n     * @see android.location.Location\n     */\n    public void setAccuracy(float accuracy)\n    {\n        invalidateSelf();\n\n        this.accuracy = accuracy;\n\n        recalculateBounds();\n\n        invalidateSelf();\n    }\n\n\n    /**\n     * Rotates the position pointer by some degree. In order for this method to take effect you should call\n     * GpsPositionMarker.setBearingEnabled(true)\n     * \n     * @param bearing - GPS bearing angle value in degrees. You can get it from {@link android.location.Location} object.\n     */\n    public void setBearing(float bearing)\n    {\n    \tinvalidateSelf();\n        this.bearing = bearing;\n        invalidateSelf();\n    }\n\n    \n    public void setDotPointer(Drawable dotPointer, Point pivotPoint)\n    {\n    \tthis.roundPointerDrawable = dotPointer;\n    \tthis.roundPointerPivotPoint = pivotPoint;\n    }\n    \n    \n    public void setArrowPointer(Drawable arrowPointer, Point pivotPoint)\n    {\n    \tthis.arrowPointerDrawable = arrowPointer;\n    \tthis.arrowPointerPivotPoint = pivotPoint;\n    }\n    \n    \n    /**\n     * Enables show direction mode.\n     * @param hasBearing - true to show movement direction of false otherwise.\n     */\n    public void setBearingEnabled(boolean hasBearing)\n    {\n        this.hasBearing = hasBearing;\n       \n        if (hasBearing) {\n            setDrawable(arrowPointerDrawable);\n            if (arrowPointerPivotPoint == null) {\n            \tsetPivotPoint(PivotFactory.createPivotPoint(arrowPointerDrawable, PivotPosition.PIVOT_CENTER));\n            } else {\n            \tsetPivotPoint(arrowPointerPivotPoint);\n            }\n        } else {\n            setDrawable(roundPointerDrawable);\n            \n            if (roundPointerPivotPoint == null) {\n            \tsetPivotPoint(PivotFactory.createPivotPoint(roundPointerDrawable, PivotPosition.PIVOT_CENTER));\n            } else {\n            \tsetPivotPoint(roundPointerPivotPoint);\n            }\n        }\n\n        recalculateBounds();\n    }\n\n\n    @Override\n    protected void recalculateBounds()\n    {\n        super.recalculateBounds();\n\n        float r = getAccuracyDiameter() / 2.0f;\n\n        if (accuracyDrawable != null) {\n\n            Rect bounds = super.getBounds();\n\n            float diameter = getAccuracyDiameter();\n            accuracyRadius = diameter / 2.0f;\n            accuracyDrawable.getShape().resize(diameter, diameter);\n\n            centerX = posScaled.x + bounds.width() / 2.0 - pivotPoint.x;\n            centerY = posScaled.y + bounds.height() / 2.0 - pivotPoint.y;\n\n            accuracyDrawable.setBounds((int) (centerX - r),\n                    (int) (centerY - r), (int) (centerX + r),\n                    (int) (centerY + r));\n        }\n    }\n\n\n    @Override\n    public Rect getBounds()\n    {\n        Rect bounds = super.getBounds();\n\n        if ((accuracyRadius * 2.0) >= bounds.width()) {\n            return accuracyDrawable.getBounds();\n        }\n        \n        \n        if (hasBearing) {\n            Rect newBounds = new Rect(bounds);\n            int width = newBounds.width();\n            int height = bounds.height();\n            if ( width > height) {\n                newBounds.bottom = newBounds.top + width;\n                return newBounds;\n            } else if (width > height) {\n                newBounds.right = newBounds.left + height;\n                return newBounds;\n            }\n        }\n\n        return bounds;\n    }\n\n\n    @Override\n    public void draw(Canvas canvas)\n    {\n        if (accuracy > 50.0f) {\n            accuracyDrawable.draw(canvas);\n            canvas.drawCircle((float) centerX, (float) centerY, accuracyRadius - 1,\n                    accuracyBorderPaint);\n        }\n\n        if (!hasBearing) {\n            super.draw(canvas);\n        } else {\n            // Rotate the drawable\n            canvas.save(Canvas.MATRIX_SAVE_FLAG);\n            canvas.rotate(bearing, (float) centerX, (float) centerY);\n            super.draw(canvas);\n            canvas.restore();\n        }\n    }\n\n\n    private float getAccuracyDiameter()\n    {\n        if (pixelsInMeter == 0) {\n            pixelsInMeter = calculatePixelsInMeter(context);\n        }\n        \n        return (accuracy) * pixelsInMeter * scale * 2;\n    }\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/model/Cell.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.model;\n\nimport java.lang.ref.SoftReference;\n\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.Drawable.Callback;\nimport android.graphics.drawable.TransitionDrawable;\nimport android.util.Log;\nimport android.view.View;\n\nimport com.ls.widgets.map.interfaces.TileManagerDelegate;\nimport com.ls.widgets.map.providers.TileProvider;\n\npublic class Cell implements Callback, TileManagerDelegate\n{\n\t// Model\n\tprivate int zoomLevel;\n\tprivate float width;\n\tprivate float height;\n\tprivate int col;\n\tprivate int row;\n\t\n\t// View\n\tprivate Grid parent;\n\tprivate View rootView;\n\tprivate double scale;\n\tprivate float density;\n\tprotected Drawable image;\n\tprivate SoftReference<Drawable> imageCache;\n\tprivate TileProvider tileProvider;\n\tprivate Rect imageBounds;\n\tprivate float x1;\n\tprivate float y1;\n\t\n\t// Controller\n\tprotected boolean invalidateRect;\n\tprivate boolean isImageLoading;\n\tprivate boolean loadImage;\n\tprivate boolean isReady;\n\tprivate String TAG = Cell.class.getSimpleName();\n\tprivate boolean doNotProcessThisCell;\n\t\n\n\tpublic Cell(Grid parent, TileProvider tileProvider, int zoomLevel, int col, int row, int tileSize, double scale)\n\t{\n\t\tdoNotProcessThisCell = false;\n\t\tthis.width = tileSize;\n\t\tthis.height = tileSize;\n\t\tthis.col = col;\n\t\tthis.row = row;\n\t\tthis.scale = scale;\n\t\tthis.zoomLevel = zoomLevel;\n\t\tinvalidateRect = true;\n\t\t\n\t\tthis.parent = parent;\n\t\tthis.rootView = parent.getParentView();\n\t\tthis.tileProvider = tileProvider;\n\t\tloadImage = true;\n\t\t\n\t\tx1 = col * width;\n\t\ty1 = row * height;\n\t\t\n\t\timageBounds = new Rect();\n\t\t\n\t\tdensity = rootView.getResources().getDisplayMetrics().density;\n\n\t\tisImageLoading = false;\n\t\tisReady = false;\n\t}\n\n\t\n\tpublic void cacheImage(float dx, float dy)\n\t{\n\t\tif (image == null) {\n\t\t\tloadImage(dx, dy, false);\n\t\t}\n\t}\n\t\n\t\n\tpublic void draw (Canvas canvas, Paint paint, float dx, float dy) \n\t{\n\t\ttry {\n\t\t\tif (image == null)\n\t\t\t\tloadImage(dx, dy, true);\n\t\t\t\n\t\t\tif (image != null) {\n\t\t\t\t\n\t\t\t\tif (invalidateRect) {\n\t\t\t\t\trecalculateDrawableRect(dx, dy);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\timage.draw(canvas);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t    e.printStackTrace();\n\t\t\tLog.e(\"Cell\", \"Exception during cell painting. E: \" + e);\n\t\t}\n\t}\n\t\n\t\n\tpublic void setLoadImage(boolean loadImage)\n\t{\n\t\tthis.loadImage = loadImage;\n\t}\n\t\n\t\n\tpublic void setScale(double scale)\n\t{\n\t\tthis.scale = scale;\n\t\tinvalidateRect = true;\n\t\t\n\t\tif (image != null) {\n\t\t\trecalculateDrawableRect(0, 0);\n\t\t}\n\t}\n\t\n\t\n\tpublic void freeResources()\n\t{\n\t    imageCache = new SoftReference<Drawable>(image);\n\t\timage = null;\n\t\tinvalidateRect = true;\n\t}\n\t\n\t\n\tprivate void loadImage(final float dx, final float dy, final boolean invalidateOnDownload)\n\t{\n\t\tif (doNotProcessThisCell)\n\t\t\treturn;\n\t\t\n\t\tif (isImageLoading || !loadImage)\n\t\t\treturn;\n\t\t\n\t\tif (imageCache != null) {\n            Drawable cached = imageCache.get();\n            if (cached != null) {\n                processNewTile(0, 0, cached, true);\n                return;\n            }\n\t\t}\n\t\t\n\t\tisImageLoading = true;\n\t\t\n\t\ttileProvider.requestTile(zoomLevel, col, row, this);\n\t}\n\t\n\t private void processNewTile(final float dx, final float dy, Drawable drawable, boolean fromCache)\n     {\n         if (drawable != null) {\n             image = drawable;\n             \n             if (!fromCache) {\n            \t Rect bounds = image.getBounds();\n            \t width = (float)Math.round(bounds.width());\n            \t height = (float)Math.round(bounds.height());\n             } else {\n            \t if (image instanceof TransitionDrawable) {\n            \t\t TransitionDrawable transDrawable = (TransitionDrawable) drawable;\n            \t\t BitmapDrawable tile = (BitmapDrawable) transDrawable.getDrawable(1);\n            \t\t width = tile.getBitmap().getWidth();\n            \t\t height = tile.getBitmap().getHeight();\n            \t }\t \n             }\n\n             recalculateDrawableRect(dx, dy);\n             \n             if (image instanceof TransitionDrawable) {\n                 ((TransitionDrawable) image).setCallback(Cell.this);\n                 ((TransitionDrawable) image).startTransition(150);\n                 \n                 rootView.postDelayed(new Runnable(){public void run(){onIsReady();}}, 150);\n             }\n         }\n     }\n\n\t \n\tprivate void onIsReady() \n\t{\n\t\tisReady = true;\t\n\t\tparent.onCellReady(this);\n\t}\n\t\n\t\n\tprotected void recalculateDrawableRect(final float dx, final float dy) \n\t{\t\n\t\timageBounds.left   = (int)((x1) * scale);\n\t\timageBounds.top    = (int)((y1) * scale);\n\t\timageBounds.right  = (int)((x1 + width) * scale);\n\t\timageBounds.bottom = (int)((y1 + height) * scale);\n\t\t\n\t\timage.setBounds(imageBounds);\t\n\t\tinvalidateRect = false;\n\t}\n\n\n\t@Override\n\tpublic void invalidateDrawable(Drawable who) \n\t{\n\t\tRect bounds = who.getBounds();\n\t\trootView.postInvalidate(bounds.left, bounds.top, bounds.right, bounds.bottom);\n\t}\n\n\n\t@Override\n\tpublic void scheduleDrawable(Drawable who, Runnable what, long when) \n\t{\n\t\trootView.scheduleDrawable(who, what, when);\n\t}\n\n\n\t@Override\n\tpublic void unscheduleDrawable(Drawable who, Runnable what) \n\t{\n\t\trootView.unscheduleDrawable(who, what);\n\t}\n\n\n\tpublic boolean isReady() \n\t{\n\t\treturn isReady;\n\t}\n\n\n\tpublic void setTileProvider(TileProvider tileManager) \n\t{\n\t\tthis.tileProvider = tileManager;\t\n\t}\n\n\n\t@Override\n\tpublic void onTileReady(int zoomLevel, int col, int row, Drawable drawable) {\n\t\tprocessNewTile(0, 0, drawable, false);\n\n\t\t//rootView.postInvalidate(imageBounds.left, imageBounds.top, imageBounds.right, imageBounds.bottom);\n\t\tisImageLoading = false;\n\t}\n\n\n\t@Override\n\tpublic void onError(Exception e) {\n\t\tisImageLoading = false;\n\t\tdoNotProcessThisCell = true;\n\t\tonIsReady();\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/model/Grid.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.model;\n\nimport java.util.ArrayList;\n\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.Point;\nimport android.graphics.Rect;\nimport android.os.Looper;\nimport android.util.Log;\nimport android.view.View;\n\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.interfaces.OnGridReadyListener;\nimport com.ls.widgets.map.providers.TileProvider;\nimport com.ls.widgets.map.utils.OfflineMapUtil;\n\npublic class Grid\n{\t\n\tprivate static final String TAG = \"Grid\";\n\n\t//Tile manager is responsible for managing image tiles and free memory\n\tprivate TileProvider tileProvider;\n\tprivate OnGridReadyListener onReadyListener;\n\t\n\t//View where drawing will be occurred\n\tprivate View parentView;\n\t\n\t//Model of the grid.\n\tprivate ArrayList<Cell>cells;\n\t\n\t//Amount of tile columns\n\tprivate int colCount;\n\t//Amount of tile rows\n\tprivate int rowCount;\n\t//Size of a square tile in pixels\n\tprivate int tileSize;\t\n\t//Zoom level \n\tprivate int zoomLevel;\n\t\n\t//Scale\n\tprivate double softScale;\n\t\n\t//Original image (max zoom) height in pixels\n\tprivate int imageHeight;\n\t//Original image (max zoom) width in pixels\n\tprivate int imageWidth;\n\t//Maximum possible zoom level\n\tprivate int maxZoomLevel;\n\n\t\n\t// For caching purpose only\n\tprivate boolean loadTiles;\n\tprivate Rect cachedDrawRect;\n\tprivate int screenXCapacity;\n\tprivate int screenYCapacity;\n\tprivate Point firstVisibleCell;\n\tprivate Point lastVisibleCell;\n\tprivate Rect gridWindow;\n\tprivate Rect gridWindowBigger;\n\t\n\tprivate int cellsToDrawCount;\n\tprivate int cellsReadyCount;\n\n\tprivate double intScale;\n\n\tprivate double scale;\n\n\tpublic Grid(View parent, OfflineMapConfig config, TileProvider tileProvider, int initZoomLevel)\n\t{\n\t\tthis.zoomLevel = initZoomLevel;\n\t\t\n\t\tthis.imageWidth = config.getImageWidth();\n\t\tthis.imageHeight = config.getImageHeight();\n\t\tthis.maxZoomLevel = OfflineMapUtil.getMaxZoomLevel(imageWidth, imageHeight);\n\t\tthis.softScale = 1.0;\n\t\tthis.intScale = 1.0;\n\t\tthis.scale = 1.0;\n\n\t\tthis.tileSize = config.getTileSize();\n\t\t\n\t\tthis.parentView = parent;\n\t\tthis.tileProvider = tileProvider;\n\t\t\n\t\tloadTiles = true;\n\n\t\trowCount = getRowCount();\n\t\tcolCount = getColCount();\n\t\t\n\t\tcalcCellsInScreen();\n\t\t\n\t\t// Creating the two points here and then reusing them in onDraw() in order to\n\t\t// avoid of extensive use of garbage collector\n\t\tfirstVisibleCell = new Point(0,0);\n\t\tlastVisibleCell = new Point(0,0);\n\t\tgridWindow = new Rect(0,0,0,0);\n\t\tgridWindowBigger = new Rect(0,0,0,0);\n\n\t\tinitGrid(initZoomLevel, tileSize);\n\t}\n\n\n\tprivate void calcCellsInScreen() {\n\t\tscreenXCapacity = (int)(parentView.getWidth() / ((float)tileSize * scale)) / 2;\n\t\tscreenYCapacity = (int)(parentView.getHeight() / ((float)tileSize * scale)) / 2;\n\t}\n\n\t\n\tprivate void initGrid(int zoomLevel, int tileSize) \n\t{\t\n\t\tif (Looper.myLooper() == null) {\n\t\t\tthrow new IllegalThreadStateException(\"Should be called from UI thread\");\n\t\t}\n\t\t\n\t\tint size = colCount*rowCount;\n\t\tcells = new ArrayList<Cell>(size);\n\t\t\n\t\tfor (int i=0; i<size; ++i) {\n\t\t\tint currRow = i/colCount;\n\t\t\tCell cell = new Cell(this, tileProvider, zoomLevel, i - currRow * colCount, currRow, tileSize, scale);\n\t\t\n\t\t\tcells.add(cell);\n\t\t}\n\t\t\n\t}\n\t\n\t\n\tpublic void setTileProvider(TileProvider tileManager)\n\t{\n\t\tfor (Cell cell:cells) {\n\t\t\tcell.setTileProvider(tileManager);\n\t\t}\n\t}\n\t\n\t\n\tpublic void draw(Canvas canvas, Paint paint, Rect drawingRect)\n\t{\n\t\tcachedDrawRect = drawingRect;\n\t\t\n\t\tif (cells == null)\n\t\t\treturn;\n\t\t\n\t\tgridWindow = getGridWindow(/*in*/ drawingRect);\n\t\tgridWindowBigger = getGridWindow(/*in*/ drawingRect);//getRridWindowBigger(gridWindow);\n\t\t\n//\t\tLog.d(TAG, \"Paint window: \" + gridWindow.toShortString() + \"Cache window: \" + gridWindowBigger.toShortString()+\n//\t\t\t\t\" Drawing rect: \" + drawingRect.toShortString() +\n//\t\t\t\t\"Cols: \" + colCount + \" Rows: \" + rowCount);\n//\t\t\n\t\tcellsToDrawCount = 0;\n\t\tcellsReadyCount = 0;\n\t\t\n\n\t\tfor (int row=gridWindowBigger.top; row<=gridWindowBigger.bottom; ++row) {\n\t\t\tfor (int col=gridWindowBigger.left; col<=gridWindowBigger.right; ++col) {\n\t\t\t\t\n\t\t\t\tCell cell = cells.get((int) (col + row*colCount));\n\t\t\t\n\t\t\t\tif (cell != null) {\n\t\t\t\t\tif (col >= gridWindow.left && col <= gridWindow.right &&\n\t\t\t\t\t\t\trow >= gridWindow.top && row <= gridWindow.bottom) {\n\t\t\t\t\t\tcell.draw(canvas, paint, 0, 0);\n\t\t\t\t\t\tif (!cell.isReady()) {\n\t\t\t\t\t\t\tcellsToDrawCount += 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcell.cacheImage(0, 0);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\tprivate Rect getRridWindowBigger(Rect gridWindow) \n\t{\n\t\t\n\t\tgridWindowBigger.left = gridWindow.left - screenXCapacity;\n\t\t\n\t\tif (gridWindowBigger.left < 0)\n\t\t\tgridWindowBigger.left = 0;\n\t\t\n\t\tgridWindowBigger.right = gridWindow.right + screenXCapacity;\n\t\t\n\t\tif (gridWindowBigger.right >= colCount)\n\t\t\tgridWindowBigger.right = colCount - 1;\n\t\t\n\t\tgridWindowBigger.top = gridWindow.top - screenYCapacity;\n\t\t\n\t\tif (gridWindowBigger.top < 0)\n\t\t\tgridWindowBigger.top = 0;\n\n\t\tgridWindowBigger.bottom = gridWindow.bottom + screenYCapacity;\n\t\t\n\t\tif (gridWindowBigger.bottom >= rowCount)\n\t\t\tgridWindowBigger.bottom = rowCount - 1;\n\t\t\n\t\treturn gridWindowBigger;\n\t}\n\n\n\tpublic int getHeight()\n\t{\n\t\treturn (int)Math.ceil(imageHeight * getScale());\n\t}\n\t\n\t\n\tpublic int getOriginalHeight() \n\t{\n\t\treturn imageHeight;\n\t}\n\t\n\t\n\tpublic int getOriginalWidth() \n\t{\n\t\treturn imageWidth;\n\t}\n\n\tpublic double getScale()\n\t{\n\t\tif (maxZoomLevel == zoomLevel)\n\t\t\treturn 1.0f * scale;\n\t\t\n\t\treturn (1.0/(Math.pow(2,maxZoomLevel - zoomLevel)))*scale;\n\t}\n\n\t\n\tpublic int getWidth()\n\t{\n\t\treturn (int) Math.ceil(imageWidth * getScale());\n\t}\n\t\n\t\n\tpublic int getZoomLevel() \n\t{\n\t\treturn zoomLevel;\n\t}\n\t\n\t\n\tpublic int getMaxZoomLevel() \n\t{\n\t\treturn maxZoomLevel;\n\t}\n\t\n\t\n\tpublic View getParentView()\n\t{\n\t\treturn parentView;\n\t}\n\t\n\t\n\tpublic void setLoadTiles(boolean loadTiles)\n\t{\n\t\tapplyLoadTileState(loadTiles);\n\t}\n\t\n\t\n\tpublic boolean isLoadTiles()\n\t{\n\t\treturn this.loadTiles;\n\t}\n\t\n\t\n\tpublic int getMinZoomLevel() \n\t{\n\t\treturn 0;\n\t}\n\t\n\t\n\tpublic void setSoftScale(float newScale)\n\t{\n\t\tif (newScale == 0.0)\n\t\t\tthrow new IllegalArgumentException();\n\t\t\n\t\tthis.softScale = newScale;\n\t\t\n\t\tthis.scale = softScale * intScale;\n\t\t\n\t\tapplyScale(this.scale);\n\t}\n\t\n\t\n\tpublic void setOnReadyListener(OnGridReadyListener listener)\n\t{\n\t\t//tileManager.setOnReadyListener(listener);\n\t\tthis.onReadyListener = listener;\n\t}\n\n\t\n\tprotected int getColCount()\n\t{\n\t\treturn (int)(Math.ceil(((float)OfflineMapUtil.getScaledImageSize(maxZoomLevel, zoomLevel, imageWidth) / (float)tileSize)));\n\t}\n\n\n\tprotected int getRowCount()\n\t{\n\t\treturn (int)((float)Math.ceil(((float)OfflineMapUtil.getScaledImageSize(maxZoomLevel, zoomLevel, imageHeight) / (float)tileSize)));\n\t}\n\n\n\tpublic double getSoftScale() \n\t{\n\t\treturn softScale;\n\t}\n\t\n\n\tprivate Point getBottomRightVisibleCell(Rect drawingRect, Point point) \n\t{\n\t\tif (point == null || drawingRect == null)\n\t\t\tthrow new IllegalArgumentException();\n\t\t\n\t\tPoint topLeft = getTopLeftVisibleCell(drawingRect, point);\n\n\t\tint cols = (int) Math.ceil(((float)drawingRect.width() / ((float)tileSize * scale))) + 2;\n\t\tint rows = (int) Math.ceil(((float)drawingRect.height() / ((float)tileSize * scale))) + 1;\n\t\t\n\t\tpoint.x = topLeft.x + cols;\n\t\tpoint.y = topLeft.y + rows;\n\t\t\n\t\tif (point.x >= colCount)\n\t\t\tpoint.x = colCount-1;\n\t\t\n\t\tif (point.y >= rowCount)\n\t\t\tpoint.y = rowCount-1;\n\t\t\n\t\treturn point;\n\t}\n\t\n\t\n\tprivate Point getTopLeftVisibleCell(Rect drawingRect, Point point) \n\t{\n\t\tif (point == null || drawingRect == null)\n\t\t\tthrow new IllegalArgumentException();\n\t\t\n\t\tpoint.x = (int) Math.floor(((float)drawingRect.left / ((float)tileSize * scale))) - 1;\n\t\tpoint.y = (int) Math.floor(((float)drawingRect.top / ((float)tileSize * scale))) - 1;\n\t\t\n\t\tif (point.x < 0) {\n\t\t\tpoint.x = 0;\n\t\t}\n\t\t\n\t\tif (point.y < 0) {\n\t\t\tpoint.y = 0;\n\t\t}\n\n\t\treturn point;\n\t}\n\t\n\t\n\tprivate synchronized Rect getGridWindow(Rect drawRect)\n\t{\n\t\tif (drawRect == null || firstVisibleCell == null || lastVisibleCell == null) \n\t\t\tthrow new IllegalArgumentException();\n\t\t\n\t\tgetTopLeftVisibleCell(drawRect, firstVisibleCell);\n\t\tgetBottomRightVisibleCell(drawRect, lastVisibleCell);\n\n//\t\twindow.top =  firstVisibleCell.y - screenYCapacity;\n//\t\tif (window.top< 0) window.top= 0;\n//\t\t\n//\t\twindow.left = firstVisibleCell.x - screenYCapacity;\n//\t\tif (window.left < 0) window.left = 0;\n//\t\t\n//\t\twindow.bottom = lastVisibleCell.y + screenYCapacity;\n//\t\tif (window.bottom > rowCount) window.bottom = rowCount;\n//\t\t\n//\t\twindow.right = lastVisibleCell.x + screenYCapacity;\n//\t\tif (window.right > colCount) window.right = colCount;\n\t\t\n//\t\treturn window;\n\t\tgridWindow.top =  firstVisibleCell.y;\n\t\tgridWindow.left = firstVisibleCell.x;\n\t\tgridWindow.bottom = lastVisibleCell.y;\n\t\tgridWindow.right = lastVisibleCell.x;\n\t\t\n\t\treturn gridWindow;\n\t}\n\t\n\t\n\tprivate void applyScale(double scale)\n\t{\n\t\tint size = cells.size();\n\t\tcalcCellsInScreen();\n\n\t\tfor (int i=0; i<size; ++i) {\n\t\t\tCell cell = cells.get(i);\n\t\t\tcell.setScale(scale);\n\t\t}\n\t}\n\t\n\t\n\tprivate void applyLoadTileState(boolean allowTileLoad)\n\t{\n\t\tint size = cells.size();\n\t\t\n\t\tsynchronized (cells) {\n\t\t\tfor (int i=0; i<size; ++i) {\n\t\t\t\tCell cell = cells.get(i);\n\t\t\t\tcell.setLoadImage(allowTileLoad);\n\t\t\t}\t\t\n\t\t}\n\t}\n\n\t\n\tpublic void freeResources()\n\t{\n\t\tif (cachedDrawRect == null)\n\t\t\treturn;\n\t\t\t\t\n\t\tgridWindow = getGridWindow(cachedDrawRect);\n\t\tgridWindowBigger = getRridWindowBigger(gridWindow);\n\t\t\n\t\tfor (int row=0; row<rowCount; ++row) {\n\t\t\tfor (int col=0; col<colCount; ++col) {\n\t\t\t\tif (!(col >= gridWindowBigger.left && col <=gridWindowBigger.right && row >= gridWindowBigger.top && row <= gridWindowBigger.bottom)) {\n\t\t\t\t\tCell cell = cells.get((int) (col + row*colCount));\n\t\t\t\n\t\t\t\t\tif (cell != null) {\n\t\t\t\t\t\tcell.freeResources();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\tvoid onCellReady(Cell cell)\n\t{\n\t\tcellsReadyCount += 1;\n\t\t\n\t\tif (cellsReadyCount == cellsToDrawCount) {\n\t\t\tif (onReadyListener != null) {\n\t\t\t\tLog.d(TAG, \"OnReady!\");\n\t\t\t\tonReadyListener.onReady();\n\t\t\t}\n\t\t}\n\t}\n\n\n\tpublic void setInternalScale(float newScale) \n\t{\n\t\tif (newScale == 0.0)\n\t\t\tthrow new IllegalArgumentException();\n\t\t\n\t\tintScale = newScale;\n\t\t\n\t\tthis.scale = softScale * intScale;\n\t\t\n\t\tapplyScale(this.scale);\n\t}\n\n\n\tpublic double getIntScale() {\n\t\treturn intScale;\n\t}\n\n//\n//\tpublic void setInternalScale(float newScale) {\n//\t\tsoftScale *= newScale;\n//\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/model/MapLayer.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.model;\n\nimport java.util.ArrayList;\n\nimport android.graphics.Canvas;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.Drawable.Callback;\nimport android.os.Looper;\n\nimport com.ls.widgets.map.MapWidget;\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.interfaces.Layer;\n\npublic class MapLayer \n\timplements Layer, Callback\n{\n\tprivate long layerId;\n\tprivate boolean isVisible;\n\t\n\tprivate ArrayList<MapObject> drawables;\n\tprivate ArrayList<MapObject> touchables;\n\t\n\tprotected MapWidget parent;\n\t\n\tpublic MapLayer(long theLayerId, MapWidget parent)\n\t{\n\t\tdrawables = new ArrayList<MapObject>();\n\t\ttouchables = new ArrayList<MapObject>();\n\t\t\n\t\t//Visible by default\n\t\tisVisible = true;\n\t\t\n\t\tthis.layerId = theLayerId;\n\t\tthis.parent = parent;\n\t}\n\t\n\n\t@Override\n\tpublic  void addMapObject(MapObject object)\n\t{\n\t\tif (object == null) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t\t\n\t\tif (Looper.myLooper() == null) {\n\t\t\tthrow new RuntimeException(\"addMapObject should be called from UI thread.\");\n\t\t}\n\t\t\n\t\tobject.setParent(this);\n\t\t\n\t\tobject.setScale(parent.getScale());\n\t\t\n\t\tdrawables.add(object);\n\t\t\n\t\tif (object.isTouchable()) {\n\t\t\ttouchables.add(object);\n\t\t}\n\t\t\n\t\tparent.invalidate(object.getBounds());\n\t}\n\n\n\t@Override\n\tpublic MapObject getMapObject(Object id) \n\t{\n\t\tif (id == null) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t\t\n\t\t// TODO: Re-factor this as this is extremely not efficient\n\t\tfor (MapObject drawable:drawables) {\n\t\t\tif (drawable.getId().equals(id)) {\n\t\t\t\treturn drawable;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n\t\n\t\n\t@Override\n\tpublic MapObject getMapObjectByIndex(int index) \n\t{\n\t\treturn drawables.get(index);\n\t}\n\n\n\t@Override\n\tpublic int getMapObjectCount() \n\t{\n\t\treturn drawables != null?drawables.size():0;\n\t}\n\t\n\t\n\t@Override\n\tpublic void removeMapObject(Object id)\n\t{\n\t\tif (id == null) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t\t\n\t\tif (Looper.myLooper() == null) {\n\t\t\tthrow new RuntimeException(\"removeMapObject should be called from UI thread.\");\n\t\t}\n\t\t\n\t\tMapObject objectToDelete = null;\n\t\tfor (MapObject mapObject:drawables) {\n\t\t\tif (mapObject.getId().equals(id)) {\n\t\t\t\tobjectToDelete = mapObject;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (objectToDelete != null) {\n\t\t\tdrawables.remove(objectToDelete);\n\t\t\ttouchables.remove(objectToDelete);\n\t\t\t\n\t\t\tRect b = objectToDelete.getDrawable().getBounds();\n\t\t\tparent.postInvalidate(b.left, b.top, b.right, b.bottom);\n\t\t}\t\t\t\t\n\t}\n\t\n\t\n//\tpublic ArrayList<Object> getTouched(int normX, int normY)\n//\t{\n//\t\tArrayList<Object> result = new ArrayList<Object>();\n//\t\t\n//\t\tfor (MapObject touchable:touchables) {\n//\t\t\tif (touchable.isTouched(normX, normY)) {\n//\t\t\t\tresult.add(touchable.getId());\n//\t\t\t}\n//\t\t}\n//\t\t\n//\t\treturn result;\n//\t}\n//\t\n\t\n\t/**\n\t * Returns Ids of map object that were touched. Intended for internal use\n\t * @param touchRect\n\t * @return\n\t */\n\tpublic ArrayList<Object> getTouched(Rect touchRect)\n\t{\n\t\tArrayList<Object> result = new ArrayList<Object>();\n\t\t\n\t\tfor (MapObject touchable:touchables) {\n\t\t\tif (touchable.isTouched(touchRect)) {\n\t\t\t\tresult.add(touchable.getId());\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\t\n\t\n\tpublic boolean isVisible()\n\t{\n\t\treturn isVisible;\n\t}\n\n\t\n\tpublic void setVisible(boolean visible)\n\t{\n\t\tisVisible = visible;\n\t}\n\t\n\t\n\tpublic void setScale(float scale)\n\t{\n\t\tint size = drawables.size();\n\t\t\n\t\tfor (int i=0; i < size; ++i) {\n\t\t\tMapObject drawable = drawables.get(i);\n\t\t\tdrawable.setScale(scale);\n\t\t}\n\t}\n\t\n\t\n\tpublic void draw(Canvas canvas, Rect drawingRect)\n\t{\n\t\tif (!isVisible)\n\t\t\treturn;\n\n    \t\tfor (int i=0, size=drawables.size(); i<size; ++i) {\n    \t\t    MapObject object = drawables.get(i);\n    \t\t    \n    \t\t\tif (Rect.intersects(object.getBounds(), drawingRect)) {\n    \t\t\t\tobject.draw(canvas);\n    \t\t\t}\n    \t\t}\n\t}\n\n\n\tpublic void clearAll() \n\t{\n\t\tif (Looper.myLooper() == null) {\n\t\t\tthrow new RuntimeException(\"clearAll should be called from UI thread.\");\n\t\t}\n\t\t\n\t\tdrawables.clear();\n\t\ttouchables.clear();\n\t\tdrawables = null;\n\t\ttouchables = null;\n\t\tdrawables = new ArrayList<MapObject>();\n\t\ttouchables = new ArrayList<MapObject>();\n\t}\n\n\t\n\tpublic boolean equals(Object o)\n\t{\n\t    if (o == null) {\n\t        return false;\n\t    }\n\t    \n\t    if (!(o instanceof MapLayer)) {\n\t        return false;\n\t    }\n\t    \n\t    MapLayer inMapLayer = (MapLayer) o;\n\t    \n\t    return inMapLayer.layerId == this.layerId;\n\t}\n\t\n\t\n\tpublic int hashCode()\n\t{\n\t    return (int)(layerId ^ (layerId >>> 32));\n\t}\n\t\n\n\t// Package access methods\n\t\n\tOfflineMapConfig getConfig()\n\t{\n\t\treturn parent.getConfig();\n\t}\n\t\n\t\n\tvoid invalidate(MapObject object)\n\t{\n\t\tRect bounds = object.getBounds();\n\t\tparent.postInvalidate(bounds.left, bounds.top, bounds.right, bounds.bottom);\n\t}\n\t\n\t\n\tpublic void scheduleDrawable(Drawable who, Runnable what, long when)\n\t{\t\t\n\t\tparent.scheduleDrawable(who, what, when);\n\t}\n\t\n\t\n\tpublic void unscheduleDrawable(Drawable who, Runnable what) {\n\t\tparent.unscheduleDrawable(who, what);\n\t}\n\n\t\n\tpublic void invalidateDrawable(Drawable who) {\n\t\tRect bounds = who.getBounds();\n\t\tparent.postInvalidate(bounds.left, bounds.top, bounds.right, bounds.bottom);\n\t}\n\n\n\tpublic long getId() \n\t{\n\t\treturn layerId;\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/model/MapObject.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.model;\n\nimport android.graphics.Canvas;\nimport android.graphics.Point;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.location.Location;\nimport android.os.Looper;\nimport android.util.Log;\n\nimport com.ls.widgets.map.config.GPSConfig;\nimport com.ls.widgets.map.utils.MapCalibrationData;\n\npublic class MapObject\n{\n\tprotected MapLayer parent;\n\n    protected float scale; // Current map scale    \n   \n    // Pivot point\n    protected Point pivotPoint;\n    \n\tprivate Object id;\n\n\t// Position in map coordinates\n\tprotected Point pos;\n\t// Position in map coordinates taking the scale into account\n\tprotected Point posScaled;\n\t\n    private Drawable drawable;\n\n\tprivate boolean isScalable; // Map object is scalable or not (on map zoom)\n\tprivate boolean isTouchable; // Shows whether this object should respond to touch events.\n\t\n\tprotected Rect touchRect; // Object's touch area.\t\n\n\tpublic MapObject(Object id)\n\t{\n\t\tthis(id, null, 0, 0, false);\n\t}\n\t\n\t\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image.\n\t * @param x  - x coordinate of the object in map coordinates.\n\t * @param y - y coordinate of the object in map coordinates.\n\t */\n\tpublic MapObject(Object id, Drawable drawable, int x, int y)\n\t{\n\t\tthis(id, drawable, x, y, false);\n\t}\n\t\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image\n\t * @param position - coordinate of the object in map coordinates.\n\t */\n\tpublic MapObject(Object id, Drawable drawable, Point position)\n\t{\n\t\tthis(id, drawable, position.x, position.y, false);\n\t}\n\t\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image.\n\t * @param x - x coordinate of the object in map coordinates.\n\t * @param y - y coordinate of the object in map coordinates.\n\t * @param pivotX - x coordinate of pivot point in image coordinates.\n\t * @param pivotY - y coordinate of pivot point in image coordinates.\n\t */\n\tpublic MapObject(Object id, Drawable drawable, int x, int y, int pivotX, int pivotY)\n\t{\n\t\tthis(id, drawable, x, y, pivotX, pivotY, false, false);\n\t}\n\t\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image.\n\t * @param position - coordinate of the object in map coordinates.\n\t * @param pivotPoint - coordinate of the pivot point in image coordinates.\n\t */\n\tpublic MapObject(Object id, Drawable drawable, Point position, Point pivotPoint)\n\t{\n\t\tthis(id, drawable, position.x, position.y, pivotPoint.x, pivotPoint.y);\n\t}\n\t\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image.\n\t * @param x - x coordinate of the object in map coordinates.\n\t * @param y - y coordinate of the object in map coordinates.\n\t * @param isTouchable - true if the object should respond to touch events, false otherwise.\n\t */\n\tpublic MapObject(Object id, Drawable drawable, int x, int y, boolean isTouchable)\n\t{\n\t\tthis(id, drawable, x, y, isTouchable, true);\n\t}\n\t\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image.\n\t * @param position - coordinate of the object in map coordinates.\n\t * @param isTouchable - true if the object should respond to touch events, false otherwise.\n\t */\n\tpublic MapObject (Object id, Drawable drawable, Point position, boolean isTouchable)\n\t{\n\t\tthis(id, drawable, position.x, position.y, true, true);\n\t}\n\t\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image.\n\t * @param position - coordinate of the object in map coordinates.\n\t * @param pivotPoint - coordinate of the pivot point in image coordinates.\n\t * @param isTouchable - true if the object should respond to touch events, false otherwise.\n\t */\n\tpublic MapObject (Object id, Drawable drawable, Point position, Point pivotPoint, boolean isTouchable)\n\t{\n\t\tthis(id, drawable, position.x, position.y, pivotPoint.x, pivotPoint.y, isTouchable, true);\n\t}\n\t\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image.\n\t * @param x - x coordinate of the object in map coordinates.\n\t * @param y - y coordinate of the object in map coordinates.\n\t * @param isTouchable - true if the object should respond to touch events, false otherwise.\n\t * @param isScalable - true, if map object should be scaled on map zoom, false otherwise.\n\t */\n\tpublic MapObject(Object id, Drawable drawable, int x, int y,  boolean isTouchable, boolean isScalable)\n\t{\n\t\tthis(id, drawable, x, y, 0, 0, isTouchable, isScalable);\n\t}\n\t\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image.\n\t * @param position - coordinate of the object in map coordinates.\n\t * @param isTouchable - true if the object should respond to touch events, false otherwise.\n\t * @param isScalable - true, if map object should be scaled on map zoom, false otherwise.\n\t */\n\tpublic MapObject(Object id, Drawable drawable, Point position,  boolean isTouchable, boolean isScalable)\n\t{\n\t\tthis(id, drawable, position.x, position.y, 0, 0, isTouchable, isScalable);\n\t}\n\t\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image.\n\t * @param position - coordinate of the object in map coordinates.\n\t * @param pivotPoint - coordinate of the pivot point in image coordinates.\n\t * @param isTouchable - true if the object should respond to touch events, false otherwise.\n\t * @param isScalable - true, if map object should be scaled on map zoom, false otherwise.\n\t */\n\tpublic MapObject (Object id, Drawable drawable, Point position, Point pivotPoint, boolean isTouchable, boolean isScalable)\n\t{\n\t\tthis(id, drawable, position.x, position.y, pivotPoint.x, pivotPoint.y, isTouchable, isScalable);\n\t}\n\t\n\n\t/**\n\t * Creates new MapObject.\n\t * @param id - id of the object.\n\t * @param drawable - image.\n\t * @param x - x coordinate of the object in map coordinates.\n\t * @param y - y coordinate of the object in map coordinates.\n\t * @param pivotX - x coordinate of pivot point in image coordinates.\n\t * @param pivotY - y coordinate of pivot point in image coordinates.\n\t * @param isTouchable - true if the object should respond to touch events, false otherwise.\n\t * @param isScalable - true, if map object should be scaled on map zoom, false otherwise.\n\t */\n\tpublic MapObject(Object id, Drawable drawable, int x, int y, int pivotX, int pivotY, boolean isTouchable, boolean isScalable)\n\t{\n\t\tthis.id = id;\n\t\tthis.drawable = drawable;\n\t\t\n\t\tpos = new Point(x, y);\n\t\tposScaled = new Point();\n\t\tthis.pivotPoint = new Point(pivotX, pivotY);\n\n\t\tthis.isTouchable = isTouchable;\n\t\tthis.isScalable = isScalable;\n\t\t\n\t\tthis.scale = 1.0f;\n\t\t\n\t\tthis.touchRect = new Rect();\t\n\t}\n\t\n\t\n\t/**\n\t * Returns image that was passed to the constructor.\n\t * @return instance of Drawable.\n\t */\n\tpublic Drawable getDrawable()\n\t{\n\t\treturn drawable;\n\t}\n\t\n\t/**\n\t * Sets object's image.\n\t * @param drawable instance of Drawable.\n\t * @throws IllegalArgumentException when null is set.\n\t */\n\tpublic void setDrawable(Drawable drawable)\n\t{\n\t\tif (drawable == null)\n\t\t\tthrow new IllegalArgumentException();\n\t\t\n\t\tif (Looper.myLooper() == null) \n\t\t\tthrow new IllegalThreadStateException(\"setDrawable should be called from UI thread\");\n\t\t\n\t\tthis.drawable = drawable;\n\t\t\n\t\trecalculateBounds();\n\t}\n\t\n\t\n\t/**\n\t * Draws the map object on the canvas\n\t * @param canvas - Canvas\n\t */\n\tpublic void draw(Canvas canvas)\n\t{\n\t\tif (drawable != null) {\n\t        drawable.draw(canvas);\n\t\t}\n\t}\n\n\t/**\n\t * Returns id of this object\n\t * @return Object that was passed as an id to the constructor.\n\t */\n\tpublic Object getId()\n\t{\n\t\treturn id;\n\t}\n\t\n\t\n\t/**\n\t * Determines whether touch rectangle intersects the bounds of this object.\n\t * Coordinates that are passed in touchRect are the screen coordinates + scroll offset.\n\t * @param touchRect - area inside of the map.\n\t * @return - true if touchRect intersects the map object's touch area, false otherwise.\n\t */\n\tpublic boolean isTouched(Rect touchRect)\n\t{\n\t\treturn Rect.intersects(this.touchRect, touchRect);\n\t}\n\n\t/**\n\t * Returns X coordinate of the map object in map coordinates.\n\t * @return X coordinate taking the map scale into account.\n\t */\n\tpublic int getXScaled() \n\t{\n\t\treturn posScaled.x;\n\t}\n\n\t/**\n\t * Returns Y coordinate of the map object in map coordinates.\n\t * @return Y coordinate taking the map scale into account.\n\t */\n\tpublic int getYScaled() \n\t{\n\t\treturn posScaled.y;\n\t}\n\t\n\t/**\n\t * Returns X coordinate of the map object in map coordinates.\n\t * @return X coordinate of the object.\n\t */\n\tpublic int getX()\n\t{\n\t\treturn pos.x;\n\t}\n\n\t/**\n\t * Returns Y coordinate of the map object in map coordinates.\n\t * @return Y coordinate of the object.\n\t */\n\tpublic int getY()\n\t{\n\t\treturn pos.y;\n\t}\n\t\n\t/**\n\t * Returns position of the map object in map coordinates in pixels of the original image.\n\t * @return instance of {@link android.graphics.Point}. \n\t */\n\tpublic Point getPosition()\n\t{\n\t    return pos;\n\t}\n\t\n\t/**\n\t * Shows whether this object is touchable.\n\t * @return true if this object should respond to touch events, false otherwise.\n\t */\n\tpublic boolean isTouchable()\n\t{\n\t\treturn isTouchable;\n\t}\n\t\n\t/**\n\t * Set's pivot point within the drawable\n\t * @param x - x coordinate in pixels\n\t * @param y - y coordinate in pixels\n\t */\n\tpublic void setPivotPoint(int x, int y)\n\t{\n\t\tpivotPoint.x = x;\n\t\tpivotPoint.y = y;\n\t}\n\t\n\t\n\t/**\n\t * Set's pivot point within the drawable\n\t * @param pivotPoint position of pivot point within the drawable.\n\t * @throws java.lang.IllegalArgumentException if null is passed\n\t */\n\tpublic void setPivotPoint(Point pivotPoint)\n\t{\n\t    if (pivotPoint == null) {\n\t        throw new IllegalArgumentException();\n\t    }\n\t    \n\t    this.pivotPoint = pivotPoint;\n\t}\n\t\n\t\n\t/**\n\t * Returns bounds of the image that represents the map object.\n\t * Note: for efficiency, the returned object may be the same object stored in the drawable (though this is not guaranteed), so if a persistent copy of the bounds is needed, call copyBounds(rect) instead. You should also not change the object returned by this method as it may be the same object stored in the drawable.\n\t * @return instance of Rect with size of the image in pixels taking the scale of the map into account.\n\t */\n\tpublic Rect getBounds()\n\t{\t\n\t    if (drawable != null) {\n\t        return drawable.getBounds();\n\t    } else return null;\n\t}\n\t\n\t\n\t/**\n\t * This method is responsible for calculation of position and size of the map object.\n\t * It will be called when map changes its scale or when other event that may affect the size of the map object occurs.\n\t * It should perform quick and do not contain memory allocations as it may be called pretty often.\n\t */\n\tprotected void recalculateBounds()\n\t{\t\n\t    posScaled.x = (int)(pos.x*scale);\n\t\tposScaled.y = (int)(pos.y*scale);\n\t\n\t\tint width = 0;\n\t\tint height = 0;\n\t\t\n\t\tif (drawable == null)\n\t\t\treturn;\n\n\t\twidth = drawable.getIntrinsicWidth();\n\t\theight = drawable.getIntrinsicHeight();\n\n\t\tif (!isScalable) {\n\t\t\t//ignore scale\t\n\t\t\tdrawable.setBounds(posScaled.x - pivotPoint.x, posScaled.y-pivotPoint.y, posScaled.x + width - pivotPoint.x, \n\t\t\t        posScaled.y + height - pivotPoint.y);\n\t\t} else {\n\t\t\tdrawable.setBounds(posScaled.x - (int)(pivotPoint.x*scale), posScaled.y-(int)(pivotPoint.y*scale), posScaled.x + (int)(width*scale) - (int)(pivotPoint.x*scale), \n\t\t\t        posScaled.y + (int)(height*scale) - (int)(pivotPoint.y*scale));\n\t\t}\n\t\n\t\tif (isTouchable) {\n\t\t    touchRect.set(drawable.getBounds());\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Moves object to another position on the map that is defined in pixels.\n\t * @param x - horizontal coordinate of the object within the map in pixels.\n\t * @param y - vertical coordinate of the object within the map in pixels.\n\t */\n\tpublic void moveTo(int x, int y) \n\t{\n\t\tinvalidateSelf();\n\t\tpos.x = x;\n\t\tpos.y = y;\n\t\trecalculateBounds();\n\n\t\tinvalidateSelf();\n\t}\n\t\n\t\n\t/**\n\t * Moves object to another position on the map that is defined in pixels. In order for this method to work you should \n\t * ensure that geo area is configured in /assets/map/map.xml file.\n\t * @param location - location of the object.\n\t * @throws IllegalStateException if geo area is not configured in map.xml file.\n\t * @see android.location.Location\n\t */\n\tpublic void moveTo(Location location)\n\t{\n\t\tGPSConfig config = parent.getConfig().getGpsConfig();\n\t\t\n\t\tif (!config.isMapCalibrated()) {\n\t\t\tLog.w(\"MapObject\", \"Can't move object to location because map has not been calibrated.\");\n\t\t\tthrow new IllegalStateException(\"Map is not calibrated. Please, add calibration info into map's configuration file.\");\n\t\t}\n\t\t\n\t\tinvalidateSelf();\n\t\n\t\tif (config.isMapCalibrated()) {\n    \t\tMapCalibrationData calibration = config.getCalibration();\n\n    \t\tcalibration.translate(location, pos);\n    \t\t\n    \t\trecalculateBounds();\n    \t\tinvalidateSelf();\n\t\t} \n\t}\n\t\n\t\n\t@Override\n\tpublic boolean equals(Object o) \n\t{\n\t\tif (o == null)\n\t\t\treturn false;\n\t\t\n\t\tif (!(o instanceof MapObject)) {\n\t\t\treturn false;\n\t\t} \n\t\t\n\t\treturn ((MapObject)o).id.equals(this.id); \t\n\t}\n\n\t\n\t@Override\n\tpublic int hashCode() \n\t{\n\t\treturn id.hashCode();\n\t}\n\n\t\n\tprotected void invalidateSelf()\n\t{\n\t\tparent.invalidate(this);\n\t}\n\t\n\t\n\t/*\n\t * Sets the scale for drawable and recalculates bounds.\n\t * Package level visibility. Is called from MapLayer.\n\t */\n\tvoid setScale(float scale)\n\t{\n\t\tthis.scale = scale;\n\t\trecalculateBounds();\n\t}\n\n\t\n\t/*\n\t * Used by the layer to set itself as a parent for this map object.\n\t * Not intended to use by the user.\n\t */\n\tvoid setParent(MapLayer layer)\n\t{\n\t\tthis.parent = layer;\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/model/MapTouchable.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.model;\n\nimport android.graphics.Rect;\n\npublic class MapTouchable\n{\n\tprivate Object id; //Used to identify the touchable\n\tprivate Rect rect; //Used to define the position and a size of the touchable\n\tprivate MapObject drawableRef;\n\t\n\tpublic MapTouchable(Object id, MapObject drawable, Rect rect)\n\t{\n\t\tthis.id = id;\n\t\tthis.rect = rect;\n\t\tdrawableRef = drawable;\n\t}\n\t\n\tpublic Object getId()\n\t{\n\t\treturn id;\n\t}\n\t\n\tpublic boolean isTouched(int x, int y)\n\t{\n\t\treturn rect.contains(x, y);\n\t}\n\t\n\tpublic boolean isTouched(Rect touchRect)\n\t{\n\t\treturn Rect.intersects(rect, touchRect);\n\t}\n\t\n\tpublic MapObject getDrawable()\n\t{\n\t\treturn drawableRef;\n\t}\n\t\n}"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/providers/AssetTileProvider.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.providers;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport android.content.Context;\nimport android.content.res.AssetManager;\n\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.utils.OfflineMapUtil;\n\npublic class AssetTileProvider extends TileProvider\n{\n\tprivate AssetManager assetManager;\n\tprivate StringBuilder sbuilder;\n\t\n\tpublic AssetTileProvider(Context context, OfflineMapConfig config)\n\t{\n\t    super(config);\n\t    \n\t\tthis.assetManager = context.getAssets();\n\t\t\n\t\tsbuilder = new StringBuilder(256);\n\t}\n\t\n    @Override\n    protected InputStream openTile(int zoomLevel, int col, int row) throws IOException\n    {\n        // This is more memory efficient than regular concatenation\n        String filesFolder = OfflineMapUtil.getFilesPath(config.getMapRootPath());\n        sbuilder.delete(0, sbuilder.length());\n        sbuilder.append(filesFolder);\n        sbuilder.append(zoomLevel);\n        sbuilder.append(\"/\");\n        sbuilder.append(col);\n        sbuilder.append(\"_\");\n        sbuilder.append(row);\n        sbuilder.append(\".\");\n        sbuilder.append(config.getImageFormat());\n\n        return assetManager.open(sbuilder.toString());\n    }\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/providers/ExternalStorageTileProvider.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.providers;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.utils.OfflineMapUtil;\n\npublic class ExternalStorageTileProvider extends TileProvider\n{\n    private StringBuilder sbuilder;\n    \n    public ExternalStorageTileProvider(OfflineMapConfig config)\n    {\n        super(config);\n        sbuilder = new StringBuilder();\n    }\n    \n    @Override\n    protected InputStream openTile(int zoomLevel, int col, int row) throws IOException\n    {\n        // This is more memory efficient than regular concatenation\n        String filesFolder = OfflineMapUtil.getFilesPath(config.getMapRootPath());\n        sbuilder.delete(0, sbuilder.length());\n        sbuilder.append(filesFolder);\n        sbuilder.append(zoomLevel);\n        sbuilder.append(\"/\");\n        sbuilder.append(col);\n        sbuilder.append(\"_\");\n        sbuilder.append(row);\n        sbuilder.append(\".\");\n        sbuilder.append(config.getImageFormat());\n\n        File file = new File(sbuilder.toString());\n        if (file.exists()) {\n            return new FileInputStream(file);\n        }\n        \n        return null;\n    }\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/providers/GPSLocationProvider.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.providers;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.location.GpsStatus;\nimport android.location.Location;\nimport android.location.LocationListener;\nimport android.location.LocationManager;\nimport android.location.LocationProvider;\nimport android.os.Bundle;\nimport android.os.SystemClock;\nimport android.util.Log;\n\nimport com.ls.widgets.map.interfaces.MapLocationListener;\n\npublic final class GPSLocationProvider implements LocationListener\n{\n\tprivate static final String TAG = \"GPSLocationProvider\";\n\n\tprivate LocationManager locManager;\n\n\tprivate int refreshRate;\n\tprivate int minDistance;\n\t\n\tprivate MapLocationListener listener;\n\n\tprivate long mLastLocationMillis;\n\tprivate Location mLastLocation;\n\t\n\tprivate boolean isGpsFix;\n\tprivate boolean filterNonGPSFix;\n\t\n\tprivate boolean started;\n\tprivate boolean permGranted;\n\tprivate boolean passiveMode;\n\t\n\tprivate MyGPSListener gpsStatusListener;\n\n\t\n\tpublic GPSLocationProvider(Context context)\n\t{\n\t\tlocManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);\n\t\t\n\t\tstarted = false;\n\t\tpassiveMode = false;\n\t\t\n\t\tgpsStatusListener = new MyGPSListener();\n\t\t\n\t\tPackageManager mgr = context.getPackageManager();\n\t\tif (mgr.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, context.getPackageName()) == PackageManager.PERMISSION_GRANTED) {\n\t\t\tpermGranted = true;\n\t\t} else {\n\t\t\tpermGranted = false;\n\t\t}\n\t}\n\n\t\n\tpublic void setMinRefreshTime(int refreshRate)\n\t{\n\t\tthis.refreshRate = refreshRate;\n\t}\n\t\n\t\n\tpublic void setMinRefreshDistance(int minDistance)\n\t{\n\t\tthis.minDistance = minDistance;\n\t}\n\t\n\n\tpublic void setMapLocationListener(MapLocationListener listener)\n\t{\n\t\tthis.listener = listener;\n\t}\n\t\n\t\n\t/**\n\t * Registers location update listeners.\n\t * @param passiveMode\n\t */\n\tpublic void start(boolean passiveMode)\n\t{\n\t\tif (!permGranted) {\n\t\t\tLog.w(TAG,\"Can't start receiving the location updates. You have no ACCESS_FINE_LOCATION permission enabled.\");\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tif (started) {\n\t\t\tLog.w(TAG, \"Can't start receiving the location updates. Already started.\");\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tstarted = true;\n\t\t\n\t\ttry {\n\t\t\tthis.passiveMode = passiveMode;\n\t\t\t\n\t\t\tif (passiveMode) {\n\t\t\t\tlocManager.requestLocationUpdates(\"passive\", 0, 0, this);\n\t\t\t\tLog.d(TAG, \"Registering for receiving updates from passive provider.\");\n\t\t\t} else {\n\t\t\t\t\n\t\t\t\tlocManager.addGpsStatusListener(gpsStatusListener);\n\t\t\t\t\n\t\t\t\tif (locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {\n\t\t\t\t\tlocManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, refreshRate, minDistance, this);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, refreshRate, minDistance, this);\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\tLocation loc1 = locManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);\n\t\t\tLocation loc2 = locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);\n\t\t\t\n\t\t\tif (loc1 != null && loc2 != null) {\n\t\t\t\tif (loc1.getAccuracy() < loc2.getAccuracy()) {\n\t\t\t\t\tonLocationChanged(loc1);\n\t\t\t\t} else {\n\t\t\t\t\tonLocationChanged(loc2);\n\t\t\t\t}\t\t\t\n\t\t\t} else {\n\t\t\t\tLocation loc = loc1 != null? loc1: loc2;\n\t\t\t\t\n\t\t\t\tif (loc != null) {\n\t\t\t\t\tonLocationChanged(loc);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (listener != null) {\n\t\t\t\tlistener.onChangePinVisibility(true);\n\t\t\t}\n\t\t\t\t\n\t\t} catch (SecurityException e) {\n\t\t\tLog.w(TAG, \"Can't get location provider due to \" + e);\n\t\t}\n\t}\n\t\n\t\n\tpublic void stop()\n\t{\n\t\tlocManager.removeGpsStatusListener(gpsStatusListener);\n\t\tif (listener != null) {\n\t\t\tlistener.onChangePinVisibility(false);\n\t\t}\n\t\tstarted = false;\n\t\tlocManager.removeUpdates(this);\n\t}\n\n\t\n\t@Override\n\tpublic void onLocationChanged(Location location) \n\t{\n\t\tif (location == null) return;\n\t\t\n\t\tif (!passiveMode) {\n\t    \tmLastLocationMillis = SystemClock.elapsedRealtime();\n\n\t\t    if (location.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {\n\t\t    \tif (!filterNonGPSFix) {\n\t\t        \t   \n\t\t    \t\tlistener.onMovePinTo(location);\n\t\t    \t}\n\t\t    } else if (location.getProvider().equals(LocationManager.GPS_PROVIDER)){\n\t\t    \tlistener.onMovePinTo(location);\n\t\t    }\n\t\t    \n\t\t    mLastLocation = location;\n\t    } else {\n\t    \tlistener.onMovePinTo(location);\n\t    }\n\t}\n\n\t\n\t@Override\n\tpublic void onProviderDisabled(String name) {\n\t\tLog.d(TAG, \"Provider disabled: \" + name);\n\t\t\n\t\t\n\t}\n\n\t\n\t@Override\n\tpublic void onProviderEnabled(String name) {\n\t\tLog.d(TAG, \"Provider enabled: \" + name);\n\t\t\n\t\tif (started && !passiveMode) {\n\t\t\tif (name.equals(LocationManager.GPS_PROVIDER)) {\n\t\t\t\tlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, refreshRate, minDistance, this);\n\t\t\t}\n\t\t}\n\t}\n\t\n\n\t@Override\n\tpublic void onStatusChanged(String name, int status, Bundle arg2) \n\t{\n\t\tLog.d(TAG, \"Status of \"+ name + \" changed for \" + statusToString(status));\n\t}\n\t\n\t\n\tprivate String statusToString(int status)\n\t{\n\t\tswitch (status) {\n\t\tcase LocationProvider.OUT_OF_SERVICE:\n\t\t\treturn \"OUT_OF_SERVICE\";\n\t\tcase LocationProvider.TEMPORARILY_UNAVAILABLE:\n\t\t\treturn \"TEMPORARILY_UNAVAILABLE\";\n\t\tcase LocationProvider.AVAILABLE:\n\t\t\treturn \"AVAILABLE:\";\n\t\t}\n\t\t\n\t\treturn \"UNKNOWN\";\n\t}\n\t\n\t\n\tprivate class MyGPSListener implements GpsStatus.Listener {\n\t    public void onGpsStatusChanged(int event) {\n\t    \t\n\t    \tif (passiveMode) {\n\t    \t\treturn;\n\t    \t}\n\t    \t\n\t        switch (event) {\n\t            case GpsStatus.GPS_EVENT_SATELLITE_STATUS:\n\t                if (mLastLocation != null)\n\t                    isGpsFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;\n\n\t                if (isGpsFix) { // A fix has been acquired.\n\t                \tfilterNonGPSFix = true;\n\t                    // Do something.\n\t                } else { // The fix has been lost.\n\t                \tfilterNonGPSFix = false;\n\t                    // Do something.\n\t                }\n\n\t                break;\n\t            case GpsStatus.GPS_EVENT_FIRST_FIX:\n\t                // Do something.\n\t            \tisGpsFix = true;\n\t            \tfilterNonGPSFix = true;\n\n\t                break;\n\t        }\n\t    }\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/providers/TileProvider.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.providers;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.LinkedList;\nimport java.util.Queue;\nimport java.util.concurrent.RejectedExecutionException;\n\nimport android.util.Log;\n\nimport com.ls.widgets.map.commands.GetTileTask;\nimport com.ls.widgets.map.config.OfflineMapConfig;\nimport com.ls.widgets.map.interfaces.TileManagerDelegate;\n\npublic abstract class TileProvider\n{\n    protected static final String TAG = TileProvider.class.getSimpleName();\n\tprotected boolean paused;\n    protected OfflineMapConfig config;\n    protected Queue<GetTileTask> commandQueue;\n\n    public TileProvider(OfflineMapConfig config)\n    {\n        this.config = config;\n        commandQueue = new LinkedList<GetTileTask>();\n    }\n    \n    public void requestTile(final int zoomLevel, final int col, final int row, final TileManagerDelegate delegate)\n    {\n        InputStream is = null;\n       \n        try {\n            is = openTile(zoomLevel, col, row);\n          \n            if (is == null) {\n                delegate.onError(null);\n                return;\n            }\n          \n            GetTileTask task = new GetTileTask(is)\n            {\n                @Override\n                protected void onPostExecute(Boolean result) {\n                    try {\n\t                \tif (result.equals(Boolean.TRUE)) {\n\t                        delegate.onTileReady(zoomLevel, col, row, getResult());\n\t                    } else {\n\t                    \tLog.w(TAG, \"Can't load tile \" + zoomLevel + \"\\\\\" + col + \"_\" + row + \".\" + config.getImageFormat());\n\t                        delegate.onError(null);\n\t                    }\n                    } finally {\n\t                    try {\n\t                       closeStream();\n\t                    } catch (IOException e) {\n\t                        e.printStackTrace();\n\t                        Log.w(TAG, \"Can't close input stream due to exception:\" + e);\n\t                        delegate.onError(null);\n\t                    }\n                    }\n                }\n            };\n            \n            if (paused) {\n                synchronized (commandQueue) {\n                    commandQueue.add(task);\n                }\n                return;\n            }\n            \n            try {\n            \ttask.execute();\n            } catch (RejectedExecutionException e) {\n            \tdelegate.onError(e);\n            }\n        } catch (IOException e){\n            delegate.onError(e);\n        }\n    }\n    \n    \n    protected abstract InputStream openTile(int zoomLevel, final int col, final int row) throws IOException;\n    \n    \n    public void startProcessingCommands()\n    {\t\n    \tthis.paused = false;\n    \t\n    \tsynchronized (commandQueue) {\n    \t\tfor (GetTileTask task:commandQueue) {\n    \t\t\ttask.execute();\n    \t\t}\n    \t\t\n    \t\tcommandQueue.clear();\n    \t}\n    }\n\n    public void pauseProcessingCommands()\n    {\n    \tthis.paused = true;\n    }\n\n    public void stopProcessingCommands()\n    {\n    \tsynchronized (commandQueue) {\n    \t\tcommandQueue.clear();\n    \t}\n    }\n\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/utils/GeoUtils.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.utils;\n\nimport android.graphics.Point;\nimport android.location.Location;\nimport android.util.Log;\n\nimport com.ls.widgets.map.MapWidget;\n\npublic class GeoUtils \n{\n\t\n\t/**\n\t * Helper function to translate position on the map to geographic coordinates. Map should be calibrated in order for \n\t * this method to take effect. Result will be returned in last parameter.\n\t * @param v - com.ls.MapWidget\n\t * @param x - x coordinate in map coordinate system.\n\t * @param y - y coordinate in map coordinate system.\n\t * @param location - out parameter. Will contain latitude and longitude of point on the map.\n\t */\n\tpublic static void translate(MapWidget v, int x, int y, Location location)\n\t{\n\t\tMapCalibrationData calibration = v.getConfig().getGpsConfig().getCalibration();\n\t\t\n\t\tif (calibration == null) {\n\t\t\tLog.w(\"GeoUtils\", \"Can't translate. No calibration data!\");\n\t\t}\n\t\t\n\t\tcalibration.translate(x, y, location);\n\t}\n\t\n\t\n\t/**\n\t * Helper function to convert position on the map to geographic coordinates. Result will be returned in last parameter.\n\t * @param v - com.ls.MapWidget\n\t * @param point - position on the map in pixels. Instance of android.graphics.Point\n\t * @param location - out parameter. Will contain latitude and longitude of point on the map.\n\t */\n\tpublic static void translate(MapWidget v, Point point, Location location)\n\t{\n\t\tMapCalibrationData calibration = v.getConfig().getGpsConfig().getCalibration();\n\t\t\n\t\tif (calibration == null) {\n\t\t\tLog.w(\"GeoUtils\", \"Can't translate. No calibration data!\");\n\t\t}\n\t\t\n\t\tcalibration.translate(point.x, point.y, location);\n\t}\n\t\n\t\n\t/**\n\t * Converts location to position on the map. Result will be returned in last parameter.\n\t * @param v - com.ls.MapWidget\n\t * @param location instance of android.location.Location object.\n\t * @param position - out parameter. Can be null.\n\t * @return returns the same object that was passed as position, or if it is null - returns new Point object.\n\t */\n\tpublic static void translate(MapWidget v, Location location, Point point)\n\t{\n\t\tMapCalibrationData calibration = v.getConfig().getGpsConfig().getCalibration();\n\t\t\n\t\tif (calibration == null) {\n\t\t\tLog.w(\"GeoUtils\", \"Can't translate. No calibration data!\");\n\t\t}\n\t\t\n\t\tcalibration.translate(location, point);\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/utils/Graphics.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.utils;\n\npublic final class Graphics {\n\tpublic final static byte BLUE_DOT[] = {-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 22, 0, 0, 0, 22, 8, 6, 0, 0, 0, -60, -76, 108, 59, 0, 0, 0, 1, 115, 82, 71, 66, 0, -82, -50, 28, -23, 0, 0, 0, 6, 98, 75, 71, 68, 0, -1, 0, -1, 0, -1, -96, -67, -89, -109, 0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 11, 19, 0, 0, 11, 19, 1, 0, -102, -100, 24, 0, 0, 0, 7, 116, 73, 77, 69, 7, -37, 10, 29, 12, 6, 21, 110, 115, 107, -90, 0, 0, 5, 64, 73, 68, 65, 84, 56, -53, 125, -107, -55, -113, 92, 103, 21, -59, -49, -3, -90, 55, -44, 123, 85, -81, -70, 29, -9, -28, -10, -40, 114, 2, -119, -80, 49, -34, -64, -118, 29, 59, -60, 36, -40, -124, 21, 11, 118, 100, -111, 13, 127, 8, 11, 54, -39, 0, 11, -110, 69, 8, 34, 65, 68, 24, 41, -96, -56, 66, 14, -120, -104, 6, 55, 118, -20, -74, 122, -118, -37, 93, -43, 85, -43, 53, -67, -31, 27, 46, -117, 38, 36, 66, 50, 87, -70, -101, 43, -99, -77, 56, 58, -6, 93, -62, 51, -26, -6, -75, 31, -21, -94, 40, 90, 76, 33, -78, -42, -23, -70, 118, -62, 24, 4, 41, -31, -125, -29, 106, 56, -24, 77, -73, -18, -1, -44, 62, 75, 79, -1, 123, -40, -40, -8, 81, -53, 54, -19, -53, -25, -49, -81, 124, -83, -35, 73, -65, 14, -30, 69, -21, -126, 110, 26, -124, -56, -80, 80, -118, 44, 59, -22, -113, -122, -45, -73, -10, -10, 15, -2, -96, -93, -29, -57, -37, -37, -81, 77, -2, -81, -15, -91, -11, 87, 47, -89, 89, -15, -67, -107, -75, -27, 43, -21, 23, -98, -5, -30, -39, -91, -4, 70, -106, 107, -104, 72, -126, 0, 48, 24, 85, -23, 48, 26, 88, 60, 61, 28, -1, 101, 127, -81, 127, -73, 127, -12, 116, 123, 54, 61, 122, 125, 103, -1, 39, -113, 62, -21, -91, 0, 96, -3, -36, -73, 73, -118, -75, 85, 29, 21, -33, -115, -45, -10, 15, -105, 87, 23, 47, 108, -68, -80, -126, -49, -67, -76, -116, -107, -75, 54, -70, 11, 17, 71, 17, -95, -84, 2, 122, 71, 21, -19, 60, 62, -63, -67, -51, 39, 55, 43, 27, 110, -114, 39, -27, -74, 117, -63, -98, 91, 121, -7, -105, -77, 114, 115, 127, 56, -70, -53, 0, 32, 1, -32, -30, -123, 111, 94, 117, 33, 123, 37, 105, 47, 126, 99, -7, -46, -6, -107, 47, 127, 117, 67, -68, 120, 99, 25, -99, -77, 9, 26, 1, -116, 75, -121, -31, -84, -63, -55, -36, -95, 97, 38, -35, 82, 104, 117, 19, -80, 52, -24, 13, 67, -34, 84, 110, -107, -68, 94, 42, -118, -91, -99, 94, -1, 78, 31, 0, -28, 23, 54, 126, -112, -42, -68, -16, -107, -87, -49, -65, -33, 58, -69, 120, 109, -3, -13, 107, -30, -54, 75, 103, -112, 47, -58, 92, -70, 64, -109, -54, 97, 92, 89, -102, -108, -98, 38, -107, -89, -103, 13, -88, -104, 97, -91, -32, -119, 35, -22, -115, -125, 24, 13, -85, -91, -39, -52, 43, -119, -6, 97, 39, -50, -10, 70, -109, 71, -115, 42, 109, -66, 82, -117, -12, -14, 84, 117, -106, 23, 58, 5, -30, -75, -100, 7, -34, -61, -10, 74, -14, -98, -95, -108, -128, 20, 0, 17, -32, 61, 80, -69, -128, -70, 9, 104, -104, 105, 68, -52, 122, 37, -121, -35, -19, -46, -20, -40, 46, 75, 63, -69, -52, -95, 88, 7, 112, 79, -7, 120, -23, 58, 71, -83, -17, 84, 105, -66, 48, 110, 39, 24, 16, -93, 61, -9, 112, 16, -112, -126, -96, 1, 72, 65, 32, 102, -8, -64, -80, -98, 81, 58, 70, 105, 3, 38, -106, 81, 26, -96, 44, 82, 52, -35, -20, 12, 79, -69, -33, 34, 127, 97, 27, -64, -65, -44, 68, -104, 85, -81, -52, 13, -33, 77, 116, -109, -57, -104, 88, -90, -109, -118, -95, 36, 35, 54, 2, -127, 8, -126, 0, 48, 33, 0, -80, -98, -48, 120, 66, 105, -127, -71, 5, 85, 32, -8, 78, -116, -48, 77, -109, -78, 78, -82, 67, -90, 43, 0, 72, 13, -107, 73, 40, 50, 90, 118, 99, -88, -44, -80, -11, -126, -26, -106, 16, 59, 1, 72, 1, -49, 4, -94, -45, -78, 5, 16, 92, 32, -44, 30, -88, 125, 64, -29, 9, 46, 8, -88, -52, -80, -24, -58, 52, 29, -58, 38, 84, 81, 12, 64, 42, -41, -19, -112, -50, 59, -24, 118, 83, 20, 45, 13, 41, 20, 42, 39, 48, -86, -128, -46, 19, -108, 36, 40, 41, 32, -120, 16, -104, -31, 124, 64, -29, 24, -75, -109, -80, 33, -128, -124, 66, 20, 51, 116, 43, -58, 36, -53, 17, 108, 42, 0, 40, 37, 59, 49, -103, 60, 70, -111, -57, -24, -74, 34, 100, -79, -122, 54, 26, -112, 26, -127, 20, 88, 10, -80, -108, 96, 34, -128, 25, -96, 0, -126, -125, 98, -113, -56, 16, 90, 30, 40, 88, -96, -55, 44, -86, 78, -124, -58, 106, -63, -128, 80, 73, -22, 57, 109, 1, 121, 106, 80, 100, 9, 21, -87, -126, 49, 6, 90, 25, 40, -91, 96, -76, -124, -108, -97, -58, -31, 61, -61, 57, 15, -37, 88, 84, 70, -62, 104, 1, -87, 20, -71, -54, -94, -52, 8, -13, -71, -57, 28, -128, 74, 68, 85, -91, 58, -44, -19, 44, -117, -14, -84, -115, 60, 102, 68, -111, -127, -47, 26, -58, 40, 24, 77, -89, -58, 0, 24, -128, 115, 12, 107, 25, -115, 81, -120, 26, 5, -93, 53, -56, 0, 85, -29, 48, -48, 117, -27, 48, 107, -26, 0, 43, 101, -57, 7, -87, 58, -13, 65, -111, -89, 95, 106, -25, 105, -110, 71, -52, -111, 86, -120, -116, -92, -56, 8, 40, 13, 40, 9, 8, 2, 2, 3, -50, 3, 77, 3, 52, 86, -96, 49, -110, -115, -47, -128, 33, -102, -105, -13, 50, 66, -7, -31, -76, -20, 61, 5, -32, -107, 31, 124, -12, -49, -50, -59, -11, -33, 20, -103, -68, -108, -91, 114, 45, -49, 52, -116, 0, 34, -59, -120, 12, -125, 36, 65, -55, 83, -13, 0, -64, 57, -64, 40, 70, 99, 9, -50, 107, -40, -96, -31, -58, 22, 121, 44, -114, 19, 63, -4, -99, 61, -36, 124, 0, -96, 86, -119, 27, 29, 100, -86, -36, -29, -14, -55, 83, 69, -68, -42, -18, 62, 71, -111, 4, 52, 17, 107, 1, 34, -63, -112, 18, 16, 18, 8, 1, 8, 30, -16, 17, -63, 51, -40, 3, 100, 3, 48, -98, 12, 65, -27, -109, -93, 22, 77, 63, -42, -10, -28, 49, 0, 86, 59, 127, -6, -59, 120, -29, -38, -51, -69, -13, -31, -18, 123, -68, -92, -92, -92, -8, -59, 86, 43, 86, -119, 81, -92, 37, -99, -110, -107, 78, 75, 1, 6, -64, 32, 38, -64, 7, -90, -38, 57, 76, 102, -91, -27, -6, 112, 107, 118, -12, -16, -74, 59, 57, -8, 112, -8, -24, -50, -47, 127, -23, -42, -33, -39, -22, 79, -57, -11, 71, 23, -97, 95, -106, 105, 18, -82, 44, 116, 116, -69, -45, 81, 34, -53, 21, -94, 8, -120, -52, -23, 38, 49, -112, -90, -96, 40, 1, -108, 104, -48, -52, -121, -2, -8, -55, -18, -34, -63, -125, 127, -68, -15, -5, -97, -67, -10, -13, -99, 59, -65, -3, -69, -73, -11, -89, -40, 108, 102, 39, 24, 108, -1, 109, 116, -18, -123, -85, -3, 56, 49, 101, 26, -47, -114, -90, -64, 100, -101, 85, -40, 10, -111, 0, 101, -111, 38, 95, -49, -55, 78, -57, -80, -13, 41, 79, -121, -125, -65, -10, -10, -9, 110, -19, -36, -33, 122, -1, -34, -19, 63, -2, 122, -13, -35, 55, 55, -67, -83, -61, 39, -96, -105, -97, -91, -2, -42, -5, -17, -11, -120, -3, -67, -48, -52, -9, -115, -110, 53, 121, 79, -66, -100, 15, -123, -9, 61, 73, 116, 56, 25, 28, -9, 78, -6, -3, -113, -57, -57, -57, 91, -5, 15, -18, -65, -5, -63, -83, 91, 111, -1, -7, -19, 119, -34, -71, -3, -42, -81, 30, -2, 39, -88, 103, -1, -68, 79, -26, -4, -43, -85, 89, -34, -23, 20, 66, -120, -116, 4, 69, -126, -124, 118, -50, 6, -17, 124, -29, -100, -101, 76, 70, -93, -31, -31, -18, -18, -8, 89, -6, 127, 3, 21, 23, -87, 18, 52, -39, 118, 119, 0, 0, 0, 0, 73, 69, 78, 68, -82, 66, 96, -126, };\n\tpublic final static byte BLUE_ARROW[] = {-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 21, 0, 0, 0, 23, 8, 6, 0, 0, 0, -28, -33, 4, -99, 0, 0, 0, 1, 115, 82, 71, 66, 0, -82, -50, 28, -23, 0, 0, 0, 6, 98, 75, 71, 68, 0, 0, 0, 0, 0, 0, -7, 67, -69, 127, 0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 11, 19, 0, 0, 11, 19, 1, 0, -102, -100, 24, 0, 0, 0, 7, 116, 73, 77, 69, 7, -37, 10, 29, 12, 26, 7, 123, -67, 71, -77, 0, 0, 3, 126, 73, 68, 65, 84, 56, -53, -91, -108, -49, 79, 92, 85, 20, -57, -65, -25, -66, 123, -33, 125, 63, -122, -103, 97, 40, 69, 22, -4, -88, 45, 63, 90, 52, -118, -76, 82, 74, -45, -96, 105, 10, -79, -94, 11, 19, 127, 110, -103, -83, 59, 87, 110, -4, 43, -20, -126, -58, -60, -65, -63, -51, -52, -62, -72, 53, -87, 77, -19, 10, 99, 109, -94, 77, 67, 0, -125, 69, -104, -57, -101, 119, -33, 125, -9, -72, -128, 26, 65, -22, 80, 60, -69, -101, -36, -13, 57, -33, -13, -109, -48, -63, -60, 82, 83, 121, -124, -79, -31, 30, -35, -1, -21, 102, -74, 81, 48, 86, -36, -19, 121, -13, -97, 62, -99, -96, 32, -88, -82, -48, -101, -83, 72, -13, -103, 16, -104, 6, 65, 117, 114, -111, -99, 62, 12, 87, -43, -87, -48, -89, -9, 13, -13, -44, 112, 77, 34, -51, -71, -15, 8, 72, -2, -105, -46, -99, 44, 63, -21, -61, -66, -70, 91, -96, 18, 123, 110, 50, -55, -20, 57, 81, 111, -48, -119, -95, -43, 79, -65, 125, -79, -65, -94, -33, 10, -107, -41, 85, 56, -64, 57, 87, -23, -119, -28, 2, 64, 103, 78, 12, 85, 40, 102, 52, -15, -37, -66, -110, -126, -119, -80, 91, 64, -108, 124, 90, -20, -117, -24, -14, -119, -95, -79, 47, 46, 41, 114, -93, 66, 8, -113, 0, 100, -114, 61, -63, -59, -88, 86, -30, -11, -25, 110, -108, -88, 55, -43, -71, 83, -2, -59, -118, -90, -117, -127, 34, -63, 96, 0, -128, 99, 66, 98, 10, 81, 9, -44, -44, -123, -49, -65, -69, -14, -45, 70, 118, -57, 45, 47, -28, -57, 83, -54, 28, -73, -115, -3, 32, -110, 52, -90, 125, 9, -30, -3, -23, 34, 32, 45, 24, -79, -62, 120, 110, -35, 71, 0, -107, -114, -99, -66, 86, 94, 53, -110, -34, -101, 30, 113, -51, 35, 2, 64, -5, 35, 11, 24, 7, 36, 109, -37, 3, -26, 55, 0, -108, -113, 5, 21, 75, -115, 120, -68, -41, -65, 126, -70, 44, -121, 66, 95, 9, -26, -61, -69, 0, -76, 50, 75, -35, 1, 13, 94, 29, -114, 110, -120, 122, 51, -18, -84, -108, 104, 98, 123, 55, 91, -44, -126, -61, 80, -53, -67, 106, -46, 65, 104, -37, 50, 92, 97, -125, 63, 90, -39, -69, 0, 94, -18, 8, 29, -23, 13, 102, -6, -54, -63, -84, 86, 82, 50, 31, -32, -19, 83, 25, 14, -116, 63, 83, 43, -75, -121, -103, -87, -127, -24, -22, 51, -69, 47, -106, -102, 4, -96, -20, 114, 51, 91, 42, -121, 61, -91, 64, 33, -77, -18, -56, 99, 64, 32, -92, -90, -96, 106, -28, 106, -62, -39, 89, 81, 111, 126, 5, -32, -119, 91, -98, -25, -125, 74, 9, 97, 57, -110, 55, 106, -111, -100, -120, 20, 65, 122, 2, 68, -49, -70, 49, -128, 117, 14, -83, 52, 7, -100, 59, 63, 122, 58, -70, 9, 70, 116, 84, -6, -70, 47, 22, -97, 116, -105, -44, 80, -88, 37, 14, 55, -120, -15, -17, 119, -110, 89, -128, -117, -127, -34, -120, 63, 6, -79, 127, 20, 116, -48, 39, 119, -87, 75, -53, 56, 10, 20, -98, 14, -4, 94, 81, 25, 12, -122, 99, -4, 29, 76, -128, 96, -14, 2, 105, 59, -113, 10, -21, 38, -107, 16, 67, 7, -96, -94, -34, 28, -102, -24, 15, 23, 107, -79, -84, -6, -110, -32, 9, 2, 97, 15, -112, 91, 7, -109, 91, 116, 73, -126, 22, -128, -92, 61, -107, 12, -96, 112, -116, -99, 52, -121, -75, 121, -41, -36, 72, -23, 67, 81, 111, 12, -1, 83, -23, 121, -55, -59, 123, -3, -107, 64, -105, 2, -123, -36, 58, -92, -58, -94, 109, 44, -104, -99, 85, -124, -43, -118, -94, 7, 85, -19, 61, 46, 7, -46, 68, 74, 64, -19, 7, 79, -115, -123, -55, -116, 22, -20, -34, 1, -45, 5, 0, 16, -94, -34, 20, -27, 64, 78, -62, 21, 19, 82, -112, -57, 12, -34, 78, -115, -39, -36, 105, 39, -101, 59, -23, -122, -16, -60, -67, -98, 90, -7, -21, 123, -21, -59, 23, -92, -93, 91, 113, 16, 124, 31, 107, 127, -75, -92, -3, 86, 24, 40, 35, 0, 78, -38, -71, -73, -67, 107, 70, 94, 25, -120, -81, 60, 29, -87, -23, -15, 62, 61, -41, 23, 123, 106, 43, 49, 120, -72, -66, -45, -126, 16, 43, 113, 24, 52, -18, -81, 39, -33, 108, -81, 37, 15, -127, -60, -128, 81, -36, -3, 109, -37, 3, -29, 22, -64, 103, 70, 95, -120, -26, 74, -70, -72, -87, -108, 122, -51, -27, 121, 117, 55, 53, 114, 108, -80, 124, -19, 126, -67, 121, 89, 2, -104, -31, -36, -124, -85, 79, -24, -57, -44, -119, 31, 30, 109, -15, -99, 86, 102, 30, 0, -26, 23, 48, 63, 118, -73, 23, 14, 55, 62, 17, 75, -115, -83, -97, -41, 118, 55, 64, 116, 23, -96, -77, 101, 29, -68, -92, -56, -101, 94, -37, 74, -117, 64, -47, 53, 18, -11, -26, -105, 96, 60, 1, 97, 5, 64, -45, 45, -49, -1, -114, -25, 52, 81, 111, -10, 2, -72, -66, -65, -78, -35, 127, 1, -10, 55, 102, -64, -66, 36, 61, 63, 0, 0, 0, 0, 73, 69, 78, 68, -82, 66, 96, -126, };\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/utils/LogUtils.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.utils;\n\n\npublic class LogUtils {\n\t\n\tpublic static final String APP = \"MAP WIDGET\";\n\t\n\tpublic static void logHeap(Class clazz) \n\t{\n//\t    Double allocated = new Double(Debug.getNativeHeapAllocatedSize())/new Double((1048576));\n//\t    Double available = new Double(Debug.getNativeHeapSize())/1048576.0;\n//\t    Double free = new Double(Debug.getNativeHeapFreeSize())/1048576.0;\n//\t    DecimalFormat df = new DecimalFormat();\n//\t    df.setMaximumFractionDigits(2);\n//\t    df.setMinimumFractionDigits(2);\n//\n//\t    Log.d(APP, \"debug. =================================\");\n//\t    Log.d(APP, \"debug.heap native: allocated \" + df.format(allocated) + \"MB of \" + df.format(available) + \"MB (\" + df.format(free) + \"MB free) in [\" + clazz.getName().replaceAll(\"com.myapp.android.\",\"\") + \"]\");\n//\t    Log.d(APP, \"debug.memory: allocated: \" + df.format(new Double(Runtime.getRuntime().totalMemory()/1048576)) + \"MB of \" + df.format(new Double(Runtime.getRuntime().maxMemory()/1048576))+ \"MB (\" + df.format(new Double(Runtime.getRuntime().freeMemory()/1048576)) +\"MB free)\");\n//\t    System.gc();\n//\t    System.gc();\n\n\t    // don't need to add the following lines, it's just an app specific handling in my app        \n//\t    if (allocated>=(new Double(Runtime.getRuntime().maxMemory())/new Double((1048576))-MEMORY_BUFFER_LIMIT_FOR_RESTART)) {\n//\t        android.os.Process.killProcess(android.os.Process.myPid());\n//\t    }\n\t}\n\t\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/utils/MapCalibrationData.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.utils;\n\nimport android.graphics.Point;\nimport android.location.Location;\nimport android.util.Pair;\n\npublic class MapCalibrationData \n{\n\tprivate Pair<Point, Location> topLeft;\n\tprivate Pair<Point, Location> bottomRight;\n\t\n\tprivate float widthInMeters;\n\tprivate float heightInMeters;\n\t\n\tprivate float results[];\n\t\n\tpublic MapCalibrationData(Pair<Point, Location> topLeft, Pair<Point, Location> bottomRight)\n\t{\n\t\tthis.topLeft = topLeft;\n\t\tthis.bottomRight = bottomRight;\n\t\tresults = new float[3];\n\t\t\n\t\trecalculateDistanceInMeters();\n\t}\n\n\t\n\t/**\n\t * @return returns width of the calibration rectangle in pixels\n\t */\n\tpublic int widthInPixels()\n\t{\n\t\treturn bottomRight.first.x - topLeft.first.x; \n\t}\n\t\n\t\n\t/**\n\t * @return returns height of the calibration rectangle in pixels\n\t */\t\n\tpublic int heightInPixels()\n\t{\n\t\treturn bottomRight.first.y - topLeft.first.y; \n\t}\n\t\n\t\n\t/**\n\t * @return Returns width of the calibration rectangle in degrees;\n\t */\n\tpublic double widthInDegrees()\n\t{\n\t\treturn bottomRight.second.getLongitude() - topLeft.second.getLongitude();\n\t}\n\t\n\t/**\n\t * @return Returns height of the calibration rectangle in degrees;\n\t */\n\tpublic double heightInDegrees()\n\t{\n\t\treturn topLeft.second.getLatitude() - bottomRight.second.getLatitude();\n\t}\n\t\n\t\n\t/**\n\t * @return Returns width of the calibration rectangle in meters;\n\t */\n\tpublic float getWidthInMeters()\n\t{\n\t\treturn widthInMeters;\n\t}\n\t\n\t\n\t/** \n\t * @return Returns height of the calibration rectangle in meters;\n\t */\n\tpublic float getHeightInMeters()\n\t{\n\t\treturn heightInMeters;\n\t}\n\t\n\t\n\t/**\n\t * Converts location to position on the map.\n\t * @param location instance of android.location.Location object.\n\t * @param position - out parameter. Can be null.\n\t * @return returns the same object that was passed as position, or if it is null - returns new Point object.\n\t */\n\tpublic Point translate(final Location location, /*out*/Point position)\n\t{\n\t\tdouble heightCoef = (topLeft.second.getLatitude() - location.getLatitude()) / heightInDegrees();\n\t\tdouble widthCoef = (location.getLongitude() - topLeft.second.getLongitude()) / widthInDegrees();\n\t\t\n\t\tif (position == null) {\n\t\t\tposition = new Point();\n\t\t}\n\t\t\t\n\t\tposition.x = (int) (widthInPixels() * widthCoef + topLeft.first.x);\n\t\tposition.y = (int) (heightInPixels()* heightCoef + topLeft.first.y);\n\t\t\n\t\treturn position;\n\t}\n\t\n\t\n\t/**\n\t * Converts position on the map to location coordinates.\n\t * @param point - position on the map in pixels. Instance of android.graphics.Point\n\t * @param location - out parameter. Will contain latitude and longitude of point on the map.\n\t */\n\tpublic void translate(Point point, Location location) \n\t{\t\n\t\ttranslate(point.x, point.y, location);\n\t}\n\t\n\n\t/**\n\t * Converts position on the map to location coordinates.\n\t * @param x - x coordinate in map coordinate system.\n\t * @param y - y coordinate in map coordinate system.\n\t * @param location - out parameter. Will contain latitude and longitude of point on the map.\n\t */\n\tpublic void translate(int x, int y, Location location) \n\t{\n\t\tdouble heightCoef = (float)(topLeft.first.y - y) / (float)heightInPixels();\n\t\tdouble widthCoef = (float)(x - topLeft.first.x) / (float)widthInPixels();\n\t\t\n\t\tlocation.setLatitude(heightInDegrees() * heightCoef + topLeft.second.getLatitude());\n\t\tlocation.setLongitude(widthInDegrees() * widthCoef + topLeft.second.getLongitude());\n\t}\n\t\n\t\n\t\n\tprivate void recalculateDistanceInMeters() \n\t{\n\t\t// width\n\t\tLocation.distanceBetween(topLeft.second.getLatitude(), topLeft.second.getLongitude(), topLeft.second.getLatitude(), bottomRight.second.getLongitude(), results);\n\t\twidthInMeters = results[0];\n\t\t\n\t\t// height\n\t\tLocation.distanceBetween(bottomRight.second.getLatitude(), topLeft.second.getLongitude(), topLeft.second.getLatitude(), topLeft.second.getLongitude(), results);\n\t\theightInMeters = results[0];\n\t}\n\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/utils/MathUtils.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.utils;\n\nimport android.graphics.Point;\nimport android.graphics.PointF;\n\npublic class MathUtils \n{\n\tpublic static double distance(Point start, Point finish)\n\t{\n\t\treturn Math.sqrt(Math.pow((start.x - finish.x),2) + Math.pow((start.y - finish.y), 2));\n\t}\n\t\n\t\n\tpublic static double distance(float x1, float y1, float x2, float y2)\n\t{\n\t\treturn Math.sqrt(Math.pow((x1 - x2),2) + Math.pow((y1 - y2), 2));\n\t}\n\t\n\t\n\tpublic static Point middle(Point first, Point second)\n\t{\n\t\treturn new Point((first.x + second.x)/2, (first.y + second.y)/2);\n\t}\n\t\n\t\n\tpublic static PointF middle(PointF first, PointF second)\n\t{\n\t\treturn new PointF((first.x + second.x)/2.0f, (first.y + second.y)/2.0f);\n\t}\n\t\n\t\n\tpublic static PointF middle(float x1, float y1, float x2, float y2)\n\t{\n\t\treturn new PointF((x1 + x2)/2.0f, (y1 + y2)/2.0f);\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/utils/OfflineMapUtil.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.utils;\n\npublic class OfflineMapUtil \n{\n\tprivate static String filesPathCache;\n\tprivate static String cachedRoot;\n\t\n\tpublic static String getConfigFilePath(String root)\n\t{\n\t\tif (root == null) {\n\t\t\tthrow new IllegalArgumentException(\"root can't be null\");\n\t\t}\n\t\t\n\t\tif (root.lastIndexOf('/') == -1) {\n\t\t\treturn root + \"/\" + root + \".xml\";  \n\t\t} else {\n\t\t\treturn root + \"/\" + extractMapName(root) + \".xml\";\n\t\t}\n\t}\n\t\n\t\n\tpublic static String getFilesPath(String root)\n\t{\n\t\tif (root == null) {\n\t\t\tthrow new IllegalArgumentException(\"root can't be null\");\n\t\t}\n\t\t\n\t\tif (filesPathCache != null && cachedRoot.hashCode() == root.hashCode())\n\t\t\treturn filesPathCache;\n\t\t\n\t\tif (root.lastIndexOf('/') == -1) { \n\t\t\tfilesPathCache = root + \"/\" + root + \"_files/\"; \t\n\t\t\tcachedRoot = root;\n\t\t\treturn filesPathCache;\n\t\t} else {\n\t\t\tint indexOfSlash = root.lastIndexOf('/');\n\t\t\t\n\t\t\tif (indexOfSlash != -1) {\n\t\t\t\tfilesPathCache = root + \"/\" + extractMapName(root) + \"_files/\";\n\t\t\t\tcachedRoot = root;\n\t\t\t}\n\t\t\t\n\t\t\treturn filesPathCache;\n\t\t}\n\t}\n\t\n\t\n\tpublic static int getMaxZoomLevel(int imageWidth, int imageHeight)\n\t{\n\t\tint biggerSize = imageWidth > imageHeight ? imageWidth:imageHeight;\n\t\t\n\t\tif (biggerSize == 0) {\n\t\t\treturn 0;\n\t\t}\n\t\t\n\t\treturn (int) Math.ceil(Math.log((double)biggerSize) / Math.log(2.0));\n\t}\n\t\n\t\n\tpublic static int getScaledImageSize(int maxZoomLevel, int currZoomLevel, int size)\n\t{\n\t\tdouble scale = 1.0 / Math.pow(2, maxZoomLevel - currZoomLevel);\n\t\t\t\n\t\treturn (int)Math.ceil(size * scale);\n\t}\n\t\n\t\n\tprivate static String extractMapName(String root)\n\t{\n\t\tint indexOfSlash = root.lastIndexOf('/');\n\t\t\n\t\tif (indexOfSlash != -1) {\n\t\t\t\n\t\t\treturn root.substring(indexOfSlash+1); \n\t\t}\n\t\t\n\t\treturn root;\n\t}\n\t\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/utils/PivotFactory.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.utils;\n\nimport android.graphics.Point;\nimport android.graphics.drawable.Drawable;\n\npublic class PivotFactory \n{\n\tpublic enum PivotPosition \n\t{\n\t\tPIVOT_TOP_LEFT,\n\t\tPIVOT_CENTER,\n\t\tPIVOT_BOTTOM_CENTER\n\t}\n\t\n\tpublic static Point createPivotPoint(Drawable drawable, PivotPosition type)\n\t{\n\t\tif (drawable == null) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t\t\n\t\tswitch (type) {\n\t\tcase PIVOT_TOP_LEFT:\n\t\t\treturn new Point(0,0);\n\t\tcase PIVOT_CENTER:\n\t\t\treturn new Point(drawable.getIntrinsicWidth() / 2, drawable.getIntrinsicHeight() / 2);\n\t\tcase PIVOT_BOTTOM_CENTER:\n\t\t\treturn new Point(drawable.getIntrinsicWidth() / 2, drawable.getIntrinsicHeight());\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/utils/Resources.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.utils;\n\npublic final class Resources \n{\n\tpublic final static byte LOGO[] = {-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, -96, 0, 0, 0, 110, 8, 6, 0, 0, 0, -96, 45, 24, -23, 0, 0, 0, 1, 115, 82, 71, 66, 0, -82, -50, 28, -23, 0, 0, 0, 6, 98, 75, 71, 68, 0, -1, 0, -1, 0, -1, -96, -67, -89, -109, 0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 11, 19, 0, 0, 11, 19, 1, 0, -102, -100, 24, 0, 0, 0, 7, 116, 73, 77, 69, 7, -37, 9, 27, 14, 23, 28, 37, 57, 1, 112, 0, 0, 32, 0, 73, 68, 65, 84, 120, -38, -19, -99, 121, 124, 21, -27, -67, -1, -33, -49, 89, -78, 64, 18, -62, -110, 0, -15, 4, -54, 38, 40, 84, 48, -118, -89, 22, -91, -126, -126, -43, -21, 82, -80, -83, -43, 107, -83, -30, 66, 93, -80, -83, -46, -34, 74, -75, -117, -2, 80, 106, -107, 94, -105, 122, 113, -93, -42, -123, -126, -74, -105, -42, -107, -53, -107, 10, 114, 65, -114, -72, -79, 111, 2, 9, -100, -124, 16, -78, -111, -28, -84, -77, 60, -65, 63, 102, -26, 100, 114, 114, -78, -97, 4, -119, -25, -5, 122, 77, -26, -52, 100, -26, 121, -98, -103, -7, -52, -25, -69, 60, -33, -25, 25, 65, 74, 98, -78, 96, -63, 2, 30, 122, -24, 33, 0, -42, -81, 95, -33, 111, -63, -126, 5, -33, -40, -66, 125, -5, -40, -102, -102, -102, -2, -83, -99, -105, -107, -107, 85, 63, 100, -56, -112, -118, 51, -50, 56, 99, -33, 107, -81, -67, -74, -51, -27, 114, 5, 83, 119, 51, 37, 29, -106, 57, 115, -26, -116, -49, -53, -53, 123, -84, 127, -1, -2, -59, -128, -76, 45, 122, -36, 118, -85, -1, -53, -55, -55, 57, -106, -97, -97, -1, -113, 81, -93, 70, -51, 121, -7, -27, -105, 7, -91, -18, 108, 74, 90, -107, -45, 78, 59, -19, -6, -2, -3, -5, 127, -47, 10, -56, 58, -77, -60, -128, 57, 112, -32, -64, -99, -89, -100, 114, -54, -4, 45, 91, -74, 100, 1, -36, 113, -57, 29, -87, -101, 110, -118, -8, 42, 94, -12, -36, -71, 115, 121, -26, -103, 103, 40, 42, 42, -70, 124, -17, -34, -67, 47, 52, 52, 52, -28, -103, 96, 17, 0, 30, -113, -121, -47, -93, 71, 83, 84, 84, -60, -8, -15, -29, -55, -49, -49, 39, 61, 61, 29, 33, 4, -118, -94, 112, -4, -8, 113, 106, 106, 106, -88, -86, -86, 2, 64, -41, 117, 2, -127, 0, 85, 85, 85, -108, -108, -108, 80, 81, 81, -63, -98, 61, 123, -120, 68, 34, 86, -107, 18, 16, 66, 8, -14, -14, -14, -34, -104, 54, 109, -38, 125, 43, 86, -84, -40, 118, -61, 13, 55, -16, -30, -117, 47, -90, 0, -8, 85, -110, -15, -29, -57, -77, 125, -5, 118, 119, 94, 94, -34, 91, -107, -107, -107, 51, -19, -32, -104, 57, 115, 38, 55, -35, 116, 19, 69, 69, 69, 20, 22, 22, -110, -106, -106, -42, 106, 89, 82, 74, 74, 75, 75, -39, -77, 103, 15, 59, 118, -20, -32, -24, -47, -93, -92, -91, -91, 33, -124, -64, -19, 118, 83, 94, 94, -50, -50, -99, 59, -15, -7, 124, -44, -41, -41, 55, 1, -29, -64, -127, 3, 55, -50, -104, 49, -29, -26, -27, -53, -105, -17, -102, 63, 127, 62, -113, 62, -6, 104, 10, -128, 95, 5, -103, 62, 125, 122, -31, -122, 13, 27, 118, 70, 34, -111, 44, 107, -33, -20, -39, -77, -7, -35, -17, 126, -57, -124, 9, 19, 98, -64, 18, -94, 125, -73, -58, 126, -20, -79, 99, -57, -8, -32, -125, 15, -8, -4, -13, -49, 113, 58, -99, -79, -3, 105, 105, 105, -108, -106, -106, -78, 110, -35, 58, -74, 111, -33, -34, 4, -120, 67, -122, 12, 89, -79, 121, -13, -26, 27, 10, 11, 11, -61, 41, 0, -10, 114, 41, 42, 42, 58, 109, -21, -42, -83, 59, 84, 85, 5, 16, 99, -57, -114, -27, -123, 23, 94, 96, -54, -108, 41, 73, 41, -33, 2, 99, 32, 16, -32, -115, 55, -34, 96, -57, -114, 29, -72, -35, -18, -40, -1, 29, 14, 7, -11, -11, -11, 108, -38, -76, -119, -11, -21, -41, -57, -10, -89, -91, -91, -23, -29, -58, -115, -5, -47, -42, -83, 91, 95, -7, -39, -49, 126, -58, 31, -1, -8, -57, 20, 0, 123, -109, -52, -102, 53, -117, 105, -45, -90, -11, -71, -25, -98, 123, -114, 43, -118, -30, 4, -60, 117, -41, 93, -57, -46, -91, 75, -101, 0, 36, 89, 98, 1, 113, -41, -82, 93, -68, -10, -38, 107, 9, -113, -79, 64, -70, 103, -49, -98, 24, 27, -26, -25, -25, -65, 125, -12, -24, -47, -53, 47, -70, -24, 34, -71, 102, -51, -102, 20, 0, 123, -109, -28, -28, -28, -84, -86, -85, -85, -101, 9, -120, 5, 11, 22, -80, 112, -31, -62, 14, -87, -38, -50, 74, 40, 20, 98, -55, -110, 37, 28, 63, 126, -68, 73, 93, 82, 74, 92, 46, 23, -121, 14, 29, -30, -49, 127, -2, 51, 38, 43, -109, -103, -103, 89, 51, 107, -42, -84, 9, -53, -106, 45, 43, 75, 1, -80, 23, -56, -80, 97, -61, -24, -37, -73, -17, 55, 119, -19, -38, -75, 1, -32, 59, -33, -7, 14, 43, 87, -82, 76, 58, -37, -75, -11, -1, -91, 75, -105, 82, 82, 82, -126, -61, -31, 72, -8, -1, -105, 95, 126, -103, -3, -5, -9, 3, 72, -73, -37, 45, -50, 57, -25, -100, 41, 27, 54, 108, -40, -104, 2, 96, 47, -112, -52, -52, -52, -125, -95, 80, 104, 56, 32, 116, 93, -17, 48, -21, 73, 41, -39, 120, -72, -114, -99, -27, -11, 84, 6, -94, 72, -87, -45, -57, 41, 24, -42, 63, -125, 51, 61, -71, -116, 24, -48, -73, 85, 32, 90, -1, 123, -27, -107, 87, -40, -73, 111, 95, 66, 16, -90, -91, -91, -79, 110, -35, 58, 86, -81, 94, 13, 32, -123, 16, 98, -14, -28, -55, -33, -7, -24, -93, -113, -2, -39, -101, -97, -115, -77, -73, -125, 47, 47, 47, -17, -25, -57, -113, 31, -1, 30, 32, 22, 47, 94, -52, -71, -25, -98, -37, -95, -13, 119, 87, -122, 88, -68, -79, -108, -35, -107, 65, -114, 71, 84, 20, 85, 67, -45, 117, -94, -102, 70, 69, 125, -124, -113, 75, -86, -39, 86, 90, 75, -31, -128, -66, -28, 100, 36, -74, 39, -123, 16, 72, 41, -103, 56, 113, 34, 7, 15, 30, 108, -90, -114, -123, 16, -24, -70, -50, -80, 97, -61, 40, 40, 40, 96, -37, -74, 109, 2, -112, -91, -91, -91, -41, 76, -98, 60, 121, 75, 89, 89, -39, -18, 20, 3, -98, -100, -22, -9, -20, 67, -121, 14, 109, 6, 100, 118, 118, -74, -88, -85, -85, -21, -48, -7, -97, 29, 13, -14, -4, -89, -57, -56, 112, 65, -70, -112, 124, -77, 48, -117, 97, -3, -46, 9, 69, 85, -74, -8, 107, 40, -87, 14, -31, 118, 11, 4, 16, -115, 106, 92, 48, 58, -113, 25, -89, 13, 105, -111, 13, -83, -3, -117, 23, 47, -74, -57, 5, -101, -119, -33, -17, -25, -7, -25, -97, -113, 57, 39, -25, -98, 123, -18, 5, 31, 126, -8, -31, -70, 20, 0, 79, 46, -16, -115, -14, -5, -3, -5, 116, 93, 7, 16, -69, 119, -17, 102, -20, -40, -79, -124, -61, 97, -22, -22, -22, 8, 6, -125, 68, -93, 81, -94, -47, 40, -125, 6, 13, 98, -56, -112, 33, 77, -128, 18, 84, 37, 119, -65, 87, -118, -37, 5, -29, 114, -45, -72, 115, -14, -32, 102, 54, -33, -114, -14, 58, 94, -3, -72, -124, 52, -105, -95, 82, 117, 77, 99, 92, 94, 54, -41, -98, 51, -94, 85, 16, 6, -125, 65, 30, 121, -28, -111, 102, -86, -40, 46, -91, -91, -91, 60, -9, -36, 115, 0, -46, -27, 114, -119, -117, 47, -66, 120, -60, -63, -125, 7, -117, 119, -18, -36, -103, 82, -63, 95, 118, 25, 52, 104, -112, -73, -68, -68, 124, -85, -108, 18, 64, -84, 88, -79, -126, 111, 125, -21, 91, 0, 76, -97, 62, -99, -41, 95, 127, -99, -73, -34, 122, -117, -43, -85, 87, -77, 118, -19, 90, 46, -72, -32, 2, 6, 14, 28, -40, 68, 37, -82, -40, 93, 75, 73, -67, 66, -106, -53, -63, 125, -25, 13, -115, 1, -54, 14, -86, -4, -84, 116, -94, 58, -108, 84, 7, 1, -119, 3, -88, 108, 8, 81, 113, 60, -60, -124, 83, -6, -73, -88, -114, -45, -46, -46, -56, -51, -51, 101, -25, -50, -99, 45, -126, 48, 39, 39, 7, -113, -57, -61, -42, -83, 91, -123, -82, -21, -14, -16, -31, -61, 55, -105, -107, -107, 61, 90, 89, 89, -87, 111, -34, -68, -71, -41, 60, 43, 71, 111, -71, 16, -113, -57, 3, 64, 86, 86, -42, -36, -54, -54, -54, 77, -46, 64, -97, 120, -6, -23, -89, -7, -2, -9, -65, 31, 59, 110, -63, -126, 5, 68, -93, 81, 84, 85, 101, -28, -56, -111, 44, 91, -74, -116, -47, -93, 71, 55, 43, -17, -29, 35, 33, 34, -102, -28, -46, 49, -71, 49, -32, -60, 81, 25, -1, -77, -73, -110, 117, -5, -85, -48, -123, 64, -45, 65, -109, 18, 4, 108, 47, -83, -30, 95, -69, -4, -83, -74, -9, -52, 51, -49, -92, -96, -96, -96, -43, 99, -58, -116, 25, -61, 101, -105, 93, 6, 32, -62, -31, 112, -33, 1, 3, 6, -84, -3, -45, -97, -2, -108, 98, -64, 47, -95, -93, 65, 121, 121, 57, 5, 5, 5, -81, 6, 2, -127, 123, 85, 85, -107, -128, 88, -74, 108, 25, 55, -34, 120, 99, -109, 99, 71, -113, 30, 77, 97, 97, 33, 51, 103, -50, -28, -10, -37, 111, -57, -19, 118, 39, 84, -107, -81, -18, 58, 78, 68, -123, -85, -57, -11, 35, 55, -67, -23, 109, -38, 85, 25, 98, -47, -6, -61, -20, -85, 10, 34, 1, -105, 0, 93, 98, -4, -47, 53, 28, 72, -10, -107, 85, 49, 102, 72, 127, -6, 101, -90, -75, -88, -118, -121, 15, 31, -50, -58, -115, 27, 113, 58, 91, 126, 12, -123, -123, -123, 84, 87, 87, 115, -12, -24, 81, 17, 14, -121, 11, -57, -114, 29, 91, 87, 85, 85, -75, 41, -59, -128, 95, 34, 81, 85, -43, 51, 104, -48, 32, -65, -86, -86, -41, -26, -28, -28, 80, 84, 84, 36, 62, -5, -20, 51, -82, -71, -26, -102, -124, -57, 95, 124, -15, -59, 76, -99, 58, 53, 49, -77, -103, -94, 73, 80, -92, 32, -86, 75, 76, 85, 14, -64, 71, 71, -126, -4, -63, 119, -116, -80, 112, 18, -43, 5, 87, -100, 62, -104, -2, 25, -23, 104, 82, -94, 74, -119, 38, 65, -45, 116, 92, 46, 7, 47, -81, -35, -118, 48, -63, -106, 72, 21, -25, -25, -25, 39, 100, -33, 38, -19, -48, 52, -82, -70, -22, 42, 43, 49, 66, -18, -37, -73, 111, -15, 61, -9, -36, 51, -8, -26, -101, 111, 78, 1, -16, 75, -31, 69, 9, -15, -77, 80, 40, 116, 56, 28, 14, 23, -44, -41, -41, -13, -13, -97, -1, -100, 79, 62, -7, -124, -119, 19, 39, 118, -87, -36, -127, 25, 110, -92, -61, -63, -57, -27, -111, 24, 72, 53, 41, 121, -22, -77, 90, -124, -53, 69, 68, 23, 76, 42, -56, -26, -68, -31, -71, 28, 56, 30, 70, -107, 14, 52, 4, -86, 102, 0, 81, -43, 52, 66, -118, -62, -101, 31, -17, 109, 53, 62, 120, -63, 5, 23, -60, 122, 65, 90, 3, -31, -83, -73, -34, -118, 25, -57, -108, 47, -68, -16, -62, -101, -90, -105, -100, 2, -32, 9, -108, -66, -64, -57, 82, -54, -59, -31, 112, 88, 14, 24, 48, 64, 108, -37, -74, -115, -7, -13, -25, -73, -54, 108, -19, 21, -17, 41, -103, 40, 58, 44, -33, 83, 79, 64, -47, 1, -8, -25, -2, 0, 42, -126, -120, 6, 19, -13, -5, 112, 75, -47, 96, -98, -1, -12, 40, 56, 93, 40, -70, 68, -47, 36, -86, 4, 77, -105, -26, -94, -13, -63, -114, -125, -44, -121, 34, 45, -78, -32, -120, 17, 35, -24, -45, -89, 79, 91, 47, 25, -7, -7, -7, -100, 117, -42, 89, 0, -94, -74, -74, 118, -14, -92, 73, -109, -82, 76, -39, -128, 39, 78, 10, -127, -61, -26, 90, -36, 120, -29, -115, 98, -19, -38, -75, -12, -17, -33, 63, 41, 125, -69, 82, -62, -8, -127, 105, -68, -78, -85, 1, -23, 116, -16, 63, -59, 65, 50, -35, 14, 94, -36, 89, -113, -108, -126, -17, -114, -50, -30, -58, -81, -9, -25, -71, -49, -85, -8, -65, -61, 13, 56, -84, 4, 104, 41, -111, -70, -114, -44, 84, -48, 53, -48, 53, -124, -128, 64, 32, -52, -124, -81, 13, 105, -79, -66, -70, -70, 58, 74, 75, 75, -37, -20, -46, 27, 63, 126, 60, 107, -41, -82, 69, 74, 41, 27, 26, 26, 102, 70, -93, -47, 71, 82, 0, 60, 49, 82, 6, 100, 2, 98, -50, -100, 57, 44, 93, -70, 52, -87, -119, 5, 66, -128, 67, 8, 70, -26, -70, 121, -89, 56, -120, 38, 4, 31, -107, -121, 113, 56, 28, -72, 28, -48, -57, 37, 120, -30, -77, 106, -118, -21, -94, 56, 4, 72, -87, -101, -64, -45, 65, 87, -111, -70, 110, 0, 80, -45, 64, -41, 57, 92, 81, -51, -123, -109, 70, -29, 76, 16, 114, -111, 82, -110, -98, -98, -50, 39, -97, 124, -46, 106, 92, -48, 82, -59, -39, -39, -39, -20, -35, -69, 87, 68, -93, -47, 62, -93, 71, -113, 46, -85, -82, -82, -2, 52, -91, -126, 123, 86, -82, 49, -43, -81, 0, -72, -6, -22, -85, -69, 45, -85, 101, -54, -48, 12, 46, 25, -34, -121, -120, 34, -47, -92, 32, -86, 73, -126, 26, 108, 56, 26, 65, -111, 2, 85, 10, 20, 41, 81, 36, 40, 58, 40, 82, 55, -42, 26, -88, -70, 68, -47, 117, 84, 77, 67, 74, -55, -121, -69, 75, 90, 84, -81, -61, -121, 15, 111, 87, -5, -123, 16, 76, -103, 50, -59, 74, 33, -109, -27, -27, -27, 15, -89, 108, -64, -98, -105, -3, -10, -115, -39, -77, 103, -29, -9, 55, -58, -36, -114, 28, 57, -110, -76, -118, -92, -108, 44, -104, -100, -117, 3, 73, 84, -41, 99, 118, 94, 84, -125, -88, 46, -51, 109, -127, -94, -117, 24, -16, 20, 13, 84, 105, -38, -125, -102, 68, -43, 116, 52, 4, -101, 118, 28, 108, -75, 46, 123, 79, 76, 107, 18, 10, -123, -72, -12, -46, 75, 1, 68, 67, 67, -61, -64, -119, 19, 39, -50, 74, 1, -80, 103, -27, 35, -96, 26, -93, -97, -108, 64, 32, -64, -80, 97, -61, -104, 58, 117, 42, 35, 70, -116, -96, -96, -96, -128, 80, 40, -108, 44, 15, 27, -128, -17, -113, -51, 66, 85, 33, -86, -101, -64, -45, 116, -29, -73, -122, -63, -128, -102, 9, 70, -109, -11, -116, 109, -35, -4, 109, -80, -32, -66, -14, 42, 20, 85, 107, -79, -82, -63, -125, 7, -93, -21, 122, 66, 103, 37, -66, 77, -33, -8, -58, 55, 44, 117, 45, 75, 75, 75, 127, -107, 2, 96, -49, -53, 116, 32, 108, -127, 16, 96, -3, -6, -11, -116, 29, 59, -106, -54, -54, 74, 50, 51, 51, -109, -56, -126, 112, -18, -112, 12, 54, -6, 67, 28, 9, -88, 70, 124, 80, 7, 69, 51, 24, -79, 9, 27, -22, -46, -8, -97, -82, -37, -114, -47, 81, 52, 13, 93, -43, -40, 91, 118, -84, 69, -128, 13, 29, 58, 20, 85, 85, -47, 52, -83, 9, 16, 19, 29, 31, -119, 68, -84, 56, -90, -88, -84, -84, 60, -21, -2, -5, -17, 31, 118, -1, -3, -9, -89, 0, -40, -125, -78, 5, 56, 7, 91, 50, -59, -51, 55, -33, -52, -86, 85, -85, 24, 48, 96, 64, -110, -29, -116, 48, 38, -41, 5, 18, -10, -41, 42, 108, 40, 11, 83, 82, -81, -96, 74, 12, -75, 108, -78, 95, 84, 51, 22, 69, 51, -9, -87, -74, -75, -86, -93, 11, -8, -94, -84, -78, 69, 91, -81, 95, -65, 126, 40, -118, -126, -82, -21, 49, 16, -102, -119, 20, 9, 65, 120, -10, -39, 103, -57, 126, 47, 89, -78, 100, -18, -125, 15, 62, -104, 2, 96, 15, -53, 118, -5, -58, 115, -49, 61, -41, 109, -50, 72, -102, 67, 24, 80, 23, 6, 24, 74, -22, 20, 54, -108, -122, 40, -87, 83, 81, -92, 36, -86, 89, -10, -95, 78, 84, -45, -119, -86, -102, 9, 78, -29, -73, -94, -23, -88, -70, -92, -92, -68, -70, -27, -96, 102, -33, -66, 40, -118, 18, 99, -63, 68, 32, -76, 3, 49, 55, 55, 55, -42, -1, -83, -86, -22, 117, 41, 21, -4, 37, -112, -18, 26, -33, 17, 84, -91, -39, -39, -37, -88, -12, 37, 80, 114, 60, -54, -122, -46, 6, -54, 27, 20, 52, 93, 18, 85, 117, -109, 1, 13, -42, -117, 42, -86, -71, 109, -128, -80, -94, -74, -27, 124, -60, -12, -12, -12, 102, 0, -76, 64, 104, -83, -19, -50, -111, -94, 40, -116, 31, 63, 30, -128, -102, -102, -102, 97, -113, 62, -6, 104, 65, 10, -128, 61, 47, -5, 44, 72, 44, 95, -66, -68, -37, 42, 57, -36, -96, 26, -58, -96, -76, 41, 125, 105, -52, -64, -95, -21, -110, 61, -57, 66, -8, 14, 31, -89, 62, -94, -96, -88, 26, 81, 85, 37, -86, -86, 6, -16, 84, -107, -88, 98, 108, -41, 52, -124, 91, 125, 121, 44, 0, -58, 47, 118, 54, -76, -128, 40, -124, -32, -76, -45, 78, -117, -99, -1, -44, 83, 79, 93, -102, 2, 96, -49, -53, 35, 22, 36, -82, -67, -10, 90, -34, 122, -21, -83, -92, 87, 32, -91, 100, 75, 101, 20, -100, -62, 4, 29, -74, -75, -11, 91, 39, -92, 104, 124, 114, -72, -122, 61, 71, -21, 12, -42, 51, 65, -89, 40, 26, -118, 106, 44, -95, -120, -46, 98, 61, -119, -64, 103, 103, -62, 120, -75, 44, -91, 100, -16, -32, -63, -79, 102, 6, -125, -63, 111, -89, 0, -40, -13, -14, 60, -80, -44, 2, -54, -100, 57, 115, -70, 69, -83, -65, 87, 28, 4, -105, -61, 64, 92, -52, 14, -45, 77, 86, 52, -25, 34, -110, 26, 32, 41, 63, 30, 100, -45, -2, -93, -44, 5, 35, 40, 74, 35, 27, 70, 85, 13, -67, -107, 16, 75, 67, 67, 3, -86, -86, -94, 40, 74, 12, -116, -10, -33, -119, 0, 25, -119, 68, -84, 108, 26, -95, 40, -54, 57, 41, 0, -98, 24, -71, -55, 64, 3, -52, -104, 49, -93, 91, 42, -8, -5, 23, 1, 3, 100, 66, -40, -116, 64, 11, 120, -70, -79, 88, -35, 111, 82, 67, 85, 21, 62, 59, 80, -58, -95, 99, 53, 104, -102, -118, -94, 26, -125, -103, 50, -36, -82, 22, 89, -74, -90, -90, 6, 77, -45, 98, 96, -117, 103, 68, -5, -1, 44, 0, 42, -118, 66, 94, 94, 30, 0, 117, 117, 117, -123, 41, 0, -98, 56, 89, 5, -56, -116, -116, -116, -92, -85, -33, 53, -2, 16, 117, 65, -51, 6, 56, -5, 98, 1, -49, 6, 64, 77, 3, 77, 5, -87, 83, 82, 94, -59, 103, -5, 75, -119, 40, 10, 81, 85, 37, -73, 111, 70, -117, 44, 123, -8, -16, -31, 24, -88, -20, 12, -104, 8, -112, 118, 22, -76, 122, 80, 52, 77, 99, -31, -62, -123, 39, 29, 8, 93, -67, 4, -128, 59, -128, 75, -37, 99, 3, 30, 57, 114, -124, 101, -53, -106, 81, 92, 92, -52, -87, -89, -98, -54, -83, -73, -34, 26, -101, -47, 42, 17, 48, 22, -84, -81, -126, 52, 97, -38, 123, 122, 35, -5, 89, -32, -109, -70, -95, 126, 99, -55, 7, -86, -79, 104, 10, -24, 26, 13, -63, 8, -66, -35, -121, 56, -35, -109, 79, -63, -32, -106, 99, -108, -5, -10, -19, -117, -59, 1, 93, 46, 23, -70, -82, -29, 116, 58, -111, 82, 54, -7, -19, 112, 56, 98, 107, -121, -61, 65, 86, 86, 108, -114, 37, 124, 62, -97, 7, 35, 75, 40, -59, -128, 61, 44, 107, 1, 42, 42, 42, -104, 55, 111, 94, -116, -67, -102, 29, -76, 118, 45, 5, 5, 5, -52, -97, 63, -97, -89, -98, 122, -118, -69, -18, -70, -117, -52, -52, 76, -118, -117, -117, -101, 29, 47, -91, 100, 99, 121, -104, -113, -4, 97, 83, -21, -38, 88, -49, -82, 114, 117, 13, 84, -75, 41, -16, 84, -43, 96, 65, 93, 53, 109, 69, -99, -99, 123, 15, 49, 98, -16, 0, 90, 50, 3, -73, 111, -33, 30, 99, -65, 104, 52, 26, -5, -35, -110, 103, 108, 45, -10, -71, 109, -114, 28, 57, -46, 63, -91, -126, 79, -116, -68, 3, -44, 2, -14, -87, -89, -98, 98, -22, -44, -87, -60, 15, 95, 124, -23, -91, -105, -104, 54, 109, -102, 65, -5, 46, 23, -9, -35, 119, 31, 119, -33, 125, 55, 82, 74, -34, 126, -5, -19, -72, 121, 91, 12, -10, -5, -34, -101, -27, -112, 46, 64, -56, -90, -74, -97, -44, 76, -10, -45, 76, -90, 83, 65, 85, 12, -48, -87, -118, -79, 79, 83, 76, -112, -102, -64, -43, 97, -14, -87, -123, 36, 10, 85, 30, 59, 118, -116, -46, -46, -46, 38, -64, -77, -122, -116, -38, -105, 68, -96, -76, 75, 40, 20, 74, 79, -87, -32, 19, 39, -77, -127, 127, -127, -47, 47, 60, 97, -62, 4, 50, 51, 51, 41, 40, 40, -32, -16, -31, -61, 68, -93, -47, -40, -127, -101, 54, 109, -78, -78, -117, 121, -20, -79, -57, 98, -116, 103, -127, 80, 8, -8, -23, -38, 74, -54, 2, 90, 35, -8, 116, 25, 99, -77, 24, -13, 105, 54, -80, -87, 10, -88, 17, -48, -94, -58, -94, -85, 49, -49, 24, 96, -24, -48, 1, 12, -55, -51, 78, -40, -16, 15, 62, -8, 0, -121, -61, -47, 76, 5, -57, 47, -106, -22, -75, -74, -99, 78, 39, -118, -94, -40, 77, 6, -103, 2, -32, -119, -109, -9, -127, 123, -128, -57, -52, -89, 46, 66, -95, -112, 53, -31, 79, 76, -90, 79, -97, 30, 3, 95, -68, -67, 103, -55, -54, -3, 1, 30, -1, -72, 22, -36, 54, -43, -117, -87, 118, 53, -43, -76, -11, -20, -64, -117, 26, -32, 83, 34, -26, -74, 98, 122, -60, 22, 96, -31, -102, -23, 103, -73, -40, -16, 55, -33, 124, 19, 85, 85, 99, 51, 102, 89, -32, 114, 58, -99, -51, -64, -24, 116, 58, -101, 108, -37, 51, 127, -6, -12, -23, -45, -112, 2, -32, -119, -107, -59, 24, -67, 35, -1, -35, -46, -75, 61, -5, -20, -77, -83, -10, 25, -65, 119, 56, -60, -20, -107, 101, -112, -26, 48, 1, 100, 119, 58, -84, 84, 123, -43, 0, -99, 18, 53, 64, 23, 13, 27, 0, 84, -93, -26, 98, 2, 80, 55, -25, 41, 15, -122, -71, -19, -78, -13, -102, -43, 43, -91, -92, -86, -86, -118, -113, 62, -6, -120, -84, -84, -84, 24, -88, 18, -127, -82, 37, 86, 108, 104, 104, -60, -36, -48, -95, 67, 43, 82, 54, -32, -119, -105, 55, -127, 116, -32, 55, 64, -87, -3, 31, -117, 22, 45, 98, -44, -88, 81, -51, -64, 103, 57, 32, -49, 110, -81, 99, -58, 10, 127, 28, -8, 52, -45, -42, 83, 27, -99, 11, 37, 2, -47, 8, 40, -31, -58, 37, 26, 50, 65, 24, 49, -43, -81, 53, 73, -66, -32, -52, -15, 35, 25, 61, 116, 96, -77, 122, -123, 16, 60, -15, -60, 19, -72, 92, -82, 38, 118, 94, 34, -69, 47, -34, 6, -76, -106, -118, -118, 70, -52, -3, -32, 7, 63, 40, 62, -39, 30, 86, -81, -97, -98, -19, -40, -79, 99, -69, 107, 106, 106, -58, 14, 27, 54, -116, -12, -12, -12, -124, -79, 62, 33, 4, -41, -67, 91, -63, -85, 59, -21, -116, -112, -117, -59, 92, -70, 108, 100, 61, -51, -12, 112, -107, -80, 1, 64, 37, 12, -47, 32, 68, -126, 16, 110, 48, -42, -47, -112, -63, -122, -70, -23, -112, 8, 1, 13, 33, 86, 63, 49, -97, -117, 38, -114, 105, -58, 126, 82, 74, -100, 78, 39, -125, 6, 13, 98, -16, -32, -63, 56, 28, -114, 24, -37, 89, 42, -72, -75, 109, -105, -53, -59, -89, -97, 126, -54, -2, -3, -5, 73, 79, 79, 15, 69, 34, -111, 62, 41, 21, 124, -94, -27, -55, -125, 48, 111, 4, -4, -31, -117, -63, 59, 110, 42, -68, 118, 80, -1, -76, -79, -125, 6, -75, -4, -83, -104, -22, -120, -50, -103, -81, -108, 114, -72, 65, 49, 108, 62, 43, -21, -60, 2, -97, 102, 83, -71, -106, -99, 23, 53, 25, 47, 18, -124, 72, -64, -40, 86, -52, -1, 89, -25, 8, 35, 127, 107, -62, 105, -61, -103, 49, -23, -44, -124, 54, -25, 47, 127, -7, 75, 0, 42, 43, 43, 73, 75, 75, 35, 39, 39, -89, 69, -75, -101, 104, 91, 8, 65, 89, 89, 25, -128, -52, -52, -52, -36, 108, -5, 44, 68, -118, 1, 79, 48, 8, 31, 2, -18, 69, -47, 105, -104, -9, 53, -39, -41, -27, 72, 120, -99, -1, 87, 22, -26, -4, -27, -91, -32, 22, 54, -107, 107, 5, -104, 85, 80, -29, -63, 23, 54, -63, 23, 108, 4, 96, 52, 12, -118, -71, 86, 21, -29, 60, 93, 3, -100, 16, 8, -80, 107, -39, 66, -58, -98, -110, -41, -116, -3, -86, -85, -85, -119, 127, 49, -122, 15, 31, 78, 122, 122, 122, 19, -74, 107, -115, 1, 29, 14, 7, -85, 86, -83, 2, 32, 59, 59, -5, 87, -11, -11, -11, 15, -91, 24, -16, 68, -77, 31, 124, 29, -72, -41, 96, 49, -40, 84, 30, 21, 23, 122, -102, 119, -127, -67, -70, -89, -127, -21, -34, 60, 106, -60, -7, -102, -128, 79, 107, -86, 114, 45, -57, 66, 9, 67, 36, 4, 74, -88, 17, 124, -106, -19, -89, -124, -115, 99, -91, 106, 50, -88, 3, 84, -107, -97, 94, 123, 9, -29, 60, -7, 9, -39, -17, -54, 43, -101, -113, 43, 63, 116, -24, 16, -61, -121, 15, 111, 6, -74, 68, 94, -79, -45, -23, -92, -68, -68, 60, 118, -18, 89, 103, -99, -11, -33, -47, 104, -108, -115, 27, 55, -90, 0, 120, -62, 100, -34, 8, 120, -14, -32, -4, -58, -128, -79, -92, -96, 111, 115, 63, -21, -39, -19, 117, -52, 93, 117, -52, 4, -97, -103, -25, 23, 11, 44, -85, -115, -127, 101, 53, 108, 122, -70, -31, 70, -75, 27, 13, 54, -2, -74, -20, 65, -53, -26, -109, 38, -8, -112, -116, 40, -56, -29, -113, 63, -98, -99, -48, -29, 94, -78, 100, 9, 27, 54, 108, 72, 104, -113, 30, 57, 114, -124, -95, 67, -121, -58, -70, -32, -84, -75, -3, -73, -45, -23, 36, 61, 61, -99, 3, 7, 14, -128, -47, 7, 94, -74, 118, -19, -38, -109, 114, 22, -43, -34, 103, 3, -62, 101, 86, 52, -71, -80, -65, -101, -45, -6, 55, -3, -38, -47, -33, -9, 7, -104, -69, -86, 2, -46, 29, -115, 73, 5, -70, -51, -45, -43, -84, 16, 75, -60, 0, 96, 12, 120, -90, -22, 85, 34, -115, -32, 83, -93, -115, -128, -115, -127, 79, 39, 77, -105, 124, -10, 95, -1, -111, 48, -20, -78, 123, -9, 110, 110, -69, -19, -74, 22, 27, 31, -119, 68, -88, -83, -83, 37, 59, 59, 59, -42, -17, -101, 40, 14, 88, 95, 95, 111, 5, -41, -123, -37, -19, 126, 50, 28, 62, 57, -65, 115, -45, -69, -62, 48, 79, 30, -52, 1, -116, 30, 127, 77, 114, 87, 81, -65, -90, 15, -65, 70, -31, -69, 43, -53, 27, -63, -121, -107, 66, 101, -122, 88, -44, -88, -95, 98, 35, 38, -45, -123, -125, 16, 14, 24, 75, 36, 96, 58, 29, 13, -115, 33, 23, 93, 105, 4, -97, -60, -24, 53, 9, 43, -20, -4, -53, 111, -55, -55, 76, 111, 6, -66, -38, -38, 90, -50, 60, -13, -52, 54, 47, -93, -74, -74, -106, 72, 36, -110, -80, 75, -50, -22, -122, 43, 41, 41, -119, -87, -13, 117, -21, -42, 61, 118, -78, 62, -78, -34, -58, -128, -89, -101, -113, 27, 84, -55, 15, -57, 102, 53, 9, -75, -100, -13, -41, -46, 70, -75, 107, -123, 89, -92, 102, 56, 27, 106, -60, 80, -73, -86, -59, 118, 97, 3, -116, 74, 8, 34, -31, 56, -42, -77, -87, 92, -117, 69, -123, -64, 17, 81, -40, -11, -22, 3, -116, 26, 50, -80, -103, 106, -83, -83, -83, 101, -8, -16, -31, -76, -41, 83, -83, -82, -82, 102, -32, -64, -127, -79, 112, -115, 93, 5, 7, 2, 1, 2, -127, 0, 0, -103, -103, -103, -113, 21, 21, 21, -87, 39, -21, 3, 115, -12, 34, -10, 3, -8, -102, -27, -36, 15, -17, -17, 102, 112, 31, 103, -116, 37, 110, 88, 93, 65, -67, -86, 55, -75, -7, 116, -45, -45, -43, -52, 16, -118, 98, -78, 94, 36, 96, 48, 93, -72, 1, 66, 38, -5, 89, -22, -41, 2, 96, 44, 35, -38, 72, 56, -56, 77, 115, -29, -1, -37, 34, -58, 12, 109, 30, -14, 41, 46, 46, -90, -96, -96, -96, -43, -119, -55, -29, 69, 85, 85, 2, -127, 64, -109, -28, 3, 107, 102, -41, 67, -121, 14, 1, 72, -121, -61, -95, 87, 84, 84, -4, 98, -46, -92, 73, -92, 0, -8, 101, 112, 64, 96, -120, 69, -128, -105, -116, -56, -116, -79, -49, -82, 26, -123, -65, 108, -83, 51, -126, 78, 18, -64, -20, 38, -45, 76, -16, 69, 35, 54, -43, 107, -86, -38, -80, -71, 88, 33, 23, 37, -46, -104, 100, 96, 79, -51, 10, -122, -8, 118, -47, 56, -114, -83, -4, 3, 67, 114, -77, 99, 106, -41, -22, 93, 121, -29, -115, 55, 24, 57, 114, 36, -99, -79, -47, -30, -45, -12, 53, 77, -93, -94, -94, -62, 42, 91, 100, 102, 102, -34, -100, -107, -107, -91, 127, -2, -7, -25, 39, -19, 99, -21, 109, 42, -40, -120, 121, 40, 58, 51, -121, 103, -58, 84, -17, 109, 107, -114, 65, -70, -45, 102, -9, 89, 65, -26, 104, 99, -81, 70, -60, 4, 91, -60, 10, -79, -124, 108, 125, -68, -74, -8, -98, 21, -82, -119, 42, 100, -70, -35, -68, -76, -16, 14, -66, 123, -2, -103, 77, 28, 14, -21, -9, 29, 119, -36, -63, -45, 79, 63, -35, -91, 11, 10, 6, -125, 100, 100, 100, 32, -91, 36, 20, 10, 17, 12, 6, 1, -92, -45, -23, -4, 48, 16, 8, -4, -7, 100, 127, 96, -67, 13, -128, 70, -66, -109, 46, 57, 43, -49, -24, 118, 43, -87, 87, 89, 87, 28, -126, 52, 26, -103, -53, 74, 28, -115, -123, 88, 66, 77, 123, 55, -84, 80, -117, 5, -66, 88, 106, -107, -128, 112, 20, -31, -112, -36, -9, -61, 75, 120, -32, -122, 43, -102, -60, -10, 44, -32, 109, -34, -68, -103, -53, 47, -65, -68, 73, 63, 109, 103, 37, 26, -115, -30, 114, -71, 80, 85, 53, 6, 62, 33, 68, 120, -62, -124, 9, 23, 30, 57, 114, 36, 41, 117, -92, 0, -104, 60, 113, 3, 18, -73, 16, -61, -78, -115, 75, -5, -45, -42, 58, -93, -89, -61, 26, 64, 100, -91, -50, 39, -22, -35, -80, 84, -82, 98, -87, 92, -43, -16, 116, -91, -124, -122, 32, 5, 67, 6, 113, -17, -113, 103, 115, -25, 21, 83, -101, 57, 25, 66, 8, 74, 74, 74, -72, -29, -114, 59, 120, -25, -99, 119, -110, 122, 81, -31, 112, -40, 26, 15, 44, 1, -111, -106, -106, 118, -42, -106, 45, 91, 122, -59, -9, -123, 123, 27, 0, 117, 64, 100, -89, 53, -50, -69, -7, -6, -98, 6, -45, -10, 51, -39, 79, 51, 85, -81, 26, 109, -22, -19, 90, -67, 28, 74, -40, -80, 9, 53, -59, 96, -67, -6, 0, -25, 23, -115, 99, -31, 77, 87, 112, -2, -41, 71, 55, 3, 29, -64, -58, -115, 27, 121, -32, -127, 7, -84, -17, -68, 37, -1, -94, 108, -32, 115, -71, 92, 23, 71, 34, -111, 93, -67, -27, -127, -11, 54, 0, 86, 1, 100, -104, -8, 11, 41, 58, -59, 53, 102, -110, -127, 21, 112, -42, -43, -58, 60, 62, -59, -58, -128, -79, 44, 23, -45, -47, 8, -122, -104, 52, -58, -61, 43, -9, -2, -126, -15, -61, -121, 52, 25, 51, -94, -21, 58, -17, -65, -1, 62, 43, 87, -82, 100, -7, -14, -27, 84, 85, 85, 117, -9, 117, 73, 67, -53, -117, 43, 84, 85, 93, -35, -101, 30, 88, 111, 3, -32, -127, -40, -29, 2, -74, -43, -104, -29, 50, -92, 48, 123, 58, -84, 52, 122, -45, -10, 83, 35, 77, -63, 103, 5, -105, 27, 2, 44, -103, 127, 45, 115, 47, -99, 18, 3, -36, -22, -43, -85, 121, -9, -35, 119, 89, -77, 102, 13, 59, 118, -20, -24, -55, 107, -78, 38, 4, 57, 79, 74, -71, -95, -105, 61, -81, 94, 7, -64, 61, 96, 76, 36, 9, 112, -88, 94, -59, -100, -60, -71, 49, -93, -39, -22, -15, -48, -44, -58, 49, 28, 86, -120, 69, 83, -23, -25, -128, 29, -81, 63, -60, 41, 3, -5, -15, -50, 59, -17, -80, 104, -47, 34, -42, -81, 95, 127, 34, -81, -87, 12, 56, 27, 40, -89, 23, 74, 111, 3, -32, 22, -128, 58, -43, 64, 96, -64, 66, 34, -10, 97, -108, 74, 35, -8, 84, 5, 20, 37, 54, -78, -83, -97, 19, 74, 95, 125, -112, 112, -96, -98, -119, 19, 39, -78, 117, -21, -42, 19, 117, 29, 22, -21, 45, 1, 110, -93, 23, 75, -17, -22, 11, -98, 55, 34, 0, -78, 76, 42, -110, -128, -94, -29, 116, -120, -58, -18, 50, 123, -118, -107, 125, 48, -111, 22, -115, -87, -35, -99, -49, -35, 75, -55, -127, 47, -56, -49, -49, 63, 81, -32, -109, 54, 83, 98, 82, 111, 7, 95, -17, 3, -96, 17, 37, 91, -123, 46, -39, 89, -93, 48, 40, -61, -47, 56, 46, -41, -98, -21, 23, 27, 68, 110, -126, 50, 24, -30, -15, 59, 103, 35, -62, 13, -116, 31, 63, -66, -55, 92, 124, 54, 80, -12, -124, 124, 1, 92, 5, -116, -74, -40, -68, -73, 75, 111, 76, 72, -3, 43, 110, 49, -25, 125, 127, -120, -17, -114, -22, 107, -101, -51, -64, 54, -96, -36, -4, 126, -121, 21, 96, 30, -36, -65, 47, 119, 93, 126, 94, -4, 76, -11, -106, 26, 60, -126, 49, 3, -41, 58, -45, 30, -45, -128, -127, -64, 24, -32, 92, -116, -7, -86, -57, 116, 82, -59, 2, 52, 0, 43, -127, 39, -127, -51, 124, -59, -92, -105, -90, -28, 31, -120, 78, -20, -25, 114, 127, -2, -61, 66, -60, -30, 61, 102, -24, 37, 100, -90, 86, -43, 27, 75, -88, -63, 88, 31, -81, -31, -39, 121, 87, 82, -74, -31, 109, 126, -5, -37, -33, -58, 3, 100, 46, -16, 108, 59, 106, -52, 2, 102, 0, -105, 0, -33, 0, 78, 107, -27, -27, -82, 4, 62, -58, -104, 78, 100, -43, 87, -123, -23, -66, 42, 78, -120, 37, 75, -74, -108, 71, -26, 85, -122, 53, -68, -7, -23, -8, -54, -107, -90, -77, 91, 53, -103, -51, 74, -27, -106, -117, -50, 70, -52, -104, 108, 7, 95, 0, 24, 71, -36, -80, -50, 86, -60, 98, -79, -107, -74, 125, 125, 48, -6, -90, 51, -128, -88, 89, -26, 81, 82, -46, 68, 122, -33, 23, -45, -97, 60, 0, -80, 25, -89, -8, -123, -94, 74, -66, -23, -55, 96, -11, 23, 117, 32, -29, 103, 48, 48, -42, 69, -123, -125, 24, 18, 60, -60, -14, -41, 94, -73, -37, 123, -123, 73, 8, 123, 40, 24, -13, -43, 84, 2, 53, 38, 0, 83, -46, -21, -99, -112, 121, 35, 97, -34, -56, 74, 4, 43, -2, -13, -29, 90, -82, 63, -67, -97, -15, 97, 15, -53, -38, -80, 39, -93, -22, 58, -45, 38, -97, -50, 10, 3, 124, -106, 73, 114, 13, 112, 44, 5, -115, 20, 0, 59, 47, 79, 28, 0, -28, -113, 113, -62, -93, -101, 107, -104, 57, 58, -121, -58, 105, -87, 68, -29, 116, 107, -86, -58, -23, -123, 121, 124, 106, -28, -45, 73, -45, 11, 93, -111, -126, 69, 10, -128, 93, -109, -69, 70, -62, 93, -93, 107, 113, 56, -18, -3, -3, -58, 99, -36, 62, 121, 16, -124, 52, 16, -26, -27, -118, 70, 54, -52, 112, -69, 9, 52, 4, 44, -10, 123, 40, 5, -119, 20, 0, -109, 39, 63, 25, -75, -120, 76, -41, -50, 59, 87, -105, -55, 91, -67, -125, 13, -114, 115, -120, 70, 117, -20, 114, 114, -88, -70, -114, -36, -36, -40, -32, -91, 55, 83, -112, 72, 1, 48, 121, -14, -8, 94, 0, -81, 63, -88, 41, 27, -113, -124, 101, 78, 102, 26, 8, -89, 113, -43, 66, -128, -61, -63, -70, 79, -9, 113, -58, -23, -29, -20, 33, -110, -108, -92, 0, -104, 44, 6, 60, 21, 52, -67, 1, -63, -60, -19, 85, 17, 81, -89, 72, -119, -61, 97, 92, -74, 16, 32, 4, -85, 54, -17, 96, -31, -61, -65, -57, -19, 118, 63, -106, -126, 67, 10, -128, -55, -105, -69, -57, -63, 61, -29, 119, -29, 16, -109, 112, 58, 5, -62, 41, 113, -70, -64, -31, 50, 64, -88, 104, -44, -69, -77, -119, 70, -93, -1, -5, -16, -61, 15, -89, 16, -111, 2, 96, 55, -55, 47, 38, 110, 65, 112, 10, 46, 119, 37, 78, 55, 56, 93, -32, 116, -125, -61, -55, -64, -84, 62, 0, -45, -18, -67, -9, -34, 20, 34, 82, 0, -20, 70, 81, -43, 50, 30, -104, -106, -113, -45, -3, 48, -18, 12, 13, 87, 58, 119, -52, -2, 22, 5, 3, -78, -63, -104, -44, 50, 37, 41, -23, 57, 57, 127, -47, -37, 125, -92, -108, 79, -21, -70, -66, 75, 74, 57, -84, -83, -81, -107, -89, 36, 37, 73, 21, 59, -32, 82, -32, 75, 73, 74, -66, -54, 44, -48, 29, 12, -112, -20, 50, -69, -109, -91, 122, -14, -6, -69, -13, -66, 36, -93, -20, -98, -46, 6, 82, 74, -124, -108, 114, 4, -16, 93, -32, 93, 33, -60, -10, 36, -33, -108, 124, -32, -38, 36, 57, 59, 2, -40, 34, -124, 120, -49, 26, -109, 43, -91, -68, 28, 40, 22, 66, 108, 107, -19, -45, 11, 109, -76, 51, 29, -72, 5, 88, 47, -124, -40, 98, -37, 127, 13, 48, -76, 43, -73, 0, 40, 6, -34, 18, 66, 40, 113, 117, -98, 11, 76, -63, -4, -54, 103, 18, -28, -17, 64, -119, 121, 79, -58, 2, 23, -48, -7, 76, 110, 1, -44, 1, -17, 11, 33, -54, 19, -51, 113, 104, -42, -109, 99, 94, -61, 80, 58, -105, -42, 39, -128, -43, 72, 41, -53, -92, 41, -35, -128, -16, 61, 50, -7, 50, -46, 44, 123, -119, 109, -33, 51, 29, 121, 115, 109, -84, 127, -123, -108, 50, 106, 43, -25, 20, 115, -1, -84, 36, -73, -7, 26, 91, -35, -39, -35, 112, 79, 106, 109, -27, 39, 83, -98, -117, -65, 111, 82, -54, 62, 82, -54, 119, -110, 84, -2, 81, 7, -42, 124, 42, 70, 5, 105, 73, -58, -32, -64, 100, -30, -39, 92, 91, -97, 34, -8, -90, -19, 127, -73, 74, 41, 107, 0, 111, 59, -127, -24, -110, 82, -2, 3, -8, 103, -36, -37, 59, -54, 92, -9, 79, 114, -69, -105, 73, 41, 11, -51, 118, 37, -5, -125, -126, 18, 35, -23, -75, 59, -98, -33, -51, 82, -54, -97, -40, -103, 15, 56, 4, 124, 59, 73, -19, 110, -10, 5, 101, -39, 13, 55, -57, -82, 38, 66, 93, 84, 13, -101, 108, 102, -126, 22, -9, -1, 126, -64, 38, 41, -27, -77, 66, -120, -71, -83, -88, -114, 111, 99, 100, 46, 103, -40, -54, -115, 111, -81, -67, -115, -59, 24, -29, 65, 58, 106, 70, -92, 3, -33, -73, 109, -33, 46, -124, -72, 55, -18, -27, 8, 3, 127, -91, -13, -103, -23, -62, 84, -29, 45, 13, 27, 120, -119, -114, 15, -69, 112, 0, -1, 102, -34, 79, -128, 59, -127, -57, -51, 123, -9, -37, 56, 82, 41, 3, 86, 3, -111, 78, -74, -3, 69, -92, -108, -11, 54, 74, 116, 39, 89, 5, 31, -77, -107, 61, 56, -55, 101, 127, 102, -106, -85, -57, -83, -91, -108, -78, 70, 74, -23, -115, 83, -73, 78, 41, -27, 10, -37, -79, -42, -15, -86, -19, -68, -13, -51, 99, 111, -76, -19, 123, -87, 11, 109, -100, 103, -85, 111, -91, -71, 111, -104, 93, 5, 37, -7, -98, -92, -39, -11, 91, 23, -54, 25, 108, 43, 70, -73, -19, -33, 111, -37, -1, -41, 100, -76, -71, 39, 123, 66, -46, 58, 121, 51, -38, -13, 38, -51, 4, -2, -49, -58, 94, 22, 27, 62, 99, -66, -71, -45, -127, 122, 27, 35, 9, -109, 65, 103, 2, 31, -75, 81, 126, 87, -122, 45, 84, -38, -22, 115, -76, -48, -10, 47, 99, 84, -92, -70, -123, 54, -114, -76, -3, -98, -105, -24, -39, 116, 20, -9, 61, 57, 40, -23, 7, -90, -99, -42, 81, -102, -34, 101, 3, 87, 75, 18, 16, 66, 76, -107, 82, -34, 4, 60, 111, 83, -95, -73, 74, 41, -81, 51, -19, 70, -21, -93, -65, 2, 120, 15, -72, 76, 8, 17, -111, 82, 46, 106, -93, -20, -47, 82, -54, 27, 58, 120, -81, 36, -112, 11, -4, -54, 86, -25, -95, 4, -57, 101, -104, -19, -53, -24, -60, 125, 121, 23, -16, -73, -26, -7, 75, 41, 111, -20, -60, 11, 36, -127, -101, 108, -37, -91, -74, 104, 65, 99, 3, -124, 104, 41, 117, -19, 84, 41, -27, -65, -75, 81, 71, 4, 120, 79, 8, -79, -73, -89, 84, -80, -34, 69, 111, -23, 107, -83, -88, 96, 41, -91, -4, -90, 109, 127, -82, -108, 114, 115, -126, 122, 117, 41, -91, 38, -91, -4, -9, 56, -43, -4, 73, 27, 42, -72, 43, 98, -43, 31, -106, 82, -114, 49, -67, -56, 97, 73, 42, -69, -86, 13, 21, -84, 39, -87, -98, 69, 22, 0, 19, -87, -27, 4, 109, -48, 58, 80, -10, 92, 71, -110, -87, -69, 37, 10, -18, -84, -86, -79, 10, -53, -18, -64, 57, -75, 66, -120, -55, -64, 93, -40, 102, -123, 6, 62, 4, -6, 9, 33, 94, 53, -33, -32, -98, 96, 125, -85, -110, 32, -55, 77, 118, -107, 64, -33, 118, -42, -35, -111, -5, 44, -29, 28, -80, 79, -124, 16, -65, -20, -96, 90, 117, 116, -64, -47, -4, -99, 43, -119, -32, 27, 44, -91, -68, -42, 84, -105, -119, 70, -8, -1, -125, -114, 15, 77, 20, -64, -25, 66, -120, 109, -19, 62, 33, -10, -43, 115, -15, -92, -108, -14, -97, 24, -29, 60, -2, 37, -124, 88, -38, 73, -69, -68, 24, 88, -33, 9, 123, 57, 19, -29, 43, -18, -46, 12, -67, -4, 84, 8, -15, -101, -72, 54, 68, -128, -27, -99, 48, -123, 28, -64, 115, -19, 56, -18, -107, 4, 64, -44, 77, 47, 119, 64, -36, 125, 62, 106, 70, 7, 114, -52, -105, -27, 109, 33, -60, 106, 91, -12, -96, -67, -128, -98, 9, 92, -33, -58, 11, -16, -17, -26, 58, 55, 105, 42, 88, 74, -7, -123, -83, -100, -52, 30, -12, -126, -101, -88, -32, -114, 26, -60, 82, -54, -11, 61, -28, 5, 47, -5, 50, 121, -63, 82, -54, 7, 18, 68, 4, 62, -106, 82, -98, -35, -46, -67, -117, 83, -97, -103, 93, 104, -89, 37, -31, 100, 122, -63, 57, -74, -33, -3, -109, -27, 5, 119, 73, -1, -75, 79, -51, -74, -123, -46, -82, 120, -63, -43, 109, 68, 28, 68, 23, 1, -41, -107, 123, -13, 107, 32, 15, -8, -105, -51, 84, 41, 2, 54, 75, 41, -41, 90, 30, 111, 92, 29, -10, 23, -26, 63, -110, -15, -116, -30, -87, 127, -114, -108, -78, 51, 95, -35, -119, -60, 1, 76, -74, -32, 5, 87, 119, -47, -98, -38, 38, -124, -16, -11, 48, -114, 79, -107, 82, -50, 107, -89, 10, -50, -79, 93, 123, 58, -16, 19, -102, 78, 114, -44, -110, 23, -100, -34, 69, 16, -66, 69, -25, -90, -3, -88, 20, 66, 92, 36, -91, -68, 16, 88, -122, -11, -103, 11, -104, 10, -20, 55, 89, 123, -82, -108, -78, -63, 124, -103, -1, -127, 49, 95, -114, 4, 126, 99, -58, 90, -33, -64, -104, 122, -92, -45, 23, 80, -97, 100, -81, 73, 74, 41, -121, 38, -39, 11, -74, -53, -80, 4, 42, 120, 74, 23, -82, -1, -125, 86, 84, -80, -98, 36, 47, 88, 74, 41, 39, 37, -39, 11, -74, 75, 101, 87, 2, -47, 54, 7, -14, 87, 9, -54, 62, 102, 29, 99, -21, -57, -42, -69, 120, 127, -84, -13, 106, 29, 38, 122, 101, -110, -126, -94, -46, -58, -120, 96, 116, 53, 37, -69, -20, 92, -101, 49, 109, -19, -21, -54, 84, 26, -10, 76, -107, 96, -36, 62, -47, -59, -10, 90, -25, -1, 63, 33, -60, -25, 38, -117, 4, -37, -87, -6, 59, 82, 79, -74, -87, 86, -93, -74, 125, 74, 39, 28, -73, -123, -26, -3, 125, -53, 86, 78, -125, 117, -116, 16, -94, 30, 24, 107, 51, 45, 68, 23, -81, -29, 25, 23, -16, 61, -32, -26, 36, -35, 16, 1, -84, 17, 66, 88, 13, -100, 5, -36, -99, -60, -78, 63, 23, 66, 88, 83, -105, 94, 11, -4, -36, 12, 21, -20, -19, -126, -6, -70, -34, 12, 24, -17, 20, 66, 124, 98, -13, 30, 39, -47, -75, 116, -84, -80, -23, 65, -65, 38, -124, -40, 99, 15, -32, 74, 41, -25, -46, -75, -108, -87, -8, -5, -14, -126, 109, 123, 22, 112, 37, -58, -100, -122, -99, -111, -29, 66, -120, -53, 77, -83, -14, 99, -32, -105, 113, -3, -22, 123, -123, 16, -125, -92, -108, 51, -128, 11, -127, 83, 58, 17, 33, 80, 77, 47, -5, 53, 78, 86, 73, 86, -10, 88, 50, -70, -109, 122, -94, -99, 39, -22, -2, -10, 84, 82, 109, 74, 82, -110, -110, -108, -92, 36, 37, 41, 73, 73, 74, 82, -110, 28, -15, -7, 123, -26, -100, -8, -13, 58, 82, 70, 71, -50, -21, 108, 29, 39, -78, -116, -8, 99, 123, -14, -103, -76, -45, -123, -17, 110, -16, -67, 10, 92, -122, -47, 57, 47, -37, 104, -53, 110, -68, -98, 51, -52, -13, 111, 4, -18, -61, -104, -81, -71, -91, -13, 74, -128, -121, -15, 122, -2, 108, -98, -13, 30, 112, 6, 94, 79, 126, 7, -37, 106, 124, -4, -51, -21, 25, -33, -114, 99, -85, 1, 31, 94, -49, 37, -8, -4, -91, 64, 65, 7, 106, 122, 25, -81, -25, 122, 124, -2, 16, -16, 6, 94, -49, -43, 102, -103, -13, 48, 66, 74, 67, 90, -72, 86, -119, -15, -15, -102, 95, -29, -11, -4, -51, -42, 102, 7, -16, 109, -68, -98, -110, 54, -38, 124, 4, -40, -118, -41, 115, 49, 62, -1, 32, -116, 30, -115, 51, 105, 59, 9, -62, 1, 60, -125, -41, 115, 103, 119, -63, -92, -5, 18, 82, -67, 30, -16, -7, 23, 97, -60, -21, 116, -116, -82, 34, -47, 6, 0, -113, -102, 55, 108, 22, -115, 113, -84, 74, -116, -72, 81, -68, -72, 49, -66, -49, -79, 20, -97, 63, -120, -41, -77, -62, -36, -50, -61, -25, 23, 120, 61, 29, -119, 19, -116, 108, 39, 80, 29, 24, -3, -36, -42, -124, -126, 7, 48, -6, -118, -19, -23, 76, -3, 48, 18, 96, -85, 105, -38, 69, 37, -128, -61, -8, -4, 105, 24, 9, -88, 99, -51, 50, 111, 1, -98, 48, -113, -87, 32, -15, 80, -51, 116, -116, 79, 63, -68, -114, -49, 127, 17, 94, -49, 26, -64, -125, 17, -128, 46, -58, -25, 127, 16, -81, -25, -41, -8, -4, -58, 125, 111, -38, 102, -105, 9, 108, 43, 0, -2, 22, 112, 14, 70, -100, -78, -70, 29, 0, -20, -42, 79, -127, 118, 119, 70, -12, 55, -52, -75, 7, -81, -25, 72, 7, -50, -5, -87, -71, -2, 94, -20, -115, 79, 12, -120, -85, 49, -46, -103, 126, -122, 49, -73, 115, -94, 65, 69, -19, -111, -50, 29, -17, -11, -100, -97, -96, 77, 127, 0, -26, 3, -77, -16, 122, 62, 72, -16, -1, -52, -72, 58, -83, 107, -67, 16, 34, 122, 42, -82, 0, 0, 2, -107, 73, 68, 65, 84, -81, -25, 95, -83, 92, -21, -19, -64, -97, -128, 123, -128, 53, -26, 94, -51, 124, -122, -9, -29, -13, -49, -63, 72, -123, -38, 25, 7, -60, -8, 123, 82, 4, 68, -16, 122, -6, 116, 72, -101, -59, 3, -5, 36, 1, 96, -67, -71, -66, 27, -97, 127, 67, 27, 12, -72, 25, -81, -57, 31, 3, -84, -15, -128, -1, -42, 6, -53, -82, -64, -25, 95, 14, 12, -1, 18, 89, -66, 86, 98, 65, 123, -45, -107, 60, 64, -76, 85, -16, 25, -14, -84, 9, 64, -5, -75, -22, 38, 35, 111, 0, 78, 7, 118, -32, -13, 63, -114, -41, -13, -45, 86, 64, 19, 0, 114, 77, -26, 109, 45, 73, 86, 1, -42, -32, -11, -124, -70, 11, 124, 61, 1, -64, -57, 76, -5, 111, -66, -71, -76, -11, -90, -35, -126, -41, -13, 124, 15, 48, -40, -105, 73, -100, -19, 108, -65, 35, -127, -35, -18, -64, -21, -87, 5, -58, -29, -13, -1, 2, -8, 61, -16, 19, 124, -2, -21, 49, -110, 78, 63, 76, 80, -50, 98, -32, 1, -38, -9, 5, 40, -16, -7, -65, 14, 108, 63, 57, 25, -48, -21, 89, -117, -49, 127, 42, 112, -123, 105, -77, -75, 36, -89, 96, -116, 63, -3, 61, -58, -96, -94, -114, 58, 71, 29, 119, -90, 12, 6, 80, -16, 122, 94, -20, -64, 89, 122, 55, 0, 94, 38, -27, 56, -81, -25, 17, 124, -2, -65, 0, -1, 11, 124, 29, -40, -120, -49, -1, 18, 94, -49, -113, -102, 120, -79, 94, -49, -125, -8, -4, -21, 109, -26, 81, 75, -41, 121, 30, 112, 57, -80, 16, -81, -25, -54, -109, -107, 1, -63, -21, -39, 103, 50, 97, 91, -128, -72, -119, -58, 76, -105, 106, 96, 36, 62, -1, -39, 120, 61, 31, -73, 114, -50, 68, -13, -41, -47, 102, 14, 80, -37, -14, 95, -90, 97, -2, -94, 121, -2, -41, -16, -7, 71, -32, -11, 28, 108, -27, 28, 43, -19, -85, 52, 9, 119, 70, -73, -75, 125, 20, 62, -1, 72, -68, -98, 3, -83, 28, 111, -39, -101, -83, 125, -63, -23, 40, 94, -49, 25, -8, -4, 63, 1, -2, 19, -72, 30, -97, -1, -86, 102, -114, -115, -41, -77, 22, -29, 91, 117, -83, 61, -113, 103, 48, -66, -12, 52, -80, 59, -31, -47, -67, 0, 52, 88, -26, 71, -76, 61, 9, -49, 0, -45, 102, -78, 30, -2, 75, 24, 95, 9, -33, -116, -49, -1, 97, 11, 94, -80, 11, -29, 107, -107, 70, 120, -61, -50, -124, -58, 27, -34, 26, 99, 104, -26, -79, 81, 91, 125, -65, 6, 14, -104, -74, -86, -34, -126, -41, 109, -79, -58, 95, -38, -63, 84, 109, -79, 114, -56, 86, -9, -17, -128, 47, -16, -7, 55, -74, 80, 119, 26, -26, -76, 35, -26, -15, 45, 71, 30, -116, -11, -29, -8, -4, -81, 98, 124, 12, -15, -84, 38, -9, -62, -25, 127, 18, 35, -45, 71, -74, 113, 13, -93, -51, -11, -2, -109, -39, 11, -66, -54, -58, 26, 109, 73, 29, -42, -64, 113, -81, -25, 73, 124, -2, 97, -90, -35, 120, 110, 27, -25, 61, -114, -41, 99, 49, -84, 21, 106, 56, -81, -99, 117, 106, 102, 125, -65, -63, -25, 31, -118, 49, 75, -42, -108, 54, 30, -52, 67, 120, 61, 47, -76, 114, 76, -125, -71, 110, 105, 12, 116, -92, -55, -38, -21, 121, 0, -97, -65, 0, 35, -45, 120, 74, 27, -116, -71, -48, 102, 50, 68, -38, 120, 126, -107, 120, 61, 103, -29, -13, -33, 6, 60, 109, 123, -119, 111, -95, -3, 25, -40, 95, 0, 119, 117, -89, 23, -36, -99, -20, -41, 115, -25, 118, 54, -62, -33, -39, 115, 91, 58, -66, 61, -27, 36, -69, 103, -94, -77, -67, 62, 61, -15, 28, -37, 33, -1, 31, -104, -78, -26, 106, 89, 21, 20, 3, 0, 0, 0, 0, 73, 69, 78, 68, -82, 66, 96, -126, };\n\t//public final static byte LOGO[] = null;\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/utils/Size.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.utils;\n\npublic class Size {\n\n\tprivate int width;\n\tprivate int height;\n\t\n\tpublic Size(int width, int height)\n\t{\n\t\tthis.width = width;\n\t\tthis.height = height;\n\t}\n\n\tpublic int getWidth() {\n\t\treturn width;\n\t}\n\n\tpublic void setWidth(int width) {\n\t\tthis.width = width;\n\t}\n\n\tpublic int getHeight() {\n\t\treturn height;\n\t}\n\n\tpublic void setHeight(int height) {\n\t\tthis.height = height;\n\t}\n\t\n}\n"
  },
  {
    "path": "mAppWidget/mappwidgetlib/src/main/java/com/ls/widgets/map/utils/TransformUtils.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.widgets.map.utils;\n\nimport android.graphics.Matrix;\nimport android.graphics.Rect;\n\npublic class TransformUtils \n{\n    private static final Matrix matrix = new Matrix();\n    \n\tpublic static Rect scaleRect(Rect coords, float scale, int pivotX, int pivotY)\n\t{\n\t    matrix.reset();\n\t\tmatrix.setScale(scale, scale, pivotX, pivotY);\n\t\t\n\t\tfloat[] result = {coords.left, coords.top, coords.right, coords.bottom};\n\t\tmatrix.mapPoints(result);\n\t\t\n\t\treturn new Rect((int)result[0], (int)result[1], (int)result[2], (int)result[3]);\n\t}\n}\n"
  },
  {
    "path": "mAppWidget/settings.gradle",
    "content": "include ':demo1app', ':demo2app', ':mappwidgetlib'\n"
  },
  {
    "path": "slicingtool/.classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6\"/>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.pde.core.requiredPlugins\"/>\n\t<classpathentry kind=\"src\" path=\"src\"/>\n\t<classpathentry kind=\"lib\" path=\"libs/org.eclipse.core.resources.jar\"/>\n\t<classpathentry kind=\"output\" path=\"bin\"/>\n</classpath>\n"
  },
  {
    "path": "slicingtool/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>com.ls.mappwidget.slicingtool</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.pde.ManifestBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.pde.SchemaBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>org.eclipse.pde.PluginNature</nature>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "slicingtool/.settings/org.eclipse.jdt.core.prefs",
    "content": "eclipse.preferences.version=1\norg.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\norg.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate\norg.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\norg.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve\norg.eclipse.jdt.core.compiler.compliance=1.6\norg.eclipse.jdt.core.compiler.debug.lineNumber=generate\norg.eclipse.jdt.core.compiler.debug.localVariable=generate\norg.eclipse.jdt.core.compiler.debug.sourceFile=generate\norg.eclipse.jdt.core.compiler.problem.assertIdentifier=error\norg.eclipse.jdt.core.compiler.problem.enumIdentifier=error\norg.eclipse.jdt.core.compiler.source=1.6\n"
  },
  {
    "path": "slicingtool/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Slicingtool\nBundle-SymbolicName: com.ls.mappwidget.slicingtool;singleton:=true\nBundle-Version: 1.0.0.qualifier\nBundle-Activator: com.ls.mappwidget.slicingtool.Activator\nBundle-Vendor: LS\nRequire-Bundle: org.eclipse.ui,\n org.eclipse.core.runtime,org.eclipse.core.resources\nBundle-RequiredExecutionEnvironment: JavaSE-1.6\nBundle-ActivationPolicy: lazy\nBundle-ClassPath: libs/org.eclipse.core.resources.jar,\n .\n"
  },
  {
    "path": "slicingtool/build.properties",
    "content": "source.. = src/\noutput.. = bin/\nbin.includes = plugin.xml,\\\n               META-INF/,\\\n               .,\\\n               icons/,\\\n               contexts.xml,\\\n               libs/org.eclipse.core.resources.jar\n"
  },
  {
    "path": "slicingtool/contexts.xml",
    "content": "<contexts>\n\t<context id=\"viewer\" title=\"mAppWidget\">\n\t\t<description>This is the context help for the sample view with a table viewer. It was generated by a PDE template.</description>\n\t\t<topic href=\"/PLUGINS_ROOT/org.eclipse.platform.doc.isv/guide/ua_help_context.htm\" label=\"Context-sensitive help\">\n\t\t\t<enablement>\n\t\t\t\t<with variable=\"platform\">\n\t            \t<test property=\"org.eclipse.core.runtime.isBundleInstalled\" args=\"org.eclipse.platform.doc.isv\"/>\n\t     \t\t</with>\n\t\t\t</enablement>\n\t\t</topic>\n\t</context>\n</contexts>\n"
  },
  {
    "path": "slicingtool/plugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?eclipse version=\"3.4\"?>\n<plugin>\n\n   <extension\n         point=\"org.eclipse.ui.views\">\n      <category\n            name=\"mAppWidget\"\n            id=\"com.ls.mappwidget.slicingtool\">\n      </category>\n      <view\n            name=\"Map Slicing Tool\"\n            icon=\"icons/sample.gif\"\n            category=\"com.ls.mappwidget.slicingtool\"\n            class=\"com.ls.mappwidget.slicingtool.views.MainView\"\n            id=\"com.ls.mappwidget.slicingtool.views.MainView\">\n      </view>\n   </extension>\n   <extension\n         point=\"org.eclipse.ui.perspectiveExtensions\">\n      <perspectiveExtension\n            targetID=\"org.eclipse.jdt.ui.JavaPerspective\">\n         <view\n               ratio=\"0.5\"\n               relative=\"org.eclipse.ui.views.TaskList\"\n               relationship=\"right\"\n               id=\"com.ls.mappwidget.slicingtool.views.MainView\">\n         </view>\n      </perspectiveExtension>\n   </extension>\n   <extension\n         point=\"org.eclipse.help.contexts\">\n      <contexts\n            file=\"contexts.xml\">\n      </contexts>\n   </extension>\n\n</plugin>\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/Activator.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool;\n\nimport org.eclipse.jface.resource.ImageDescriptor;\nimport org.eclipse.ui.plugin.AbstractUIPlugin;\nimport org.osgi.framework.BundleContext;\n\n/**\n * The activator class controls the plug-in life cycle\n */\npublic class Activator extends AbstractUIPlugin {\n\n\t// The plug-in ID\n\tpublic static final String PLUGIN_ID = \"com.ls.anymaps.slicingtool\"; //$NON-NLS-1$\n\n\t// The shared instance\n\tprivate static Activator plugin;\n\t\n\t/**\n\t * The constructor\n\t */\n\tpublic Activator() {\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)\n\t */\n\tpublic void start(BundleContext context) throws Exception {\n\t\tsuper.start(context);\n\t\tplugin = this;\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)\n\t */\n\tpublic void stop(BundleContext context) throws Exception {\n\t\tplugin = null;\n\t\tsuper.stop(context);\n\t}\n\n\t/**\n\t * Returns the shared instance\n\t *\n\t * @return the shared instance\n\t */\n\tpublic static Activator getDefault() {\n\t\treturn plugin;\n\t}\n\n\t/**\n\t * Returns an image descriptor for the image file at the given\n\t * plug-in relative path\n\t *\n\t * @param path the path\n\t * @return the image descriptor\n\t */\n\tpublic static ImageDescriptor getImageDescriptor(String path) {\n\t\treturn imageDescriptorFromPlugin(PLUGIN_ID, path);\n\t}\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/cutter/Constants.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.cutter;\n\npublic class Constants\n{\n\tpublic static class Tag\n\t{\n\t\tpublic static final String IMAGE = \"Image\";\n\n\t\tpublic static final String SIZE = \"Size\";\n\n\t\tpublic static final String CALIBRATIONRECT = \"CalibrationRect\";\n\n\t\tpublic static final String POINT = \"Point\";\n\t}\n\n\tpublic static class Attr\n\t{\n\t\tpublic static final String TILE_SIZE = \"TileSize\";\n\n\t\tpublic static final String OVERLAP = \"Overlap\";\n\n\t\tpublic static final String FORMAT = \"Format\";\n\n\t\tpublic static final String WIDTH = \"Width\";\n\n\t\tpublic static final String HEIGHT = \"Height\";\n\n\t\tpublic static final String X = \"x\";\n\n\t\tpublic static final String Y = \"y\";\n\n\t\tpublic static final String LAT = \"lat\";\n\n\t\tpublic static final String LON = \"lon\";\n\n\t\tpublic static final String TOPLEFT = \"topLeft\";\n\t}\n\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/cutter/Cutter.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.cutter;\n\nimport java.awt.Graphics2D;\nimport java.awt.RenderingHints;\nimport java.awt.image.BufferedImage;\nimport java.io.File;\nimport java.io.IOException;\n\nimport javax.imageio.ImageIO;\n\nimport com.ls.mappwidget.slicingtool.views.MainView;\nimport com.ls.mappwidget.slicingtool.vo.PointVO;\n\npublic class Cutter\n{\n\tprivate OnProgressUpdateListener onUpdate;\n\n\tprivate OnCompliteListener onComplite;\n\n\tpublic Cutter(OnProgressUpdateListener listener, OnCompliteListener onComplite)\n\t{\n\t\tthis.onUpdate = listener;\n\t\tthis.onComplite = onComplite;\n\t}\n\n\tpublic void startCuttingAndroid(final String inFile, final String outDir, final String mapName, final int tileSize, final PointVO pointTopLeft, final PointVO pointBottomRight)\n\t{\n\t\tnew Thread(new Runnable()\n\t\t{\n\t\t\t@Override\n\t\t\tpublic void run()\n\t\t\t{\n\t\t\t\tFile fileXml = new File(outDir, mapName);\n\t\t\t\tcreateDir(fileXml);\n\n\t\t\t\tFile file = new File(outDir, mapName + File.separator + mapName + \"_files\");\n\t\t\t\tcreateDir(file);\n\n\t\t\t\tString temp = file.getAbsolutePath() + File.separator + \"tmp.png\";\n\t\t\t\tsaveImage(inFile, \"png\", temp);\n\n\t\t\t\tint count = (int) Math.ceil(Math.log(getMaxSide(temp)) / Math.log(2));\n\t\t\t\tMainView.PROGRESS_MAX = count;\n\n\t\t\t\tfor (int i = count; i >= 0; i--)\n\t\t\t\t{\n\t\t\t\t\tFile fdir = new File(file.getAbsoluteFile(), File.separator + i);\n\t\t\t\t\tcreateDir(fdir);\n\n\t\t\t\t\tif (i == count)\n\t\t\t\t\t{\n\t\t\t\t\t\timageCut(temp, fdir.getAbsolutePath(), tileSize, fileXml.getAbsoluteFile() + File.separator + mapName + \".xml\", true, \"\", pointTopLeft, pointBottomRight);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\timageCut(temp, fdir.getAbsolutePath(), tileSize, null, false, \"\", pointTopLeft, pointBottomRight);\n\t\t\t\t\t}\n\n\t\t\t\t\timageResize(temp, temp, 50);\n\t\t\t\t\tonUpdate.onProgressUpdate(count - i + 1);\n\t\t\t\t}\n\n\t\t\t\tFile tmp = new File(temp);\n\t\t\t\ttmp.delete();\n\t\t\t\tonComplite.onComplite();\n\t\t\t}\n\t\t}).start();\n\t}\n\n\tprivate void createDir(File file)\n\t{\n\t\tif (!file.exists())\n\t\t{\n\t\t\tfile.mkdirs();\n\t\t}\n\t}\n\n\tprivate void imageCut(String inFile, String outDir, int tileSize, String mapName, boolean xml, String concut, PointVO pointTopLeft, PointVO pointBottomRight)\n\t{\n\t\tString s = \"\";\n\n\t\tif (!outDir.endsWith(File.separator))\n\t\t{\n\t\t\ts = File.separator;\n\t\t}\n\n\t\tBufferedImage image = getImage(inFile);\n\n\t\tint w = image.getWidth();\n\t\tint h = image.getHeight();\n\n\t\tif (xml)\n\t\t{\n\t\t\tImageXML.createXML(mapName, tileSize, w, h, pointTopLeft, pointBottomRight);\n\t\t}\n\n\t\tif (w < tileSize && h < tileSize)\n\t\t{\n\t\t\tsaveImage(image, \"png\", outDir + s + concut + \"0_0.png\");\n\t\t\treturn;\n\t\t}\n\n\t\tfor (int i = 0, k = 0; i < w - 1; i += tileSize, k++)\n\t\t{\n\t\t\tfor (int j = 0, l = 0; j < h - 1; j += tileSize, l++)\n\t\t\t{\n\t\t\t\tint tileWidth = tileSize;\n\t\t\t\tint tileHeight = tileSize;\n\n\t\t\t\tif (tileWidth > (w - i - 1))\n\t\t\t\t{\n\t\t\t\t\ttileWidth = w - i - 1;\n\t\t\t\t}\n\n\t\t\t\tif (tileHeight > (h - j - 1))\n\t\t\t\t{\n\t\t\t\t\ttileHeight = h - j - 1;\n\t\t\t\t}\n\n\t\t\t\tBufferedImage part = image.getSubimage(i, j, tileWidth, tileHeight);\n\t\t\t\tsaveImage(part, \"png\", outDir + s + concut + k + \"_\" + l + \".png\");\n\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean imageResize(String outFile, String inFile, int percents)\n\t{\n\t\tBufferedImage originalImage;\n\n\t\toriginalImage = getImage(inFile);\n\t\tint type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();\n\n\t\tBufferedImage resizedImage = doResize(originalImage, type, percents);\n\t\tsaveImage(resizedImage, \"png\", outFile);\n\n\t\treturn true;\n\t}\n\n\tprivate BufferedImage doResize(BufferedImage originalImage, int type, int percents)\n\t{\n\n\t\tint h = (int) Math.round((originalImage.getHeight() * percents / 100.0));\n\t\tint w = (int) Math.round((originalImage.getWidth() * percents / 100.0));\n\n\t\tif (h <= 0)\n\t\t{\n\t\t\th = 1;\n\t\t}\n\n\t\tif (w <= 0)\n\t\t{\n\t\t\tw = 1;\n\t\t}\n\n\t\tBufferedImage resizedImage = new BufferedImage(w, h, type);\n\t\tGraphics2D g = resizedImage.createGraphics();\n\n\t\t\n\t\t\n\t\tg.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);\n\t\tg.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);\n\t\tg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);\n\t\t\n\t\tg.drawImage(originalImage, 0, 0, w, h, null);\n\t\t\n\t\tg.dispose();\n\n\t\treturn resizedImage;\n\t}\n\n\tpublic int getWidth(String fileName)\n\t{\n\t\tBufferedImage image = getImage(fileName);\n\n\t\tif (image == null)\n\t\t{\n\t\t\treturn -1;\n\t\t}\n\n\t\tint width = image.getWidth();\n\t\treturn width;\n\t}\n\n\tprivate int getMaxSide(String fileName)\n\t{\n\t\tBufferedImage image = getImage(fileName);\n\t\tint width = image.getWidth();\n\t\tint height = image.getHeight();\n\n\t\tif (width > height)\n\t\t{\n\t\t\treturn width;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn height;\n\t\t}\n\t}\n\n\tprivate BufferedImage getImage(String fileName)\n\t{\n\t\ttry\n\t\t{\n\t\t\tBufferedImage image = ImageIO.read(new File(fileName));\n\t\t\treturn image;\n\n\t\t} catch (IOException e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate boolean saveImage(String inFile, String formatName, String fileName)\n\t{\n\t\ttry\n\t\t{\n\t\t\tBufferedImage image = getImage(inFile);\n\t\t\tImageIO.write(image, formatName, new File(fileName));\n\t\t\treturn true;\n\n\t\t} catch (IOException e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate boolean saveImage(BufferedImage image, String formatName, String fileName)\n\t{\n\t\ttry\n\t\t{\n\t\t\tImageIO.write(image, formatName, new File(fileName));\n\t\t\treturn true;\n\n\t\t} catch (IOException e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/cutter/ImageXML.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.cutter;\n\nimport org.w3c.dom.Attr;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\n\nimport com.ls.mappwidget.slicingtool.utils.XMLUtils;\nimport com.ls.mappwidget.slicingtool.vo.PointVO;\n\npublic class ImageXML\n{\n\tpublic static void createXML(String fileName, int tileSize, int w, int h, PointVO pointTopLeft, PointVO pointBottomRight)\n\t{\n\t\tDocument doc = XMLUtils.createDoc();\n\n\t\tElement rootElement = doc.createElement(Constants.Tag.IMAGE);\n\t\tdoc.appendChild(rootElement);\n\t\taddRootAttr(rootElement, doc, tileSize);\n\n\t\tElement sizeElement = doc.createElement(Constants.Tag.SIZE);\n\t\trootElement.appendChild(sizeElement);\n\t\taddSizeAttr(sizeElement, doc, w, h);\n\n\t\tif (pointTopLeft != null)\n\t\t{\n\t\t\tElement colibrElement = doc.createElement(Constants.Tag.CALIBRATIONRECT);\n\t\t\trootElement.appendChild(colibrElement);\n\n\t\t\tElement pointElement = doc.createElement(Constants.Tag.POINT);\n\t\t\tcolibrElement.appendChild(pointElement);\n\t\t\taddPointAttr(pointElement, doc, pointTopLeft, true);\n\n\t\t\tpointElement = doc.createElement(Constants.Tag.POINT);\n\t\t\tcolibrElement.appendChild(pointElement);\n\t\t\taddPointAttr(pointElement, doc, pointBottomRight, false);\n\t\t}\n\t\t\n\t\tXMLUtils.saveDoc(doc, fileName);\n\t}\n\n\tprivate static void addPointAttr(Element pointElement, Document doc, PointVO point, boolean b)\n\t{\n\t\tAttr attr = doc.createAttribute(Constants.Attr.X);\n\t\tattr.setValue(point.getX() + \"\");\n\t\tpointElement.setAttributeNode(attr);\n\n\t\tattr = doc.createAttribute(Constants.Attr.Y);\n\t\tattr.setValue(point.getY() + \"\");\n\t\tpointElement.setAttributeNode(attr);\n\n\t\tattr = doc.createAttribute(Constants.Attr.LAT);\n\t\tattr.setValue(point.getLat() + \"\");\n\t\tpointElement.setAttributeNode(attr);\n\n\t\tattr = doc.createAttribute(Constants.Attr.LON);\n\t\tattr.setValue(point.getLon() + \"\");\n\t\tpointElement.setAttributeNode(attr);\n\n\t\tif (b)\n\t\t{\n\t\t\tattr = doc.createAttribute(Constants.Attr.TOPLEFT);\n\t\t\tattr.setValue(\"1\");\n\t\t\tpointElement.setAttributeNode(attr);\n\t\t}\n\t}\n\n\tprivate static void addSizeAttr(Element sizeElement, Document doc, int w, int h)\n\t{\n\t\tAttr attr = doc.createAttribute(Constants.Attr.WIDTH);\n\t\tattr.setValue(\"\" + w);\n\t\tsizeElement.setAttributeNode(attr);\n\n\t\tattr = doc.createAttribute(Constants.Attr.HEIGHT);\n\t\tattr.setValue(\"\" + h);\n\t\tsizeElement.setAttributeNode(attr);\n\t}\n\n\tprivate static void addRootAttr(Element rootElement, Document doc, int tileSize)\n\t{\n\t\tAttr attr = doc.createAttribute(Constants.Attr.TILE_SIZE);\n\t\tattr.setValue(\"\" + tileSize);\n\t\trootElement.setAttributeNode(attr);\n\n\t\tattr = doc.createAttribute(Constants.Attr.OVERLAP);\n\t\tattr.setValue(\"1\");\n\t\trootElement.setAttributeNode(attr);\n\n\t\tattr = doc.createAttribute(Constants.Attr.FORMAT);\n\t\tattr.setValue(\"png\");\n\t\trootElement.setAttributeNode(attr);\n\t}\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/cutter/OnCompliteListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.cutter;\n\npublic interface OnCompliteListener\n{\n\tpublic void onComplite();\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/cutter/OnProgressUpdateListener.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.cutter;\n\n\npublic interface OnProgressUpdateListener\n{\t\n\tpublic void onProgressUpdate(int value);\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/utils/EclipseUtils.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.utils;\n\nimport java.io.File;\n\nimport org.eclipse.core.resources.IWorkspace;\nimport org.eclipse.core.resources.IWorkspaceRoot;\nimport org.eclipse.core.resources.ResourcesPlugin;\nimport org.eclipse.core.runtime.IPath;\n\npublic class EclipseUtils\n{\n\tprivate EclipseUtils()\n\t{\n\t}\n\n\tpublic static File getCurrentWorkspace()\n\t{\n\t\tIWorkspace workspace = ResourcesPlugin.getWorkspace();\n\t\tIWorkspaceRoot root = workspace.getRoot();\n\n\t\tIPath location = root.getLocation();\n\t\tlocation.toFile();\n\n\t\treturn location.toFile();\n\t}\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/utils/FileUtils.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.utils;\n\nimport java.io.File;\n\npublic class FileUtils\n{\n\tpublic static boolean deleteDir(File dir)\n\t{\n\t\tif (dir.isDirectory())\n\t\t{\n\t\t\tString[] children = dir.list();\n\t\t\tfor (int i = 0; i < children.length; i++)\n\t\t\t{\n\t\t\t\tboolean success = deleteDir(new File(dir, children[i]));\n\t\t\t\tif (!success)\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn dir.delete();\n\t}\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/utils/XMLUtils.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.utils;\n\nimport java.io.File;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.transform.Transformer;\nimport javax.xml.transform.TransformerException;\nimport javax.xml.transform.TransformerFactory;\nimport javax.xml.transform.dom.DOMSource;\nimport javax.xml.transform.stream.StreamResult;\n\nimport org.w3c.dom.Document;\n\npublic class XMLUtils\n{\n\tpublic static Document createDoc()\n\t{\n\t\tDocument document = null;\n\t\tDocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();\n\t\ttry\n\t\t{\n\t\t\tDocumentBuilder docBuilder = docFactory.newDocumentBuilder();\n\t\t\tdocument = docBuilder.newDocument();\n\t\t} catch (ParserConfigurationException e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn document;\n\t}\n\n\tpublic static void saveDoc(Document doc, String fileName)\n\t{\n\t\ttry\n\t\t{\n\t\t\tTransformerFactory transformerFactory = TransformerFactory.newInstance();\n\t\t\tTransformer transformer = transformerFactory.newTransformer();\n\t\t\tDOMSource source = new DOMSource(doc);\n\n\t\t\tStreamResult result = new StreamResult(new File(fileName));\n\t\t\ttransformer.transform(source, result);\n\t\t} catch (TransformerException e)\n\t\t{\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/views/DirectoryChooser.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.views;\n\nimport java.io.File;\n\nimport org.eclipse.swt.SWT;\nimport org.eclipse.swt.events.SelectionEvent;\nimport org.eclipse.swt.events.SelectionListener;\nimport org.eclipse.swt.layout.GridData;\nimport org.eclipse.swt.layout.GridLayout;\nimport org.eclipse.swt.widgets.Button;\nimport org.eclipse.swt.widgets.Composite;\nimport org.eclipse.swt.widgets.DirectoryDialog;\nimport org.eclipse.swt.widgets.Text;\n\npublic class DirectoryChooser extends Composite\n{\n\n\tpublic static final String DIR_PATH = \"directorychooser.file_path\";\n\n\tprivate static final String BTN_TXT = \"...\";\n\n\tprivate Text text;\n\n\tprivate Button button;\n\n\tprivate String title = null;\n\n\tpublic DirectoryChooser(Composite parent)\n\t{\n\t\tsuper(parent, SWT.NONE);\n\t\tcreateContent();\n\t}\n\n\tpublic void createContent()\n\t{\n\t\tGridLayout layout = new GridLayout(2, false);\n\t\tlayout.marginRight = 4;\n\t\tsetLayout(layout);\n\n\t\ttext = new Text(this, SWT.SINGLE | SWT.BORDER);\n\t\tGridData gd = new GridData(GridData.FILL_BOTH);\n\t\tgd.grabExcessHorizontalSpace = true;\n\t\tgd.horizontalAlignment = GridData.FILL;\n\t\ttext.setLayoutData(gd);\n\n\t\tbutton = new Button(this, SWT.NONE);\n\t\tbutton.setText(BTN_TXT);\n\t\tbutton.addSelectionListener(new SelectionListener()\n\t\t{\n\n\t\t\tpublic void widgetDefaultSelected(SelectionEvent e)\n\t\t\t{\n\t\t\t}\n\n\t\t\tpublic void widgetSelected(SelectionEvent e)\n\t\t\t{\n\t\t\t\tDirectoryDialog dirDialog = new DirectoryDialog(button.getShell());\n\t\t\t\tdirDialog.setFilterPath(text.getText());\n\t\t\t\tdirDialog.setText(\"Select your home directory\");\n\t\t\t\tString selectedDir = dirDialog.open();\n\n\t\t\t\tif (selectedDir == null)\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttext.setText(selectedDir);\n\t\t\t\tFileChooser.savePath(DirectoryChooser.this, DIR_PATH, selectedDir);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic void setText(String text)\n\t{\n\t\tthis.text.setText(text);\n\t}\n\n\tpublic String getText()\n\t{\n\t\treturn text.getText();\n\n\t}\n\n\tpublic Text getTextControl()\n\t{\n\t\treturn text;\n\t}\n\n\tpublic File getFile()\n\t{\n\t\tString text = this.text.getText();\n\n\t\tif (text.length() == 0)\n\t\t{\n\t\t\treturn null;\n\t\t}\n\n\t\treturn new File(text);\n\t}\n\n\tpublic String getTitle()\n\t{\n\t\treturn title;\n\t}\n\n\tpublic void setTitle(String title)\n\t{\n\t\tthis.title = title;\n\t}\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/views/FileChooser.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.views;\n\nimport java.io.File;\nimport java.util.prefs.Preferences;\n\nimport org.eclipse.swt.SWT;\nimport org.eclipse.swt.events.SelectionEvent;\nimport org.eclipse.swt.events.SelectionListener;\nimport org.eclipse.swt.layout.GridData;\nimport org.eclipse.swt.layout.GridLayout;\nimport org.eclipse.swt.widgets.Button;\nimport org.eclipse.swt.widgets.Composite;\nimport org.eclipse.swt.widgets.FileDialog;\nimport org.eclipse.swt.widgets.Text;\n\npublic class FileChooser extends Composite\n{\n\tpublic static final String FILE_PATH = \"filechooser.file.path\";\n\n\tprivate static final String OPEN = \"Open\";\n\n\tprivate static final String OK = \"Ok\";\n\n\tprivate static final String BTN_TXT = \"...\";\n\n\tprivate Text text;\n\n\tprivate Button button;\n\n\tprivate String title = null;\n\n\tprivate int mode;\n\n\tpublic FileChooser(Composite parent, int mode)\n\t{\n\t\tsuper(parent, SWT.NONE);\n\t\tthis.mode = mode;\n\n\t\tcreateContent();\n\t}\n\n\tpublic void createContent()\n\t{\n\t\tGridLayout layout = new GridLayout();\n\t\tlayout.numColumns = 2;\n\t\tlayout.marginHeight = 0;\n\t\tlayout.marginWidth = 0;\n\t\tsetLayout(layout);\n\n\t\ttext = new Text(this, SWT.SINGLE | SWT.BORDER);\n\t\tGridData gd = new GridData();\n\t\tgd.grabExcessHorizontalSpace = true;\n\t\tgd.horizontalAlignment = GridData.FILL;\n\t\ttext.setLayoutData(gd);\n\n\t\tbutton = new Button(this, SWT.NONE);\n\t\tbutton.setText(BTN_TXT);\n\t\tbutton.addSelectionListener(new SelectionListener()\n\t\t{\n\n\t\t\tpublic void widgetDefaultSelected(SelectionEvent e)\n\t\t\t{\n\t\t\t}\n\n\t\t\tpublic void widgetSelected(SelectionEvent e)\n\t\t\t{\n\t\t\t\tString path = null;\n\n\t\t\t\tswitch (mode)\n\t\t\t\t{\n\t\t\t\tcase Mode.OPEN:\n\t\t\t\t\tpath = openFile();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Mode.SAVE:\n\t\t\t\t\tpath = saveFile();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (path == null)\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttext.setText(path);\n\t\t\t\tsavePath(FileChooser.this, FILE_PATH, path);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic static void savePath(Composite composite, String key, String value)\n\t{\n\t\tPreferences prefs = Preferences.userNodeForPackage(composite.getClass());\n\t\tprefs.put(key, value);\n\t}\n\n\tpublic String openFile()\n\t{\n\t\tFileDialog dlg = new FileDialog(button.getShell(), SWT.OPEN);\n\t\tdlg.setFileName(text.getText());\n\t\tdlg.setFilterExtensions(new String[] { \"*.gif; *.jpg; *.png; *.ico; *.bmp\" });\n\n\t\tdlg.setText(OPEN);\n\t\tString path = dlg.open();\n\n\t\treturn path;\n\t}\n\n\tpublic String saveFile()\n\t{\n\t\tFileDialog dlg = new FileDialog(button.getShell(), SWT.SAVE);\n\t\tdlg.setFileName(text.getText());\n\n\t\tdlg.setText(OK);\n\t\tString path = dlg.open();\n\n\t\treturn path;\n\t}\n\n\tpublic void setText(String text)\n\t{\n\t\tthis.text.setText(text);\n\t}\n\n\tpublic String getText()\n\t{\n\t\treturn text.getText();\n\n\t}\n\n\tpublic Text getTextControl()\n\t{\n\t\treturn text;\n\t}\n\n\tpublic File getFile()\n\t{\n\t\tString text = this.text.getText();\n\n\t\tif (text.length() == 0)\n\t\t{\n\t\t\treturn null;\n\t\t}\n\n\t\treturn new File(text);\n\t}\n\n\tpublic String getTitle()\n\t{\n\t\treturn title;\n\t}\n\n\tpublic void setTitle(String title)\n\t{\n\t\tthis.title = title;\n\t}\n\n\tpublic static class Mode\n\t{\n\t\tpublic static final int OPEN = 1;\n\n\t\tpublic static final int SAVE = 2;\n\t}\n}"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/views/GPSChooser.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.views;\n\nimport org.eclipse.swt.SWT;\nimport org.eclipse.swt.layout.GridData;\nimport org.eclipse.swt.layout.GridLayout;\nimport org.eclipse.swt.widgets.Composite;\nimport org.eclipse.swt.widgets.Group;\nimport org.eclipse.swt.widgets.Label;\nimport org.eclipse.swt.widgets.Text;\n\nimport com.ls.mappwidget.slicingtool.vo.PointVO;\n\npublic class GPSChooser extends Composite\n{\n\tprivate String title;\n\n\tprivate Text x;\n\n\tprivate Text y;\n\n\tprivate Text longitude;\n\n\tprivate Text latitude;\n\n\tpublic GPSChooser(Composite parent, String title)\n\t{\n\t\tsuper(parent, SWT.NONE);\n\t\tthis.title = title;\n\t\tcreateContent();\n\t}\n\n\tpublic void createContent()\n\t{\n\t\tGridData gd = new GridData();\n\t\tgd.grabExcessHorizontalSpace = true;\n\t\tgd.horizontalAlignment = GridData.FILL;\n\n\t\tGridLayout contentLayout = new GridLayout();\n\t\tcontentLayout.numColumns = 1;\n\t\tcontentLayout.marginHeight = 0;\n\t\tcontentLayout.marginWidth = 0;\n\t\tsetLayout(contentLayout);\n\t\tsetLayoutData(gd);\n\n\t\tGroup group = new Group(this, SWT.NONE);\n\n\t\tGridLayout layout = new GridLayout();\n\t\tlayout.marginWidth = 15;\n\t\tlayout.numColumns = 4;\n\n\t\tgroup.setLayoutData(gd);\n\t\tgroup.setLayout(layout);\n\t\tgroup.setText(title);\n\n\t\tGridData textData = new GridData();\n\t\ttextData.grabExcessHorizontalSpace = true;\n\t\ttextData.horizontalAlignment = GridData.FILL;\n\n\t\tLabel label = new Label(group, SWT.WRAP);\n\t\tlabel.setText(\"X\");\n\n\t\tx = new Text(group, SWT.SINGLE | SWT.BORDER);\n\t\tx.setLayoutData(textData);\n\n\t\tlabel = new Label(group, SWT.WRAP);\n\t\tlabel.setText(\"Longitude\");\n\n\t\tlongitude = new Text(group, SWT.SINGLE | SWT.BORDER);\n\t\tlongitude.setLayoutData(textData);\n\n\t\tlabel = new Label(group, SWT.WRAP);\n\t\tlabel.setText(\"Y\");\n\n\t\ty = new Text(group, SWT.SINGLE | SWT.BORDER);\n\t\ty.setLayoutData(textData);\n\n\t\tlabel = new Label(group, SWT.WRAP);\n\t\tlabel.setText(\"Latitude\");\n\n\t\tlatitude = new Text(group, SWT.SINGLE | SWT.BORDER);\n\t\tlatitude.setLayoutData(textData);\n\t}\n\n\tpublic void setActive(boolean enabled)\n\t{\n\t\tx.setEnabled(enabled);\n\t\ty.setEnabled(enabled);\n\t\tlatitude.setEnabled(enabled);\n\t\tlongitude.setEnabled(enabled);\n\t}\n\n\tpublic PointVO getPoint()\n\t{\n\t\tPointVO result = new PointVO();\n\n\t\ttry\n\t\t{\n\t\t\tresult.setX(Double.valueOf(x.getText()));\n\t\t\tresult.setY(Double.valueOf(y.getText()));\n\t\t\tresult.setLat(Double.valueOf(latitude.getText()));\n\t\t\tresult.setLon(Double.valueOf(longitude.getText()));\n\n\t\t} catch (NumberFormatException e)\n\t\t{\n\t\t\treturn null;\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/views/MainView.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.views;\n\nimport java.io.File;\nimport java.util.prefs.Preferences;\n\nimport org.eclipse.jface.dialogs.MessageDialog;\nimport org.eclipse.swt.SWT;\nimport org.eclipse.swt.custom.ScrolledComposite;\nimport org.eclipse.swt.graphics.Image;\nimport org.eclipse.swt.layout.GridData;\nimport org.eclipse.swt.layout.GridLayout;\nimport org.eclipse.swt.widgets.Button;\nimport org.eclipse.swt.widgets.Combo;\nimport org.eclipse.swt.widgets.Composite;\nimport org.eclipse.swt.widgets.Event;\nimport org.eclipse.swt.widgets.Group;\nimport org.eclipse.swt.widgets.Label;\nimport org.eclipse.swt.widgets.Listener;\nimport org.eclipse.swt.widgets.MessageBox;\nimport org.eclipse.swt.widgets.ProgressBar;\nimport org.eclipse.swt.widgets.Text;\nimport org.eclipse.ui.part.ViewPart;\n\nimport com.ls.mappwidget.slicingtool.cutter.Cutter;\nimport com.ls.mappwidget.slicingtool.cutter.OnCompliteListener;\nimport com.ls.mappwidget.slicingtool.cutter.OnProgressUpdateListener;\nimport com.ls.mappwidget.slicingtool.utils.FileUtils;\nimport com.ls.mappwidget.slicingtool.views.FileChooser.Mode;\nimport com.ls.mappwidget.slicingtool.vo.PointVO;\n\npublic class MainView extends ViewPart\n{\n\tprivate static final String GPS_POSITIONING = \"GPS Positioning\";\n\n\tprivate static final String BOTTOM_RIGHT_POINT = \"Bottom right point\";\n\n\tprivate static final String TOP_LEFT_POINT = \"Top left point\";\n\n\tprivate static final String ATTENTION = \"Attention :\";\n\n\tprivate static final String EXPORT_OPTIONS = \"Export Options\";\n\n\tprivate static final String MAP_SOURCE = \"Map Source\";\n\n\tprivate static final String DEFAULT_NAME = \"map\";\n\n\tprivate static final String INCORECT_FILE_NAME = \"Incorect file name!\";\n\n\tprivate static final String CHOOSE_SAVE_DIR_FIRST = \"Choose save dir first!\";\n\n\tprivate static final String ENTER_NAME_FIRST = \"Enter name first!\";\n\n\tprivate static final String CHOOSE_IMAGE_FIRST = \"Choose image first!\";\n\n\tprivate static final String NAME = \"Name\";\n\n\tprivate static final String TILE_SIZE = \"Tile Size\";\n\n\tprivate static final String CUT = \"Export\";\n\n\tpublic static final String ID = \"com.ls.map.image.views.SampleView\";\n\n\tpublic static int PROGRESS_MAX = 10;\n\n\tpublic MainView()\n\t{\n\t}\n\n\t@Override\n\tpublic void createPartControl(Composite parent)\n\t{\n\t\tinitWidgets(parent);\n\t}\n\n\t@Override\n\tpublic void setFocus()\n\t{\n\t}\n\n\tprivate void initWidgets(final Composite parent)\n\t{\n\t\tScrolledComposite scrolledComposite = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);\n\t\tfinal Composite top = new Composite(scrolledComposite, SWT.NONE);\n\t\tfillTop(top, scrolledComposite);\n\n\t\tPreferences prefs = Preferences.userNodeForPackage(this.getClass());\n\n\t\tComposite mapSource = new Composite(top, SWT.NONE);\n\t\tfinal FileChooser fileChooser = fillMapSource(mapSource, prefs);\n\n\t\tfinal Group group = new Group(top, SWT.NONE);\n\t\tfillGroup(group);\n\n\t\tGridLayout layout = new GridLayout();\n\t\tlayout.numColumns = 2;\n\n\t\tGridData fileDir = new GridData();\n\t\tfileDir.grabExcessHorizontalSpace = true;\n\t\tfileDir.horizontalAlignment = GridData.FILL;\n\n\t\tComposite composite = new Composite(group, SWT.NONE);\n\t\tcomposite.setLayoutData(fileDir);\n\t\tcomposite.setLayout(layout);\n\n\t\tLabel label = new Label(composite, SWT.WRAP);\n\t\tlabel.setText(NAME);\n\n\t\tfinal Text text = fillName(composite);\n\n\t\tfinal RadioGroup radioGroup = new RadioGroup(group);\n\t\tradioGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));\n\t\tradioGroup.setDirText(prefs.get(RadioGroup.DIR_PATH, \"\"));\n\n\t\tlayout = new GridLayout();\n\t\tlayout.numColumns = 2;\n\n\t\tcomposite = new Composite(group, SWT.NONE);\n\t\tcomposite.setLayoutData(fileDir);\n\t\tcomposite.setLayout(layout);\n\n\t\tGridData dataCombo = new GridData();\n\t\tdataCombo.widthHint = 50;\n\n\t\tlabel = new Label(composite, SWT.WRAP);\n\t\tlabel.setText(TILE_SIZE);\n\n\t\tfinal Combo comboTile = new Combo(composite, SWT.DROP_DOWN | SWT.READ_ONLY);\n\t\tcomboTile.setItems(new String[] { \"128\", \"256\" });\n\t\tcomboTile.select(1);\n\t\tcomboTile.setLayoutData(dataCombo);\n\n\t\tcomposite = new Composite(group, SWT.NONE);\n\t\tcomposite.setLayoutData(fileDir);\n\t\tcomposite.setLayout(layout);\n\n\t\tlabel = new Label(composite, SWT.WRAP);\n\t\tlabel.setText(GPS_POSITIONING);\n\n\t\tfinal Button gps = new Button(composite, SWT.CHECK);\n\n\t\tfileDir = new GridData();\n\t\tfileDir.grabExcessHorizontalSpace = true;\n\t\tfileDir.horizontalAlignment = GridData.FILL;\n\n\t\tlayout = new GridLayout();\n\t\tlayout.numColumns = 2;\n\n\t\tcomposite = new Composite(group, SWT.NONE);\n\t\tcomposite.setLayoutData(fileDir);\n\t\tcomposite.setLayout(layout);\n\n\t\tfinal GPSChooser gpsChooserTopLeft = new GPSChooser(composite, TOP_LEFT_POINT);\n\t\tgpsChooserTopLeft.setActive(false);\n\n\t\tfinal GPSChooser gpsChooserBottomRight = new GPSChooser(composite, BOTTOM_RIGHT_POINT);\n\t\tgpsChooserBottomRight.setActive(false);\n\n\t\tfinal Button runButton = new Button(top, SWT.NONE);\n\t\trunButton.setText(CUT);\n\n\t\tfinal ProgressBar progressBar = new ProgressBar(top, SWT.SMOOTH);\n\n\t\tprogressBar.setMinimum(0);\n\t\tprogressBar.setVisible(false);\n\n\t\tprogressBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));\n\n\t\tfinal Cutter cutter = new Cutter(new OnProgressUpdateListener()\n\t\t{\n\t\t\t@Override\n\t\t\tpublic void onProgressUpdate(int value)\n\t\t\t{\n\t\t\t\tsetValue(top, progressBar, value);\n\t\t\t}\n\t\t}, new OnCompliteListener()\n\t\t{\n\n\t\t\t@Override\n\t\t\tpublic void onComplite()\n\t\t\t{\n\t\t\t\tsetCompliete(top, runButton, progressBar);\n\t\t\t}\n\t\t});\n\n\t\trunButton.addListener(SWT.Selection, new Listener()\n\t\t{\n\n\t\t\tpublic void handleEvent(Event event)\n\t\t\t{\n\t\t\t\tPointVO pointTopLeft = gpsChooserTopLeft.getPoint();\n\t\t\t\tPointVO pointBottomRight = gpsChooserBottomRight.getPoint();\n\n\t\t\t\tif (gps.getSelection() && (pointTopLeft == null || pointBottomRight == null))\n\t\t\t\t{\n\t\t\t\t\tMessageBox dialog = new MessageBox(parent.getShell());\n\t\t\t\t\tdialog.setMessage(\"Please enter a valid values for points!.\");\n\t\t\t\t\tdialog.open();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tString dir = getDir(radioGroup);\n\n\t\t\t\tif (dir == null)\n\t\t\t\t{\n\t\t\t\t\tMessageBox dialog = new MessageBox(parent.getShell());\n\t\t\t\t\tdialog.setMessage(\"Incorect location path!\");\n\t\t\t\t\tdialog.open();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!checkDir(parent, dir, text.getText()))\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprogressBar.setSelection(0);\n\t\t\t\trunButton.setEnabled(false);\n\n\t\t\t\tprogressBar.setMaximum(PROGRESS_MAX);\n\t\t\t\tprogressBar.setVisible(true);\n\t\t\t\ttop.update();\n\n\t\t\t\tgetTiles(parent, group, fileChooser.getText(), dir, text.getText(), comboTile, cutter, pointTopLeft, pointBottomRight);\n\t\t\t}\n\n\t\t});\n\n\t\tgps.addListener(SWT.Selection, new Listener()\n\t\t{\n\t\t\tpublic void handleEvent(Event event)\n\t\t\t{\n\t\t\t\tboolean selection = gps.getSelection();\n\n\t\t\t\tgpsChooserTopLeft.setActive(selection);\n\t\t\t\tgpsChooserBottomRight.setActive(selection);\n\t\t\t}\n\n\t\t});\n\n\t}\n\n\tprivate String getDir(RadioGroup radioGroup)\n\t{\n\t\tswitch (radioGroup.getSelected())\n\t\t{\n\t\tcase RadioGroup.LOCATION:\n\n\t\t\treturn radioGroup.getDirText();\n\t\tcase RadioGroup.PROJECT:\n\n\t\t\treturn radioGroup.getSelectedPath();\n\n\t\t}\n\t\treturn null;\n\t}\n\n\tprotected boolean checkDir(Composite parent, String dir, String name)\n\t{\n\t\tString sign = \"\";\n\n\t\tif (!dir.endsWith(\"\\\\\"))\n\t\t{\n\t\t\tsign = \"\\\\\";\n\t\t}\n\n\t\tString fileName = dir + sign + name;\n\t\tFile file = new File(fileName);\n\n\t\tif (file.exists())\n\t\t{\n\t\t\tboolean answer = MessageDialog.openQuestion(parent.getShell(), ATTENTION, \"Directory \\\"\" + fileName + \"\\\"\"\n\t\t\t\t\t+ \" already exist. Do you want to continue(its will remove old files!)?\");\n\n\t\t\tif (answer)\n\t\t\t{\n\t\t\t\tFileUtils.deleteDir(file);\n\t\t\t}\n\n\t\t\treturn answer;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate void setValue(Composite top, final ProgressBar progressBar, final int value)\n\t{\n\t\ttop.getDisplay().asyncExec(new Runnable()\n\t\t{\n\t\t\t@Override\n\t\t\tpublic void run()\n\t\t\t{\n\t\t\t\tprogressBar.setSelection(value);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void setCompliete(Composite top, final Button runButton, final ProgressBar progressBar)\n\t{\n\t\ttop.getDisplay().asyncExec(new Runnable()\n\t\t{\n\t\t\t@Override\n\t\t\tpublic void run()\n\t\t\t{\n\t\t\t\trunButton.setEnabled(true);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate FileChooser fillMapSource(Composite mapSource, Preferences prefs)\n\t{\n\t\tGridLayout layout = new GridLayout();\n\t\tlayout.numColumns = 2;\n\n\t\tGridData fileDir = new GridData();\n\t\tfileDir.grabExcessHorizontalSpace = true;\n\t\tfileDir.horizontalAlignment = GridData.FILL;\n\n\t\tmapSource.setLayoutData(fileDir);\n\t\tmapSource.setLayout(layout);\n\n\t\tLabel label = new Label(mapSource, SWT.WRAP);\n\t\tlabel.setText(MAP_SOURCE);\n\n\t\tfinal FileChooser fileChooser = new FileChooser(mapSource, Mode.OPEN);\n\t\tfileChooser.setLayoutData(fileDir);\n\t\tfileChooser.setText(prefs.get(FileChooser.FILE_PATH, \"\"));\n\n\t\treturn fileChooser;\n\t}\n\n\tprivate Text fillName(Composite parent)\n\t{\n\t\tText text = new Text(parent, SWT.SINGLE | SWT.BORDER);\n\n\t\tGridData gd = new GridData();\n\t\tgd.grabExcessHorizontalSpace = true;\n\t\tgd.horizontalAlignment = GridData.FILL;\n\t\ttext.setLayoutData(gd);\n\t\ttext.setText(DEFAULT_NAME);\n\n\t\treturn text;\n\t}\n\n\tprivate void fillGroup(Group group)\n\t{\n\t\tGridLayout layout = new GridLayout();\n\t\tlayout.marginWidth = 15;\n\t\tlayout.numColumns = 1;\n\n\t\tGridData gd = new GridData();\n\t\tgd.grabExcessHorizontalSpace = true;\n\t\tgd.horizontalAlignment = GridData.FILL;\n\n\t\tgroup.setLayoutData(gd);\n\t\tgroup.setLayout(layout);\n\t\tgroup.setText(EXPORT_OPTIONS);\n\t}\n\n\tprivate void fillTop(Composite top, ScrolledComposite scrolledComposite)\n\t{\n\t\tGridLayout layout = new GridLayout();\n\t\tlayout.numColumns = 1;\n\n\t\tGridData data = new GridData();\n\t\tdata.grabExcessHorizontalSpace = true;\n\t\tdata.horizontalAlignment = GridData.FILL;\n\n\t\ttop.setLayoutData(data);\n\t\ttop.setLayout(layout);\n\n\t\tscrolledComposite.setMinSize(500, 250);\n\t\tscrolledComposite.setExpandHorizontal(true);\n\t\tscrolledComposite.setExpandVertical(true);\n\t\tscrolledComposite.setContent(top);\n\t}\n\n\tprotected void getTiles(final Composite parent, final Composite banner, final String imgPath, final String saveDirPath, final String name, final Combo combo,\n\t\t\tfinal Cutter cutter, final PointVO pointTopLeft, final PointVO pointBottomRight)\n\t{\n\t\tMessageBox dialog = new MessageBox(parent.getShell());\n\n\t\tif (name == null || name.contentEquals(\"\"))\n\t\t{\n\t\t\tdialog.setMessage(ENTER_NAME_FIRST);\n\t\t\tdialog.open();\n\t\t\treturn;\n\t\t}\n\n\t\telse if (imgPath == null || imgPath.contentEquals(\"\"))\n\t\t{\n\t\t\tdialog.setMessage(CHOOSE_IMAGE_FIRST);\n\t\t\tdialog.open();\n\t\t\treturn;\n\t\t}\n\n\t\telse if (saveDirPath == null || saveDirPath.contentEquals(\"\"))\n\t\t{\n\t\t\tdialog.setMessage(CHOOSE_SAVE_DIR_FIRST);\n\t\t\tdialog.open();\n\t\t\treturn;\n\t\t}\n\n\t\tFile f = new File(imgPath);\n\n\t\tif (f.exists())\n\t\t{\n\t\t\tcutter.startCuttingAndroid(imgPath, saveDirPath, name, Integer.parseInt(combo.getItem(combo.getSelectionIndex())), pointTopLeft, pointBottomRight);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdialog.setMessage(INCORECT_FILE_NAME);\n\t\t\tdialog.open();\n\t\t\treturn;\n\t\t}\n\n\t}\n\n\tpublic Image loadImage(Composite composite, String filename)\n\t{\n\t\tFile f = new File(filename);\n\t\tImage sourceImage = null;\n\n\t\tif (f.exists())\n\t\t{\n\t\t\tsourceImage = new Image(composite.getDisplay(), filename);\n\t\t}\n\n\t\treturn sourceImage;\n\t}\n}"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/views/RadioGroup.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.views;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.eclipse.swt.SWT;\nimport org.eclipse.swt.events.SelectionAdapter;\nimport org.eclipse.swt.events.SelectionEvent;\nimport org.eclipse.swt.events.SelectionListener;\nimport org.eclipse.swt.layout.GridData;\nimport org.eclipse.swt.layout.GridLayout;\nimport org.eclipse.swt.widgets.Button;\nimport org.eclipse.swt.widgets.Combo;\nimport org.eclipse.swt.widgets.Composite;\nimport org.eclipse.swt.widgets.DirectoryDialog;\nimport org.eclipse.swt.widgets.Label;\nimport org.eclipse.swt.widgets.Text;\n\nimport com.ls.mappwidget.slicingtool.utils.EclipseUtils;\n\npublic class RadioGroup extends Composite\n{\n\tpublic static final int LOCATION = 1;\n\n\tpublic static final int PROJECT = 2;\n\n\tprivate static final String BTN_LOCATION_TXT = \"Export to location\";\n\n\tprivate static final String BTN_PROJECT_TXT = \"Export to Project\";\n\n\tprivate Button btnLocation;\n\n\tprivate Button btnProject;\n\n\tpublic static final String DIR_PATH = \"directorychooser.file_path\";\n\n\tprivate static final String BTN_TXT = \"...\";\n\n\tprivate Text text;\n\n\tprivate Button button;\n\n\tprivate List<String> result;\n\n\tprivate File workspace;\n\n\tprivate Combo comboPath;\n\n\tpublic RadioGroup(Composite parent)\n\t{\n\t\tsuper(parent, SWT.NULL);\n\t\tcreateContent();\n\t}\n\n\tpublic void createContent()\n\t{\n\t\tGridLayout layout = new GridLayout(3, false);\n\t\tsetLayout(layout);\n\n\t\tGridData gd = new GridData(GridData.FILL_BOTH);\n\t\tgd.horizontalAlignment = SWT.FILL;\n\t\tgd.minimumWidth = 400;\n\t\tgd.minimumHeight = 50;\n\n\t\tbtnLocation = new Button(this, SWT.RADIO);\n\t\tbtnLocation.setText(BTN_LOCATION_TXT);\n\n\t\ttext = new Text(this, SWT.SINGLE | SWT.BORDER);\n\t\tGridData gd2 = new GridData(GridData.FILL_BOTH);\n\t\tgd.grabExcessHorizontalSpace = true;\n\t\tgd.horizontalAlignment = GridData.FILL;\n\t\ttext.setLayoutData(gd2);\n\n\t\tbutton = new Button(this, SWT.NONE);\n\t\tbutton.setText(BTN_TXT);\n\t\tbutton.addSelectionListener(new SelectionListener()\n\t\t{\n\t\t\tpublic void widgetDefaultSelected(SelectionEvent e)\n\t\t\t{\n\t\t\t}\n\n\t\t\tpublic void widgetSelected(SelectionEvent e)\n\t\t\t{\n\t\t\t\tDirectoryDialog dirDialog = new DirectoryDialog(button.getShell());\n\t\t\t\tdirDialog.setFilterPath(text.getText());\n\t\t\t\tdirDialog.setText(\"Select your home directory\");\n\t\t\t\tString selectedDir = dirDialog.open();\n\n\t\t\t\tif (selectedDir == null)\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttext.setText(selectedDir);\n\t\t\t\tFileChooser.savePath(RadioGroup.this, DIR_PATH, selectedDir);\n\t\t\t}\n\t\t});\n\n\t\tbtnProject = new Button(this, SWT.RADIO);\n\t\tbtnProject.setText(BTN_PROJECT_TXT);\n\t\tbtnProject.setSelection(true);\n\t\ttext.setEnabled(false);\n\t\tbutton.setEnabled(false);\n\n\t\tGridData dataCombo = new GridData();\n\t\tdataCombo.grabExcessHorizontalSpace = true;\n\t\tdataCombo.horizontalAlignment = GridData.FILL;\n\n\t\tworkspace = EclipseUtils.getCurrentWorkspace();\n\t\tString[] list = workspace.list();\n\t\tresult = new ArrayList<String>();\n\n\t\tfor (int i = 0; i < list.length; i++)\n\t\t{\n\t\t\tFile f = new File(workspace, list[i] + \"\\\\\" + \"AndroidManifest.xml\");\n\t\t\tif (f.exists())\n\t\t\t{\n\t\t\t\tresult.add(list[i]);\n\t\t\t}\n\t\t}\n\n\t\tcomboPath = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);\n\t\tcomboPath.setItems(result.toArray(new String[result.size()]));\n\t\tcomboPath.select(0);\n\t\tcomboPath.setLayoutData(dataCombo);\n\n\t\tLabel label = new Label(this, SWT.WRAP);\n\t\tlabel.setText(\"\");\n\n\t\tbtnProject.addSelectionListener(new SelectionAdapter()\n\t\t{\n\t\t\tpublic void widgetSelected(SelectionEvent e)\n\t\t\t{\n\t\t\t\tcomboPath.setEnabled(true);\n\t\t\t\ttext.setEnabled(false);\n\t\t\t\tbutton.setEnabled(false);\n\t\t\t}\n\t\t});\n\n\t\tbtnLocation.addSelectionListener(new SelectionAdapter()\n\t\t{\n\t\t\tpublic void widgetSelected(SelectionEvent e)\n\t\t\t{\n\t\t\t\tcomboPath.setEnabled(false);\n\t\t\t\ttext.setEnabled(true);\n\t\t\t\tbutton.setEnabled(true);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic void setDirText(String text)\n\t{\n\t\tthis.text.setText(text);\n\t}\n\n\tpublic String getDirText()\n\t{\n\t\treturn text.getText();\n\t}\n\n\tpublic String getSelectedPath()\n\t{\n\t\tint pos = comboPath.getSelectionIndex();\n\n\t\tif (pos == -1)\n\t\t{\n\t\t\treturn null;\n\t\t}\n\n\t\treturn workspace.getAbsolutePath() + \"\\\\\" + result.get(pos) + \"\\\\assets\";\n\t}\n\n\tpublic int getSelected()\n\t{\n\t\tif (btnLocation.getSelection())\n\t\t{\n\t\t\treturn LOCATION;\n\t\t}\n\n\t\treturn PROJECT;\n\t}\n\n}"
  },
  {
    "path": "slicingtool/src/com/ls/mappwidget/slicingtool/vo/PointVO.java",
    "content": "/*************************************************************************\n* Copyright (c) 2015 Lemberg Solutions\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*    http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n**************************************************************************/\n\npackage com.ls.mappwidget.slicingtool.vo;\n\npublic class PointVO\n{\n\tprivate double x;\n\tprivate double y;\n\tprivate double lat;\n\tprivate double lon;\n\n\tprivate int topLeft;\n\n\tpublic double getX()\n\t{\n\t\treturn x;\n\t}\n\n\tpublic void setX(double x)\n\t{\n\t\tthis.x = x;\n\t}\n\n\tpublic double getY()\n\t{\n\t\treturn y;\n\t}\n\n\tpublic void setY(double y)\n\t{\n\t\tthis.y = y;\n\t}\n\n\tpublic double getLat()\n\t{\n\t\treturn lat;\n\t}\n\n\tpublic void setLat(double lat)\n\t{\n\t\tthis.lat = lat;\n\t}\n\n\tpublic double getLon()\n\t{\n\t\treturn lon;\n\t}\n\n\tpublic void setLon(double lon)\n\t{\n\t\tthis.lon = lon;\n\t}\n\n\tpublic int getTopLeft()\n\t{\n\t\treturn topLeft;\n\t}\n\n\tpublic void setTopLeft(int topLeft)\n\t{\n\t\tthis.topLeft = topLeft;\n\t}\n\n}\n"
  }
]