diff --git a/AndroidWearMap/README.md b/AndroidWearMap/README.md index 15a7f502..f07223ec 100644 --- a/AndroidWearMap/README.md +++ b/AndroidWearMap/README.md @@ -16,8 +16,21 @@ Pre-requisites Getting Started --------------- -This sample uses the Gradle build system. To build this project, use the -"gradlew build" command or use "Import Project" in Android Studio. + +This sample use the Gradle build system. + +First download the samples by cloning this repository or downloading an archived +snapshot. (See the options on the right hand side.) + +In Android Studio, use the "Import non-Android Studio project" or +"Import Project" option. Next select the ApiDemos/ directory that you downloaded +from this repository. +If prompted for a gradle configuration accept the default settings. + +Alternatively use the "gradlew build" command to build the project directly. + +Don't forget to add your API key to the AndroidManifest.xml. +(See [https://developers.google.com/maps/documentation/android/start](https://developers.google.com/maps/documentation/android/start#get_an_android_certificate_and_the_google_maps_api_key)) Support ------- @@ -33,6 +46,8 @@ https://github.com/googlemaps/android-samples/issues Patches are encouraged, and may be submitted according to the instructions in CONTRIBUTING.md. +![Analytics](https://ga-beacon.appspot.com/UA-12846745-20/android-samples-wearmap/readme?pixel) + License ------- diff --git a/ApiDemos/.gitignore b/ApiDemos/.gitignore new file mode 100644 index 00000000..afbdab33 --- /dev/null +++ b/ApiDemos/.gitignore @@ -0,0 +1,6 @@ +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build diff --git a/ApiDemos/LICENSE b/ApiDemos/LICENSE new file mode 100644 index 00000000..1af981f5 --- /dev/null +++ b/ApiDemos/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ApiDemos/README.md b/ApiDemos/README.md new file mode 100644 index 00000000..04f3abda --- /dev/null +++ b/ApiDemos/README.md @@ -0,0 +1,70 @@ +Google Maps Android API Demos +=================================== + +These are demos for the [Google Maps Android API v2](https://developers.google.com/maps/documentation/android-api/). +They demonstrate most of the features available in the API. + +This app was written for a minSdk of 9 and the v4 support library, but it can be easily adapted to +use native functionality instead. +(For example replacing ``SupportMapFragment`` with ``MapFragment``.) + +Pre-requisites +-------------- + +- Android SDK v23 +- Latest Android Build Tools +- Android Support Repository + +Getting Started +--------------- + +This sample use the Gradle build system. + +First download the samples by cloning this repository or downloading an archived +snapshot. (See the options on the right hand side.) + +In Android Studio, use the "Import non-Android Studio project" or +"Import Project" option. Next select the ApiDemos/ directory that you downloaded +from this repository. +If prompted for a gradle configuration accept the default settings. + +Alternatively use the "gradlew build" command to build the project directly. + +Don't forget to add your API key to the AndroidManifest.xml. +(See [https://developers.google.com/maps/documentation/android/start](https://developers.google.com/maps/documentation/android/start#get_an_android_certificate_and_the_google_maps_api_key)) + +Support +------- + +- Stack Overflow: https://stackoverflow.com/questions/tagged/android+google-maps + +If you have discovered an issue with the Google Maps Android API v2, please see +the resources here: https://developers.google.com/maps/documentation/android-api/support + +If you've found an error in these samples, please file an issue: +https://github.com/googlemaps/android-samples/issues + +Patches are encouraged, and may be submitted according to the instructions in +CONTRIBUTING.md. + +![Analytics](https://ga-beacon.appspot.com/UA-12846745-20/android-samples-apidemos/readme?pixel) + +License +------- + +Copyright 2015 The Android Open Source Project + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy of +the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations under +the License. diff --git a/ApiDemos/app/.gitignore b/ApiDemos/app/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/ApiDemos/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/ApiDemos/app/build.gradle b/ApiDemos/app/build.gradle new file mode 100644 index 00000000..eb4b4e7e --- /dev/null +++ b/ApiDemos/app/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.1" + + defaultConfig { + applicationId "com.example.mapdemo" + minSdkVersion 9 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:23.0.1' + compile 'com.google.android.gms:play-services:8.1.0' +} diff --git a/ApiDemos/app/proguard-rules.pro b/ApiDemos/app/proguard-rules.pro new file mode 100644 index 00000000..94d0d928 --- /dev/null +++ b/ApiDemos/app/proguard-rules.pro @@ -0,0 +1,33 @@ +# +# Proguard config for the demo project. +# + +# This file only contains the proguard options required by the Google Maps +# Android API v2. It should be used in addition to the one provided by the +# Android SDK (/tools/proguard/proguard-android-optimize.txt). +# +# For more details on the use of proguard in Android, please read: +# http://proguard.sourceforge.net/manual/examples.html#androidapplication + +-optimizations !code/simplification/variable + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Fragment +-keep public class * extends android.support.v4.app.Fragment + +# The Maps API uses custom Parcelables. +# Use this rule (which is slightly broader than the standard recommended one) +# to avoid obfuscating them. +-keepclassmembers class * implements android.os.Parcelable { + static *** CREATOR; +} + +# The Maps API uses serialization. +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + static final java.io.ObjectStreamField[] serialPersistentFields; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} diff --git a/ApiDemos/app/src/debug/res/values/google_maps_api.xml b/ApiDemos/app/src/debug/res/values/google_maps_api.xml new file mode 100644 index 00000000..2400f398 --- /dev/null +++ b/ApiDemos/app/src/debug/res/values/google_maps_api.xml @@ -0,0 +1,21 @@ + + + + YOUR_KEY_HERE + + diff --git a/ApiDemos/app/src/main/AndroidManifest.xml b/ApiDemos/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..35d0cde8 --- /dev/null +++ b/ApiDemos/app/src/main/AndroidManifest.xml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/BasicMapDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/BasicMapDemoActivity.java new file mode 100755 index 00000000..86f4da75 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/BasicMapDemoActivity.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.MarkerOptions; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +/** + * This shows how to create a simple activity with a map and a marker on the map. + */ +public class BasicMapDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.basic_demo); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + /** + * This is where we can add markers or lines, add listeners or move the camera. In this case, + * we + * just add a marker near Africa. + */ + @Override + public void onMapReady(GoogleMap map) { + map.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker")); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/CameraDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/CameraDemoActivity.java new file mode 100644 index 00000000..beaa94b3 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/CameraDemoActivity.java @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.CameraUpdate; +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.GoogleMap.CancelableCallback; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.CameraPosition; +import com.google.android.gms.maps.model.LatLng; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.SeekBar; +import android.widget.Toast; + +/** + * This shows how to change the camera position for the map. + */ +public class CameraDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + /** + * The amount by which to scroll the camera. Note that this amount is in raw pixels, not dp + * (density-independent pixels). + */ + private static final int SCROLL_BY_PX = 100; + + public static final CameraPosition BONDI = + new CameraPosition.Builder().target(new LatLng(-33.891614, 151.276417)) + .zoom(15.5f) + .bearing(300) + .tilt(50) + .build(); + + public static final CameraPosition SYDNEY = + new CameraPosition.Builder().target(new LatLng(-33.87365, 151.20689)) + .zoom(15.5f) + .bearing(0) + .tilt(25) + .build(); + + private GoogleMap mMap; + + private CompoundButton mAnimateToggle; + + private CompoundButton mCustomDurationToggle; + + private SeekBar mCustomDurationBar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.camera_demo); + + mAnimateToggle = (CompoundButton) findViewById(R.id.animate); + mCustomDurationToggle = (CompoundButton) findViewById(R.id.duration_toggle); + mCustomDurationBar = (SeekBar) findViewById(R.id.duration_bar); + + updateEnabledState(); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + protected void onResume() { + super.onResume(); + updateEnabledState(); + } + + @Override + public void onMapReady(GoogleMap map) { + mMap = map; + + // We will provide our own zoom controls. + mMap.getUiSettings().setZoomControlsEnabled(false); + + // Show Sydney + mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(-33.87365, 151.20689), 10)); + } + + /** + * When the map is not ready the CameraUpdateFactory cannot be used. This should be called on + * all entry points that call methods on the Google Maps API. + */ + private boolean checkReady() { + if (mMap == null) { + Toast.makeText(this, R.string.map_not_ready, Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + /** + * Called when the Go To Bondi button is clicked. + */ + public void onGoToBondi(View view) { + if (!checkReady()) { + return; + } + + changeCamera(CameraUpdateFactory.newCameraPosition(BONDI)); + } + + /** + * Called when the Animate To Sydney button is clicked. + */ + public void onGoToSydney(View view) { + if (!checkReady()) { + return; + } + + changeCamera(CameraUpdateFactory.newCameraPosition(SYDNEY), new CancelableCallback() { + @Override + public void onFinish() { + Toast.makeText(getBaseContext(), "Animation to Sydney complete", Toast.LENGTH_SHORT) + .show(); + } + + @Override + public void onCancel() { + Toast.makeText(getBaseContext(), "Animation to Sydney canceled", Toast.LENGTH_SHORT) + .show(); + } + }); + } + + /** + * Called when the stop button is clicked. + */ + public void onStopAnimation(View view) { + if (!checkReady()) { + return; + } + + mMap.stopAnimation(); + } + + /** + * Called when the zoom in button (the one with the +) is clicked. + */ + public void onZoomIn(View view) { + if (!checkReady()) { + return; + } + + changeCamera(CameraUpdateFactory.zoomIn()); + } + + /** + * Called when the zoom out button (the one with the -) is clicked. + */ + public void onZoomOut(View view) { + if (!checkReady()) { + return; + } + + changeCamera(CameraUpdateFactory.zoomOut()); + } + + /** + * Called when the tilt more button (the one with the /) is clicked. + */ + public void onTiltMore(View view) { + if (!checkReady()) { + return; + } + + CameraPosition currentCameraPosition = mMap.getCameraPosition(); + float currentTilt = currentCameraPosition.tilt; + float newTilt = currentTilt + 10; + + newTilt = (newTilt > 90) ? 90 : newTilt; + + CameraPosition cameraPosition = new CameraPosition.Builder(currentCameraPosition) + .tilt(newTilt).build(); + + changeCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); + } + + /** + * Called when the tilt less button (the one with the \) is clicked. + */ + public void onTiltLess(View view) { + if (!checkReady()) { + return; + } + + CameraPosition currentCameraPosition = mMap.getCameraPosition(); + + float currentTilt = currentCameraPosition.tilt; + + float newTilt = currentTilt - 10; + newTilt = (newTilt > 0) ? newTilt : 0; + + CameraPosition cameraPosition = new CameraPosition.Builder(currentCameraPosition) + .tilt(newTilt).build(); + + changeCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); + } + + /** + * Called when the left arrow button is clicked. This causes the camera to move to the left + */ + public void onScrollLeft(View view) { + if (!checkReady()) { + return; + } + + changeCamera(CameraUpdateFactory.scrollBy(-SCROLL_BY_PX, 0)); + } + + /** + * Called when the right arrow button is clicked. This causes the camera to move to the right. + */ + public void onScrollRight(View view) { + if (!checkReady()) { + return; + } + + changeCamera(CameraUpdateFactory.scrollBy(SCROLL_BY_PX, 0)); + } + + /** + * Called when the up arrow button is clicked. The causes the camera to move up. + */ + public void onScrollUp(View view) { + if (!checkReady()) { + return; + } + + changeCamera(CameraUpdateFactory.scrollBy(0, -SCROLL_BY_PX)); + } + + /** + * Called when the down arrow button is clicked. This causes the camera to move down. + */ + public void onScrollDown(View view) { + if (!checkReady()) { + return; + } + + changeCamera(CameraUpdateFactory.scrollBy(0, SCROLL_BY_PX)); + } + + /** + * Called when the animate button is toggled + */ + public void onToggleAnimate(View view) { + updateEnabledState(); + } + + /** + * Called when the custom duration checkbox is toggled + */ + public void onToggleCustomDuration(View view) { + updateEnabledState(); + } + + /** + * Update the enabled state of the custom duration controls. + */ + private void updateEnabledState() { + mCustomDurationToggle.setEnabled(mAnimateToggle.isChecked()); + mCustomDurationBar + .setEnabled(mAnimateToggle.isChecked() && mCustomDurationToggle.isChecked()); + } + + private void changeCamera(CameraUpdate update) { + changeCamera(update, null); + } + + /** + * Change the camera position by moving or animating the camera depending on the state of the + * animate toggle button. + */ + private void changeCamera(CameraUpdate update, CancelableCallback callback) { + if (mAnimateToggle.isChecked()) { + if (mCustomDurationToggle.isChecked()) { + int duration = mCustomDurationBar.getProgress(); + // The duration must be strictly positive so we make it at least 1. + mMap.animateCamera(update, Math.max(duration, 1), callback); + } else { + mMap.animateCamera(update, callback); + } + } else { + mMap.moveCamera(update); + } + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/CircleDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/CircleDemoActivity.java new file mode 100755 index 00000000..fa69e332 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/CircleDemoActivity.java @@ -0,0 +1,262 @@ +/* Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener; +import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.BitmapDescriptorFactory; +import com.google.android.gms.maps.model.Circle; +import com.google.android.gms.maps.model.CircleOptions; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.Marker; +import com.google.android.gms.maps.model.MarkerOptions; + +import android.graphics.Color; +import android.graphics.Point; +import android.location.Location; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; + +import java.util.ArrayList; +import java.util.List; + + +/** + * This shows how to draw circles on a map. + */ +public class CircleDemoActivity extends AppCompatActivity implements OnSeekBarChangeListener, + OnMarkerDragListener, OnMapLongClickListener, OnMapReadyCallback { + + private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); + + private static final double DEFAULT_RADIUS = 1000000; + + public static final double RADIUS_OF_EARTH_METERS = 6371009; + + private static final int WIDTH_MAX = 50; + + private static final int HUE_MAX = 360; + + private static final int ALPHA_MAX = 255; + + private GoogleMap mMap; + + private List mCircles = new ArrayList(1); + + private SeekBar mColorBar; + + private SeekBar mAlphaBar; + + private SeekBar mWidthBar; + + private int mStrokeColor; + + private int mFillColor; + + private class DraggableCircle { + + private final Marker centerMarker; + + private final Marker radiusMarker; + + private final Circle circle; + + private double radius; + + public DraggableCircle(LatLng center, double radius) { + this.radius = radius; + centerMarker = mMap.addMarker(new MarkerOptions() + .position(center) + .draggable(true)); + radiusMarker = mMap.addMarker(new MarkerOptions() + .position(toRadiusLatLng(center, radius)) + .draggable(true) + .icon(BitmapDescriptorFactory.defaultMarker( + BitmapDescriptorFactory.HUE_AZURE))); + circle = mMap.addCircle(new CircleOptions() + .center(center) + .radius(radius) + .strokeWidth(mWidthBar.getProgress()) + .strokeColor(mStrokeColor) + .fillColor(mFillColor)); + } + + public DraggableCircle(LatLng center, LatLng radiusLatLng) { + this.radius = toRadiusMeters(center, radiusLatLng); + centerMarker = mMap.addMarker(new MarkerOptions() + .position(center) + .draggable(true)); + radiusMarker = mMap.addMarker(new MarkerOptions() + .position(radiusLatLng) + .draggable(true) + .icon(BitmapDescriptorFactory.defaultMarker( + BitmapDescriptorFactory.HUE_AZURE))); + circle = mMap.addCircle(new CircleOptions() + .center(center) + .radius(radius) + .strokeWidth(mWidthBar.getProgress()) + .strokeColor(mStrokeColor) + .fillColor(mFillColor)); + } + + public boolean onMarkerMoved(Marker marker) { + if (marker.equals(centerMarker)) { + circle.setCenter(marker.getPosition()); + radiusMarker.setPosition(toRadiusLatLng(marker.getPosition(), radius)); + return true; + } + if (marker.equals(radiusMarker)) { + radius = toRadiusMeters(centerMarker.getPosition(), radiusMarker.getPosition()); + circle.setRadius(radius); + return true; + } + return false; + } + + public void onStyleChange() { + circle.setStrokeWidth(mWidthBar.getProgress()); + circle.setFillColor(mFillColor); + circle.setStrokeColor(mStrokeColor); + } + } + + /** Generate LatLng of radius marker */ + private static LatLng toRadiusLatLng(LatLng center, double radius) { + double radiusAngle = Math.toDegrees(radius / RADIUS_OF_EARTH_METERS) / + Math.cos(Math.toRadians(center.latitude)); + return new LatLng(center.latitude, center.longitude + radiusAngle); + } + + private static double toRadiusMeters(LatLng center, LatLng radius) { + float[] result = new float[1]; + Location.distanceBetween(center.latitude, center.longitude, + radius.latitude, radius.longitude, result); + return result[0]; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.circle_demo); + + mColorBar = (SeekBar) findViewById(R.id.hueSeekBar); + mColorBar.setMax(HUE_MAX); + mColorBar.setProgress(0); + + mAlphaBar = (SeekBar) findViewById(R.id.alphaSeekBar); + mAlphaBar.setMax(ALPHA_MAX); + mAlphaBar.setProgress(127); + + mWidthBar = (SeekBar) findViewById(R.id.widthSeekBar); + mWidthBar.setMax(WIDTH_MAX); + mWidthBar.setProgress(10); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + mMap = map; + + // Override the default content description on the view, for accessibility mode. + map.setContentDescription(getString(R.string.map_circle_description)); + + mColorBar.setOnSeekBarChangeListener(this); + mAlphaBar.setOnSeekBarChangeListener(this); + mWidthBar.setOnSeekBarChangeListener(this); + mMap.setOnMarkerDragListener(this); + mMap.setOnMapLongClickListener(this); + + mFillColor = Color.HSVToColor( + mAlphaBar.getProgress(), new float[]{mColorBar.getProgress(), 1, 1}); + mStrokeColor = Color.BLACK; + + DraggableCircle circle = new DraggableCircle(SYDNEY, DEFAULT_RADIUS); + mCircles.add(circle); + + // Move the map so that it is centered on the initial circle + mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(SYDNEY, 4.0f)); + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // Don't do anything here. + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // Don't do anything here. + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (seekBar == mColorBar) { + mFillColor = Color.HSVToColor(Color.alpha(mFillColor), new float[]{progress, 1, 1}); + } else if (seekBar == mAlphaBar) { + mFillColor = Color.argb(progress, Color.red(mFillColor), Color.green(mFillColor), + Color.blue(mFillColor)); + } + + for (DraggableCircle draggableCircle : mCircles) { + draggableCircle.onStyleChange(); + } + } + + @Override + public void onMarkerDragStart(Marker marker) { + onMarkerMoved(marker); + } + + @Override + public void onMarkerDragEnd(Marker marker) { + onMarkerMoved(marker); + } + + @Override + public void onMarkerDrag(Marker marker) { + onMarkerMoved(marker); + } + + private void onMarkerMoved(Marker marker) { + for (DraggableCircle draggableCircle : mCircles) { + if (draggableCircle.onMarkerMoved(marker)) { + break; + } + } + } + + @Override + public void onMapLongClick(LatLng point) { + // We know the center, let's place the outline at a point 3/4 along the view. + View view = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)) + .getView(); + LatLng radiusLatLng = mMap.getProjection().fromScreenLocation(new Point( + view.getHeight() * 3 / 4, view.getWidth() * 3 / 4)); + + // ok create it + DraggableCircle circle = new DraggableCircle(point, radiusLatLng); + mCircles.add(circle); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/DemoDetails.java b/ApiDemos/app/src/main/java/com/example/mapdemo/DemoDetails.java new file mode 100755 index 00000000..181b0e00 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/DemoDetails.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import android.support.v7.app.AppCompatActivity; + +/** + * A simple POJO that holds the details about the demo that are used by the List Adapter. + */ +public class DemoDetails { + + /** + * The resource id of the title of the demo. + */ + public final int titleId; + + /** + * The resources id of the description of the demo. + */ + public final int descriptionId; + + /** + * The demo activity's class. + */ + public final Class activityClass; + + public DemoDetails( + int titleId, int descriptionId, Class activityClass) { + this.titleId = titleId; + this.descriptionId = descriptionId; + this.activityClass = activityClass; + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/DemoDetailsList.java b/ApiDemos/app/src/main/java/com/example/mapdemo/DemoDetailsList.java new file mode 100755 index 00000000..a7997220 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/DemoDetailsList.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +/** + * A list of all the demos we have available. + */ +public final class DemoDetailsList { + + /** This class should not be instantiated. */ + private DemoDetailsList() { + } + + public static final DemoDetails[] DEMOS = { + new DemoDetails(R.string.basic_map_demo_label, + R.string.basic_map_demo_description, + BasicMapDemoActivity.class), + new DemoDetails(R.string.camera_demo_label, + R.string.camera_demo_description, + CameraDemoActivity.class), + new DemoDetails(R.string.circle_demo_label, + R.string.circle_demo_description, + CircleDemoActivity.class), + new DemoDetails(R.string.events_demo_label, + R.string.events_demo_description, + EventsDemoActivity.class), + new DemoDetails(R.string.ground_overlay_demo_label, + R.string.ground_overlay_demo_description, + GroundOverlayDemoActivity.class), + new DemoDetails(R.string.indoor_demo_label, + R.string.indoor_demo_description, + IndoorDemoActivity.class), + new DemoDetails(R.string.layers_demo_label, + R.string.layers_demo_description, + LayersDemoActivity.class), + new DemoDetails(R.string.lite_demo_label, + R.string.lite_demo_description, + LiteDemoActivity.class), + new DemoDetails(R.string.lite_list_demo_label, + R.string.lite_list_demo_description, + LiteListDemoActivity.class), + new DemoDetails(R.string.location_source_demo_label, + R.string.location_source_demo_description, + LocationSourceDemoActivity.class), + new DemoDetails(R.string.map_in_pager_demo_label, + R.string.map_in_pager_demo_description, + MapInPagerDemoActivity.class), + new DemoDetails(R.string.marker_demo_label, + R.string.marker_demo_description, + MarkerDemoActivity.class), + new DemoDetails(R.string.multi_map_demo_label, + R.string.multi_map_demo_description, + MultiMapDemoActivity.class), + new DemoDetails(R.string.my_location_demo_label, + R.string.my_location_demo_description, + MyLocationDemoActivity.class), + new DemoDetails(R.string.options_demo_label, + R.string.options_demo_description, + OptionsDemoActivity.class), + new DemoDetails(R.string.polygon_demo_label, + R.string.polygon_demo_description, + PolygonDemoActivity.class), + new DemoDetails(R.string.polyline_demo_label, + R.string.polyline_demo_description, + PolylineDemoActivity.class), + new DemoDetails(R.string.programmatic_demo_label, + R.string.programmatic_demo_description, + ProgrammaticDemoActivity.class), + new DemoDetails(R.string.raw_map_view_demo_label, + R.string.raw_map_view_demo_description, + RawMapViewDemoActivity.class), + new DemoDetails(R.string.retain_map_demo_label, + R.string.retain_map_demo_description, + RetainMapDemoActivity.class), + new DemoDetails(R.string.save_state_demo_label, + R.string.save_state_demo_description, + SaveStateDemoActivity.class), + new DemoDetails(R.string.snapshot_demo_label, + R.string.snapshot_demo_description, + SnapshotDemoActivity.class), + new DemoDetails(R.string.split_street_view_panorama_and_map_demo_label, + R.string.split_street_view_panorama_and_map_demo_description, + SplitStreetViewPanoramaAndMapDemoActivity.class), + new DemoDetails(R.string.street_view_panorama_basic_demo_label, + R.string.street_view_panorama_basic_demo_description, + StreetViewPanoramaBasicDemoActivity.class), + new DemoDetails(R.string.street_view_panorama_events_demo_label, + R.string.street_view_panorama_events_demo_description, + StreetViewPanoramaEventsDemoActivity.class), + new DemoDetails(R.string.street_view_panorama_navigation_demo_label, + R.string.street_view_panorama_navigation_demo_description, + StreetViewPanoramaNavigationDemoActivity.class), + new DemoDetails(R.string.street_view_panorama_options_demo_label, + R.string.street_view_panorama_options_demo_description, + StreetViewPanoramaOptionsDemoActivity.class), + new DemoDetails(R.string.street_view_panorama_view_demo_label, + R.string.street_view_panorama_view_demo_description, + StreetViewPanoramaViewDemoActivity.class), + new DemoDetails(R.string.tile_coordinate_demo_label, + R.string.tile_coordinate_demo_description, + TileCoordinateDemoActivity.class), + new DemoDetails(R.string.tile_overlay_demo_label, + R.string.tile_overlay_demo_description, + TileOverlayDemoActivity.class), + new DemoDetails(R.string.ui_settings_demo_label, + R.string.ui_settings_demo_description, + UiSettingsDemoActivity.class), + new DemoDetails(R.string.visible_region_demo_label, + R.string.visible_region_demo_description, + VisibleRegionDemoActivity.class), + }; +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/EventsDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/EventsDemoActivity.java new file mode 100644 index 00000000..b84f2d38 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/EventsDemoActivity.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener; +import com.google.android.gms.maps.GoogleMap.OnMapClickListener; +import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.CameraPosition; +import com.google.android.gms.maps.model.LatLng; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.widget.TextView; + +/** + * This shows how to listen to some {@link GoogleMap} events. + */ +public class EventsDemoActivity extends AppCompatActivity + implements OnMapClickListener, OnMapLongClickListener, OnCameraChangeListener, + OnMapReadyCallback { + + private TextView mTapTextView; + + private TextView mCameraTextView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.events_demo); + + mTapTextView = (TextView) findViewById(R.id.tap_text); + mCameraTextView = (TextView) findViewById(R.id.camera_text); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + map.setOnMapClickListener(this); + map.setOnMapLongClickListener(this); + map.setOnCameraChangeListener(this); + } + + @Override + public void onMapClick(LatLng point) { + mTapTextView.setText("tapped, point=" + point); + } + + @Override + public void onMapLongClick(LatLng point) { + mTapTextView.setText("long pressed, point=" + point); + } + + @Override + public void onCameraChange(final CameraPosition position) { + mCameraTextView.setText(position.toString()); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/FeatureView.java b/ApiDemos/app/src/main/java/com/example/mapdemo/FeatureView.java new file mode 100755 index 00000000..c14e03b9 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/FeatureView.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.FrameLayout; +import android.widget.TextView; + +/** + * A widget that describes an activity that demonstrates a feature. + */ +public final class FeatureView extends FrameLayout { + + /** + * Constructs a feature view by inflating layout/feature.xml. + */ + public FeatureView(Context context) { + super(context); + + LayoutInflater layoutInflater = + (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + layoutInflater.inflate(R.layout.feature, this); + } + + /** + * Set the resource id of the title of the demo. + * + * @param titleId the resource id of the title of the demo + */ + public synchronized void setTitleId(int titleId) { + ((TextView) (findViewById(R.id.title))).setText(titleId); + } + + /** + * Set the resource id of the description of the demo. + * + * @param descriptionId the resource id of the description of the demo + */ + public synchronized void setDescriptionId(int descriptionId) { + ((TextView) (findViewById(R.id.description))).setText(descriptionId); + } + +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java new file mode 100644 index 00000000..f5d17f84 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.BitmapDescriptor; +import com.google.android.gms.maps.model.BitmapDescriptorFactory; +import com.google.android.gms.maps.model.GroundOverlay; +import com.google.android.gms.maps.model.GroundOverlayOptions; +import com.google.android.gms.maps.model.LatLng; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; + +import java.util.ArrayList; +import java.util.List; + +/** + * This shows how to add a ground overlay to a map. + */ +public class GroundOverlayDemoActivity extends AppCompatActivity + implements OnSeekBarChangeListener, OnMapReadyCallback { + + private static final int TRANSPARENCY_MAX = 100; + + private static final LatLng NEWARK = new LatLng(40.714086, -74.228697); + + private final List mImages = new ArrayList(); + + private GroundOverlay mGroundOverlay; + + private SeekBar mTransparencyBar; + + private int mCurrentEntry = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.ground_overlay_demo); + + mTransparencyBar = (SeekBar) findViewById(R.id.transparencySeekBar); + mTransparencyBar.setMax(TRANSPARENCY_MAX); + mTransparencyBar.setProgress(0); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + map.moveCamera(CameraUpdateFactory.newLatLngZoom(NEWARK, 11)); + + mImages.clear(); + mImages.add(BitmapDescriptorFactory.fromResource(R.drawable.newark_nj_1922)); + mImages.add(BitmapDescriptorFactory.fromResource(R.drawable.newark_prudential_sunny)); + + mCurrentEntry = 0; + mGroundOverlay = map.addGroundOverlay(new GroundOverlayOptions() + .image(mImages.get(mCurrentEntry)).anchor(0, 1) + .position(NEWARK, 8600f, 6500f)); + + mTransparencyBar.setOnSeekBarChangeListener(this); + + // Override the default content description on the view, for accessibility mode. + // Ideally this string would be localised. + map.setContentDescription("Google Map with ground overlay."); + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (mGroundOverlay != null) { + mGroundOverlay.setTransparency((float) progress / (float) TRANSPARENCY_MAX); + } + } + + public void switchImage(View view) { + mCurrentEntry = (mCurrentEntry + 1) % mImages.size(); + mGroundOverlay.setImage(mImages.get(mCurrentEntry)); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/IndoorDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/IndoorDemoActivity.java new file mode 100755 index 00000000..fa8124c3 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/IndoorDemoActivity.java @@ -0,0 +1,133 @@ +/* Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.IndoorBuilding; +import com.google.android.gms.maps.model.IndoorLevel; +import com.google.android.gms.maps.model.LatLng; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.TextView; + +import java.util.List; + +/** + * A demo activity showing how to use indoor. + */ +public class IndoorDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + private GoogleMap mMap; + + private boolean showLevelPicker = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.indoor_demo); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + mMap = map; + mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.614631, -122.385153), 18)); + } + + /** + * Called when the toggle level picker button is clicked. + */ + public void onToggleLevelPicker(View view) { + showLevelPicker = !showLevelPicker; + mMap.getUiSettings().setIndoorLevelPickerEnabled(showLevelPicker); + } + + /** + * Called when the focused building info is clicked. + */ + public void onFocusedBuildingInfo(View view) { + IndoorBuilding building = mMap.getFocusedBuilding(); + if (building != null) { + StringBuilder s = new StringBuilder(); + for (IndoorLevel level : building.getLevels()) { + s.append(level.getName()).append(" "); + } + if (building.isUnderground()) { + s.append("is underground"); + } + setText(s.toString()); + } else { + setText("No visible building"); + } + } + + /** + * Called when the focused level info is clicked. + */ + public void onVisibleLevelInfo(View view) { + IndoorBuilding building = mMap.getFocusedBuilding(); + if (building != null) { + IndoorLevel level = + building.getLevels().get(building.getActiveLevelIndex()); + if (level != null) { + setText(level.getName()); + } else { + setText("No visible level"); + } + } else { + setText("No visible building"); + } + } + + /** + * Called when the activate higher level is clicked. + */ + public void onHigherLevel(View view) { + IndoorBuilding building = mMap.getFocusedBuilding(); + if (building != null) { + List levels = building.getLevels(); + if (!levels.isEmpty()) { + int currentLevel = building.getActiveLevelIndex(); + // The levels are in 'display order' from top to bottom, + // i.e. higher levels in the building are lower numbered in the array. + int newLevel = currentLevel - 1; + if (newLevel == -1) { + newLevel = levels.size() - 1; + } + IndoorLevel level = levels.get(newLevel); + setText("Activiating level " + level.getName()); + level.activate(); + } else { + setText("No levels in building"); + } + } else { + setText("No visible building"); + } + } + + private void setText(String message) { + TextView text = (TextView) findViewById(R.id.top_text); + text.setText(message); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/LayersDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/LayersDemoActivity.java new file mode 100755 index 00000000..0ad0f2d6 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/LayersDemoActivity.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; + +import android.Manifest; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; +import android.widget.Spinner; +import android.widget.Toast; + +import static com.google.android.gms.maps.GoogleMap.MAP_TYPE_HYBRID; +import static com.google.android.gms.maps.GoogleMap.MAP_TYPE_NONE; +import static com.google.android.gms.maps.GoogleMap.MAP_TYPE_NORMAL; +import static com.google.android.gms.maps.GoogleMap.MAP_TYPE_SATELLITE; +import static com.google.android.gms.maps.GoogleMap.MAP_TYPE_TERRAIN; + +/** + * Demonstrates the different base layers of a map. + */ +public class LayersDemoActivity extends AppCompatActivity + implements OnItemSelectedListener, OnMapReadyCallback, + ActivityCompat.OnRequestPermissionsResultCallback { + + private static final int LOCATION_PERMISSION_REQUEST_CODE = 1; + + private GoogleMap mMap; + + private CheckBox mTrafficCheckbox; + + private CheckBox mMyLocationCheckbox; + + private CheckBox mBuildingsCheckbox; + + private CheckBox mIndoorCheckbox; + + private Spinner mSpinner; + + /** + * Flag indicating whether a requested permission has been denied after returning in + * {@link #onRequestPermissionsResult(int, String[], int[])}. + */ + private boolean mShowPermissionDeniedDialog = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.layers_demo); + + mSpinner = (Spinner) findViewById(R.id.layers_spinner); + ArrayAdapter adapter = ArrayAdapter.createFromResource( + this, R.array.layers_array, android.R.layout.simple_spinner_item); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mSpinner.setAdapter(adapter); + mSpinner.setOnItemSelectedListener(this); + + mTrafficCheckbox = (CheckBox) findViewById(R.id.traffic); + mMyLocationCheckbox = (CheckBox) findViewById(R.id.my_location); + mBuildingsCheckbox = (CheckBox) findViewById(R.id.buildings); + mIndoorCheckbox = (CheckBox) findViewById(R.id.indoor); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + mMap = map; + updateMapType(); + updateTraffic(); + updateMyLocation(); + updateBuildings(); + updateIndoor(); + } + + private boolean checkReady() { + if (mMap == null) { + Toast.makeText(this, R.string.map_not_ready, Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + /** + * Called when the Traffic checkbox is clicked. + */ + public void onTrafficToggled(View view) { + updateTraffic(); + } + + private void updateTraffic() { + if (!checkReady()) { + return; + } + mMap.setTrafficEnabled(mTrafficCheckbox.isChecked()); + } + + /** + * Called when the MyLocation checkbox is clicked. + */ + public void onMyLocationToggled(View view) { + updateMyLocation(); + } + + private void updateMyLocation() { + if (!checkReady()) { + return; + } + + if (!mMyLocationCheckbox.isChecked()) { + mMap.setMyLocationEnabled(false); + return; + } + + // Enable the location layer. Request the location permission if needed. + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED) { + mMap.setMyLocationEnabled(true); + } else { + // Uncheck the box until the layer has been enabled and request missing permission. + mMyLocationCheckbox.setChecked(false); + PermissionUtils.requestPermission(this, LOCATION_PERMISSION_REQUEST_CODE, + Manifest.permission.ACCESS_FINE_LOCATION, false); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results) { + if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) { + return; + } + + if (PermissionUtils.isPermissionGranted(permissions, results, + Manifest.permission.ACCESS_FINE_LOCATION)) { + mMap.setMyLocationEnabled(true); + mMyLocationCheckbox.setChecked(true); + } else { + mShowPermissionDeniedDialog = true; + } + } + + @Override + protected void onResumeFragments() { + super.onResumeFragments(); + if (mShowPermissionDeniedDialog) { + PermissionUtils.PermissionDeniedDialog + .newInstance(false).show(getSupportFragmentManager(), "dialog"); + mShowPermissionDeniedDialog = false; + } + } + + /** + * Called when the Buildings checkbox is clicked. + */ + public void onBuildingsToggled(View view) { + updateBuildings(); + } + + private void updateBuildings() { + if (!checkReady()) { + return; + } + mMap.setBuildingsEnabled(mBuildingsCheckbox.isChecked()); + } + + /** + * Called when the Indoor checkbox is clicked. + */ + public void onIndoorToggled(View view) { + updateIndoor(); + } + + private void updateIndoor() { + if (!checkReady()) { + return; + } + mMap.setIndoorEnabled(mIndoorCheckbox.isChecked()); + } + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + updateMapType(); + } + + private void updateMapType() { + // No toast because this can also be called by the Android framework in onResume() at which + // point mMap may not be ready yet. + if (mMap == null) { + return; + } + + String layerName = ((String) mSpinner.getSelectedItem()); + if (layerName.equals(getString(R.string.normal))) { + mMap.setMapType(MAP_TYPE_NORMAL); + } else if (layerName.equals(getString(R.string.hybrid))) { + mMap.setMapType(MAP_TYPE_HYBRID); + + + } else if (layerName.equals(getString(R.string.satellite))) { + mMap.setMapType(MAP_TYPE_SATELLITE); + } else if (layerName.equals(getString(R.string.terrain))) { + mMap.setMapType(MAP_TYPE_TERRAIN); + } else if (layerName.equals(getString(R.string.none_map))) { + mMap.setMapType(MAP_TYPE_NONE); + } else { + Log.i("LDA", "Error setting layer with name " + layerName); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + // Do nothing. + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/LegalInfoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/LegalInfoActivity.java new file mode 100755 index 00000000..e7727822 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/LegalInfoActivity.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.common.GooglePlayServicesUtil; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; + +/** + * Activity to show legal information. + */ +public class LegalInfoActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.legal_info); + + TextView legalInfoTextView = (TextView) findViewById(R.id.legal_info); + String openSourceSoftwareLicenseInfo = + GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(this); + if (openSourceSoftwareLicenseInfo != null) { + legalInfoTextView.setText(openSourceSoftwareLicenseInfo); + } else { + legalInfoTextView.setText(R.string.play_services_not_installed); + } + } + +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/LiteDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/LiteDemoActivity.java new file mode 100755 index 00000000..780a8a87 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/LiteDemoActivity.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.BitmapDescriptorFactory; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.LatLngBounds; +import com.google.android.gms.maps.model.MarkerOptions; +import com.google.android.gms.maps.model.PolygonOptions; +import com.google.android.gms.maps.model.PolylineOptions; + +import android.annotation.SuppressLint; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; + +/** + * This demo shows some features supported in lite mode. + * In particular it demonstrates the use of {@link com.google.android.gms.maps.model.Marker}s to + * launch the Google Maps Mobile application, {@link com.google.android.gms.maps.CameraUpdate}s + * and {@link com.google.android.gms.maps.model.Polygon}s. + */ +public class LiteDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + private static final LatLng BRISBANE = new LatLng(-27.47093, 153.0235); + + private static final LatLng MELBOURNE = new LatLng(-37.81319, 144.96298); + + private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); + + private static final LatLng ADELAIDE = new LatLng(-34.92873, 138.59995); + + private static final LatLng PERTH = new LatLng(-31.952854, 115.857342); + + private static final LatLng DARWIN = new LatLng(-12.459501, 130.839915); + + /** + * A Polygon with five points in the Norther Territory, Australia. + */ + private static final LatLng[] POLYGON = new LatLng[]{ + new LatLng(-18.000328, 130.473633), new LatLng(-16.173880, 135.087891), + new LatLng(-19.663970, 137.724609), new LatLng(-23.202307, 135.395508), + new LatLng(-19.705347, 129.550781)}; + + private GoogleMap mMap; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Set the layout + setContentView(R.layout.lite_demo); + + // Get the map and register for the ready callback + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + /** + * Move the camera to center on Darwin. + */ + public void showDarwin(View v) { + // Wait until map is ready + if (mMap == null) { + return; + } + + // Center camera on Adelaide marker + mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(DARWIN, 10f)); + } + + /** + * Move the camera to center on Adelaide. + */ + public void showAdelaide(View v) { + // Wait until map is ready + if (mMap == null) { + return; + } + + // Center camera on Adelaide marker + mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(ADELAIDE, 10f)); + } + + /** + * Move the camera to show all of Australia. + * Construct a {@link com.google.android.gms.maps.model.LatLngBounds} from markers positions, + * then move the camera. + */ + public void showAustralia(View v) { + // Wait until map is ready + if (mMap == null) { + return; + } + + // Create bounds that include all locations of the map + LatLngBounds.Builder boundsBuilder = LatLngBounds.builder() + .include(PERTH) + .include(ADELAIDE) + .include(MELBOURNE) + .include(SYDNEY) + .include(DARWIN) + .include(BRISBANE); + + // Move camera to show all markers and locations + mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(boundsBuilder.build(), 20)); + } + + /** + * Called when the map is ready to add all markers and objects to the map. + */ + @Override + public void onMapReady(GoogleMap googleMap) { + mMap = googleMap; + addMarkers(); + addPolyobjects(); + + final View mapView = getSupportFragmentManager().findFragmentById(R.id.map).getView(); + if (mapView.getViewTreeObserver().isAlive()) { + mapView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { + @SuppressWarnings("deprecation") // We use the new method when supported + @SuppressLint("NewApi") // We check which build version we are using. + @Override + public void onGlobalLayout() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } else { + mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + showAustralia(null); + } + }); + } + } + + /** + * Add a Polyline and a Polygon to the map. + * The Polyline connects Melbourne, Adelaide and Perth. The Polygon is located in the Northern + * Territory (Australia). + */ + private void addPolyobjects() { + mMap.addPolyline((new PolylineOptions()) + .add(MELBOURNE, ADELAIDE, PERTH) + .color(Color.GREEN) + .width(5f)); + + mMap.addPolygon(new PolygonOptions() + .add(POLYGON) + .fillColor(Color.CYAN) + .strokeColor(Color.BLUE) + .strokeWidth(5)); + } + + /** + * Add Markers with default info windows to the map. + */ + private void addMarkers() { + mMap.addMarker(new MarkerOptions() + .position(BRISBANE) + .title("Brisbane")); + + mMap.addMarker(new MarkerOptions() + .position(MELBOURNE) + .title("Melbourne") + .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))); + + mMap.addMarker(new MarkerOptions() + .position(SYDNEY) + .title("Sydney") + .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))); + + mMap.addMarker(new MarkerOptions() + .position(ADELAIDE) + .title("Adelaide") + .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW))); + + mMap.addMarker(new MarkerOptions() + .position(PERTH) + .title("Perth") + .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA))); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java new file mode 100755 index 00000000..563adfc0 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.MapView; +import com.google.android.gms.maps.MapsInitializer; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.MarkerOptions; + +import android.content.Context; +import android.os.Bundle; +import android.support.v4.app.ListFragment; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import java.util.HashSet; + +/** + * This shows to include a map in lite mode in a ListView. + * Note the use of the view holder pattern with the + * {@link com.google.android.gms.maps.OnMapReadyCallback}. + */ +public class LiteListDemoActivity extends AppCompatActivity { + + private ListFragment mList; + + private MapAdapter mAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.lite_list_demo); + + // Set a custom list adapter for a list of locations + mAdapter = new MapAdapter(this, LIST_LOCATIONS); + mList = (ListFragment) getSupportFragmentManager().findFragmentById(R.id.list); + mList.setListAdapter(mAdapter); + + // Set a RecyclerListener to clean up MapView from ListView + AbsListView lv = mList.getListView(); + lv.setRecyclerListener(mRecycleListener); + + } + + /** + * Adapter that displays a title and {@link com.google.android.gms.maps.MapView} for each item. + * The layout is defined in lite_list_demo_row.xml. It contains a MapView + * that is programatically initialised in + * {@link #getView(int, android.view.View, android.view.ViewGroup)} + */ + private class MapAdapter extends ArrayAdapter { + + private final HashSet mMaps = new HashSet(); + + public MapAdapter(Context context, NamedLocation[] locations) { + super(context, R.layout.lite_list_demo_row, R.id.lite_listrow_text, locations); + } + + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View row = convertView; + ViewHolder holder; + + // Check if a view can be reused, otherwise inflate a layout and set up the view holder + if (row == null) { + // Inflate view from layout file + row = getLayoutInflater().inflate(R.layout.lite_list_demo_row, null); + + // Set up holder and assign it to the View + holder = new ViewHolder(); + holder.mapView = (MapView) row.findViewById(R.id.lite_listrow_map); + holder.title = (TextView) row.findViewById(R.id.lite_listrow_text); + // Set holder as tag for row for more efficient access. + row.setTag(holder); + + // Initialise the MapView + holder.initializeMapView(); + + // Keep track of MapView + mMaps.add(holder.mapView); + } else { + // View has already been initialised, get its holder + holder = (ViewHolder) row.getTag(); + } + + // Get the NamedLocation for this item and attach it to the MapView + NamedLocation item = getItem(position); + holder.mapView.setTag(item); + + // Ensure the map has been initialised by the on map ready callback in ViewHolder. + // If it is not ready yet, it will be initialised with the NamedLocation set as its tag + // when the callback is received. + if (holder.map != null) { + // The map is already ready to be used + setMapLocation(holder.map, item); + } + + // Set the text label for this item + holder.title.setText(item.name); + + return row; + } + + /** + * Retuns the set of all initialised {@link MapView} objects. + * + * @return All MapViews that have been initialised programmatically by this adapter + */ + public HashSet getMaps() { + return mMaps; + } + } + + /** + * Displays a {@link LiteListDemoActivity.NamedLocation} on a + * {@link com.google.android.gms.maps.GoogleMap}. + * Adds a marker and centers the camera on the NamedLocation with the normal map type. + */ + private static void setMapLocation(GoogleMap map, NamedLocation data) { + // Add a marker for this item and set the camera + map.moveCamera(CameraUpdateFactory.newLatLngZoom(data.location, 13f)); + map.addMarker(new MarkerOptions().position(data.location)); + + // Set the map type back to normal. + map.setMapType(GoogleMap.MAP_TYPE_NORMAL); + } + + /** + * Holder for Views used in the {@link LiteListDemoActivity.MapAdapter}. + * Once the the map field is set, otherwise it is null. + * When the {@link #onMapReady(com.google.android.gms.maps.GoogleMap)} callback is received and + * the {@link com.google.android.gms.maps.GoogleMap} is ready, it stored in the {@link #map} + * field. The map is then initialised with the NamedLocation that is stored as the tag of the + * MapView. This ensures that the map is initialised with the latest data that it should + * display. + */ + class ViewHolder implements OnMapReadyCallback { + + MapView mapView; + + TextView title; + + GoogleMap map; + + @Override + public void onMapReady(GoogleMap googleMap) { + MapsInitializer.initialize(getApplicationContext()); + map = googleMap; + NamedLocation data = (NamedLocation) mapView.getTag(); + if (data != null) { + setMapLocation(map, data); + } + } + + /** + * Initialises the MapView by calling its lifecycle methods. + */ + public void initializeMapView() { + if (mapView != null) { + // Initialise the MapView + mapView.onCreate(null); + // Set the map ready callback to receive the GoogleMap object + mapView.getMapAsync(this); + } + } + + } + + /** + * RecycleListener that completely clears the {@link com.google.android.gms.maps.GoogleMap} + * attached to a row in the ListView. + * Sets the map type to {@link com.google.android.gms.maps.GoogleMap#MAP_TYPE_NONE} and clears + * the map. + */ + private AbsListView.RecyclerListener mRecycleListener = new AbsListView.RecyclerListener() { + + @Override + public void onMovedToScrapHeap(View view) { + ViewHolder holder = (ViewHolder) view.getTag(); + if (holder != null && holder.map != null) { + // Clear the map and free up resources by changing the map type to none + holder.map.clear(); + holder.map.setMapType(GoogleMap.MAP_TYPE_NONE); + } + + } + }; + + /** + * Location represented by a position ({@link com.google.android.gms.maps.model.LatLng} and a + * name ({@link java.lang.String}). + */ + private static class NamedLocation { + + public final String name; + + public final LatLng location; + + NamedLocation(String name, LatLng location) { + this.name = name; + this.location = location; + } + } + + /** + * A list of locations to show in this ListView. + */ + private static final NamedLocation[] LIST_LOCATIONS = new NamedLocation[]{ + new NamedLocation("Cape Town", new LatLng(-33.920455, 18.466941)), + new NamedLocation("Beijing", new LatLng(39.937795, 116.387224)), + new NamedLocation("Bern", new LatLng(46.948020, 7.448206)), + new NamedLocation("Breda", new LatLng(51.589256, 4.774396)), + new NamedLocation("Brussels", new LatLng(50.854509, 4.376678)), + new NamedLocation("Copenhagen", new LatLng(55.679423, 12.577114)), + new NamedLocation("Hannover", new LatLng(52.372026, 9.735672)), + new NamedLocation("Helsinki", new LatLng(60.169653, 24.939480)), + new NamedLocation("Hong Kong", new LatLng(22.325862, 114.165532)), + new NamedLocation("Istanbul", new LatLng(41.034435, 28.977556)), + new NamedLocation("Johannesburg", new LatLng(-26.202886, 28.039753)), + new NamedLocation("Lisbon", new LatLng(38.707163, -9.135517)), + new NamedLocation("London", new LatLng(51.500208, -0.126729)), + new NamedLocation("Madrid", new LatLng(40.420006, -3.709924)), + new NamedLocation("Mexico City", new LatLng(19.427050, -99.127571)), + new NamedLocation("Moscow", new LatLng(55.750449, 37.621136)), + new NamedLocation("New York", new LatLng(40.750580, -73.993584)), + new NamedLocation("Oslo", new LatLng(59.910761, 10.749092)), + new NamedLocation("Paris", new LatLng(48.859972, 2.340260)), + new NamedLocation("Prague", new LatLng(50.087811, 14.420460)), + new NamedLocation("Rio de Janeiro", new LatLng(-22.90187, -43.232437)), + new NamedLocation("Rome", new LatLng(41.889998, 12.500162)), + new NamedLocation("Sao Paolo", new LatLng(-22.863878, -43.244097)), + new NamedLocation("Seoul", new LatLng(37.560908, 126.987705)), + new NamedLocation("Stockholm", new LatLng(59.330650, 18.067360)), + new NamedLocation("Sydney", new LatLng(-33.873651, 151.2068896)), + new NamedLocation("Taipei", new LatLng(25.022112, 121.478019)), + new NamedLocation("Tokyo", new LatLng(35.670267, 139.769955)), + new NamedLocation("Tulsa Oklahoma", new LatLng(36.149777, -95.993398)), + new NamedLocation("Vaduz", new LatLng(47.141076, 9.521482)), + new NamedLocation("Vienna", new LatLng(48.209206, 16.372778)), + new NamedLocation("Warsaw", new LatLng(52.235474, 21.004057)), + new NamedLocation("Wellington", new LatLng(-41.286480, 174.776217)), + new NamedLocation("Winnipeg", new LatLng(49.875832, -97.150726)) + }; + +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/LocationSourceDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/LocationSourceDemoActivity.java new file mode 100644 index 00000000..126b3c37 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/LocationSourceDemoActivity.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener; +import com.google.android.gms.maps.LocationSource; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.LatLng; + +import android.location.Location; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +/** + * This shows how to use a custom location source. + */ +public class LocationSourceDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + /** + * A {@link LocationSource} which reports a new location whenever a user long presses the map + * at + * the point at which a user long pressed the map. + */ + private static class LongPressLocationSource implements LocationSource, OnMapLongClickListener { + + private OnLocationChangedListener mListener; + + /** + * Flag to keep track of the activity's lifecycle. This is not strictly necessary in this + * case because onMapLongPress events don't occur while the activity containing the map is + * paused but is included to demonstrate best practices (e.g., if a background service were + * to be used). + */ + private boolean mPaused; + + @Override + public void activate(OnLocationChangedListener listener) { + mListener = listener; + } + + @Override + public void deactivate() { + mListener = null; + } + + @Override + public void onMapLongClick(LatLng point) { + if (mListener != null && !mPaused) { + Location location = new Location("LongPressLocationProvider"); + location.setLatitude(point.latitude); + location.setLongitude(point.longitude); + location.setAccuracy(100); + mListener.onLocationChanged(location); + } + } + + public void onPause() { + mPaused = true; + } + + public void onResume() { + mPaused = false; + } + } + + private LongPressLocationSource mLocationSource; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.basic_demo); + + mLocationSource = new LongPressLocationSource(); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + protected void onResume() { + super.onResume(); + mLocationSource.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + mLocationSource.onPause(); + } + + @Override + public void onMapReady(GoogleMap map) { + map.setLocationSource(mLocationSource); + map.setOnMapLongClickListener(mLocationSource); + map.setMyLocationEnabled(true); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/MainActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/MainActivity.java new file mode 100644 index 00000000..7b3a567e --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/MainActivity.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; +import android.widget.ListView; + +/** + * The main activity of the API library demo gallery. + *

+ * The main layout lists the demonstrated features, with buttons to launch them. + */ +public final class MainActivity extends AppCompatActivity + implements AdapterView.OnItemClickListener { + + + /** + * A custom array adapter that shows a {@link FeatureView} containing details about the demo. + */ + private static class CustomArrayAdapter extends ArrayAdapter { + + /** + * @param demos An array containing the details of the demos to be displayed. + */ + public CustomArrayAdapter(Context context, DemoDetails[] demos) { + super(context, R.layout.feature, R.id.title, demos); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + FeatureView featureView; + if (convertView instanceof FeatureView) { + featureView = (FeatureView) convertView; + } else { + featureView = new FeatureView(getContext()); + } + + DemoDetails demo = getItem(position); + + featureView.setTitleId(demo.titleId); + featureView.setDescriptionId(demo.descriptionId); + + Resources resources = getContext().getResources(); + String title = resources.getString(demo.titleId); + String description = resources.getString(demo.descriptionId); + featureView.setContentDescription(title + ". " + description); + + return featureView; + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + ListView list = (ListView) findViewById(R.id.list); + + ListAdapter adapter = new CustomArrayAdapter(this, DemoDetailsList.DEMOS); + + list.setAdapter(adapter); + list.setOnItemClickListener(this); + list.setEmptyView(findViewById(R.id.empty)); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.activity_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle item selection + if (item.getItemId() == R.id.menu_legal) { + startActivity(new Intent(this, LegalInfoActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + DemoDetails demo = (DemoDetails) parent.getAdapter().getItem(position); + startActivity(new Intent(this, demo.activityClass)); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/MapInPagerDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/MapInPagerDemoActivity.java new file mode 100755 index 00000000..65e5d16b --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/MapInPagerDemoActivity.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.SupportMapFragment; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.view.ViewPager; +import android.support.v7.app.AppCompatActivity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +/** + * This shows how to add a map to a ViewPager. Note the use of + * {@link ViewGroup#requestTransparentRegion(View)} to reduce jankiness. + */ +public class MapInPagerDemoActivity extends AppCompatActivity { + + private MyAdapter mAdapter; + + private ViewPager mPager; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.map_in_pager_demo); + mAdapter = new MyAdapter(getSupportFragmentManager()); + + mPager = (ViewPager) findViewById(R.id.pager); + mPager.setAdapter(mAdapter); + + // This is required to avoid a black flash when the map is loaded. The flash is due + // to the use of a SurfaceView as the underlying view of the map. + mPager.requestTransparentRegion(mPager); + } + + /** A simple fragment that displays a TextView. */ + public static class TextFragment extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { + return inflater.inflate(R.layout.text_fragment, container, false); + } + } + + /** A simple FragmentPagerAdapter that returns two TextFragment and a SupportMapFragment. */ + public static class MyAdapter extends FragmentPagerAdapter { + + public MyAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public int getCount() { + return 3; + } + + @Override + public Fragment getItem(int position) { + switch (position) { + case 0: + case 1: + return new TextFragment(); + case 2: + return SupportMapFragment.newInstance(); + default: + return null; + } + } + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java new file mode 100644 index 00000000..76547330 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter; +import com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener; +import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener; +import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.BitmapDescriptorFactory; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.LatLngBounds; +import com.google.android.gms.maps.model.Marker; +import com.google.android.gms.maps.model.MarkerOptions; + +import android.annotation.SuppressLint; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.SystemClock; +import android.support.v7.app.AppCompatActivity; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.view.View; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; +import android.view.animation.BounceInterpolator; +import android.view.animation.Interpolator; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.RadioGroup; +import android.widget.RadioGroup.OnCheckedChangeListener; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * This shows how to place markers on a map. + */ +public class MarkerDemoActivity extends AppCompatActivity implements + OnMarkerClickListener, + OnInfoWindowClickListener, + OnMarkerDragListener, + OnSeekBarChangeListener, + OnMapReadyCallback { + + private static final LatLng BRISBANE = new LatLng(-27.47093, 153.0235); + + private static final LatLng MELBOURNE = new LatLng(-37.81319, 144.96298); + + private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); + + private static final LatLng ADELAIDE = new LatLng(-34.92873, 138.59995); + + private static final LatLng PERTH = new LatLng(-31.952854, 115.857342); + + /** Demonstrates customizing the info window and/or its contents. */ + class CustomInfoWindowAdapter implements InfoWindowAdapter { + + // These a both viewgroups containing an ImageView with id "badge" and two TextViews with id + // "title" and "snippet". + private final View mWindow; + + private final View mContents; + + CustomInfoWindowAdapter() { + mWindow = getLayoutInflater().inflate(R.layout.custom_info_window, null); + mContents = getLayoutInflater().inflate(R.layout.custom_info_contents, null); + } + + @Override + public View getInfoWindow(Marker marker) { + if (mOptions.getCheckedRadioButtonId() != R.id.custom_info_window) { + // This means that getInfoContents will be called. + return null; + } + render(marker, mWindow); + return mWindow; + } + + @Override + public View getInfoContents(Marker marker) { + if (mOptions.getCheckedRadioButtonId() != R.id.custom_info_contents) { + // This means that the default info contents will be used. + return null; + } + render(marker, mContents); + return mContents; + } + + private void render(Marker marker, View view) { + int badge; + // Use the equals() method on a Marker to check for equals. Do not use ==. + if (marker.equals(mBrisbane)) { + badge = R.drawable.badge_qld; + } else if (marker.equals(mAdelaide)) { + badge = R.drawable.badge_sa; + } else if (marker.equals(mSydney)) { + badge = R.drawable.badge_nsw; + } else if (marker.equals(mMelbourne)) { + badge = R.drawable.badge_victoria; + } else if (marker.equals(mPerth)) { + badge = R.drawable.badge_wa; + } else { + // Passing 0 to setImageResource will clear the image view. + badge = 0; + } + ((ImageView) view.findViewById(R.id.badge)).setImageResource(badge); + + String title = marker.getTitle(); + TextView titleUi = ((TextView) view.findViewById(R.id.title)); + if (title != null) { + // Spannable string allows us to edit the formatting of the text. + SpannableString titleText = new SpannableString(title); + titleText.setSpan(new ForegroundColorSpan(Color.RED), 0, titleText.length(), 0); + titleUi.setText(titleText); + } else { + titleUi.setText(""); + } + + String snippet = marker.getSnippet(); + TextView snippetUi = ((TextView) view.findViewById(R.id.snippet)); + if (snippet != null && snippet.length() > 12) { + SpannableString snippetText = new SpannableString(snippet); + snippetText.setSpan(new ForegroundColorSpan(Color.MAGENTA), 0, 10, 0); + snippetText.setSpan(new ForegroundColorSpan(Color.BLUE), 12, snippet.length(), 0); + snippetUi.setText(snippetText); + } else { + snippetUi.setText(""); + } + } + } + + private GoogleMap mMap; + + private Marker mPerth; + + private Marker mSydney; + + private Marker mBrisbane; + + private Marker mAdelaide; + + private Marker mMelbourne; + + /** + * Keeps track of the last selected marker (though it may no longer be selected). This is + * useful for refreshing the info window. + */ + private Marker mLastSelectedMarker; + + private final List mMarkerRainbow = new ArrayList(); + + private TextView mTopText; + + private SeekBar mRotationBar; + + private CheckBox mFlatBox; + + private RadioGroup mOptions; + + private final Random mRandom = new Random(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.marker_demo); + + mTopText = (TextView) findViewById(R.id.top_text); + + mRotationBar = (SeekBar) findViewById(R.id.rotationSeekBar); + mRotationBar.setMax(360); + mRotationBar.setOnSeekBarChangeListener(this); + + mFlatBox = (CheckBox) findViewById(R.id.flat); + + mOptions = (RadioGroup) findViewById(R.id.custom_info_window_options); + mOptions.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + if (mLastSelectedMarker != null && mLastSelectedMarker.isInfoWindowShown()) { + // Refresh the info window when the info window's content has changed. + mLastSelectedMarker.showInfoWindow(); + } + } + }); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + mMap = map; + + // Hide the zoom controls as the button panel will cover it. + mMap.getUiSettings().setZoomControlsEnabled(false); + + // Add lots of markers to the map. + addMarkersToMap(); + + // Setting an info window adapter allows us to change the both the contents and look of the + // info window. + mMap.setInfoWindowAdapter(new CustomInfoWindowAdapter()); + + // Set listeners for marker events. See the bottom of this class for their behavior. + mMap.setOnMarkerClickListener(this); + mMap.setOnInfoWindowClickListener(this); + mMap.setOnMarkerDragListener(this); + + // Override the default content description on the view, for accessibility mode. + // Ideally this string would be localised. + map.setContentDescription("Map with lots of markers."); + + // Pan to see all markers in view. + // Cannot zoom to bounds until the map has a size. + final View mapView = getSupportFragmentManager().findFragmentById(R.id.map).getView(); + if (mapView.getViewTreeObserver().isAlive()) { + mapView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { + @SuppressWarnings("deprecation") // We use the new method when supported + @SuppressLint("NewApi") // We check which build version we are using. + @Override + public void onGlobalLayout() { + LatLngBounds bounds = new LatLngBounds.Builder() + .include(PERTH) + .include(SYDNEY) + .include(ADELAIDE) + .include(BRISBANE) + .include(MELBOURNE) + .build(); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } else { + mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50)); + } + }); + } + } + + private void addMarkersToMap() { + // Uses a colored icon. + mBrisbane = mMap.addMarker(new MarkerOptions() + .position(BRISBANE) + .title("Brisbane") + .snippet("Population: 2,074,200") + .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))); + + // Uses a custom icon with the info window popping out of the center of the icon. + mSydney = mMap.addMarker(new MarkerOptions() + .position(SYDNEY) + .title("Sydney") + .snippet("Population: 4,627,300") + .icon(BitmapDescriptorFactory.fromResource(R.drawable.arrow)) + .infoWindowAnchor(0.5f, 0.5f)); + + // Creates a draggable marker. Long press to drag. + mMelbourne = mMap.addMarker(new MarkerOptions() + .position(MELBOURNE) + .title("Melbourne") + .snippet("Population: 4,137,400") + .draggable(true)); + + // A few more markers for good measure. + mPerth = mMap.addMarker(new MarkerOptions() + .position(PERTH) + .title("Perth") + .snippet("Population: 1,738,800")); + mAdelaide = mMap.addMarker(new MarkerOptions() + .position(ADELAIDE) + .title("Adelaide") + .snippet("Population: 1,213,000")); + + // Creates a marker rainbow demonstrating how to create default marker icons of different + // hues (colors). + float rotation = mRotationBar.getProgress(); + boolean flat = mFlatBox.isChecked(); + + int numMarkersInRainbow = 12; + for (int i = 0; i < numMarkersInRainbow; i++) { + mMarkerRainbow.add(mMap.addMarker(new MarkerOptions() + .position(new LatLng( + -30 + 10 * Math.sin(i * Math.PI / (numMarkersInRainbow - 1)), + 135 - 10 * Math.cos(i * Math.PI / (numMarkersInRainbow - 1)))) + .title("Marker " + i) + .icon(BitmapDescriptorFactory.defaultMarker(i * 360 / numMarkersInRainbow)) + .flat(flat) + .rotation(rotation))); + } + } + + private boolean checkReady() { + if (mMap == null) { + Toast.makeText(this, R.string.map_not_ready, Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + /** Called when the Clear button is clicked. */ + public void onClearMap(View view) { + if (!checkReady()) { + return; + } + mMap.clear(); + } + + /** Called when the Reset button is clicked. */ + public void onResetMap(View view) { + if (!checkReady()) { + return; + } + // Clear the map because we don't want duplicates of the markers. + mMap.clear(); + addMarkersToMap(); + } + + /** Called when the Reset button is clicked. */ + public void onToggleFlat(View view) { + if (!checkReady()) { + return; + } + boolean flat = mFlatBox.isChecked(); + for (Marker marker : mMarkerRainbow) { + marker.setFlat(flat); + } + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (!checkReady()) { + return; + } + float rotation = seekBar.getProgress(); + for (Marker marker : mMarkerRainbow) { + marker.setRotation(rotation); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // Do nothing. + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // Do nothing. + } + + // + // Marker related listeners. + // + + @Override + public boolean onMarkerClick(final Marker marker) { + if (marker.equals(mPerth)) { + // This causes the marker at Perth to bounce into position when it is clicked. + final Handler handler = new Handler(); + final long start = SystemClock.uptimeMillis(); + final long duration = 1500; + + final Interpolator interpolator = new BounceInterpolator(); + + handler.post(new Runnable() { + @Override + public void run() { + long elapsed = SystemClock.uptimeMillis() - start; + float t = Math.max( + 1 - interpolator.getInterpolation((float) elapsed / duration), 0); + marker.setAnchor(0.5f, 1.0f + 2 * t); + + if (t > 0.0) { + // Post again 16ms later. + handler.postDelayed(this, 16); + } + } + }); + } else if (marker.equals(mAdelaide)) { + // This causes the marker at Adelaide to change color and alpha. + marker.setIcon(BitmapDescriptorFactory.defaultMarker(mRandom.nextFloat() * 360)); + marker.setAlpha(mRandom.nextFloat()); + } + + mLastSelectedMarker = marker; + // We return false to indicate that we have not consumed the event and that we wish + // for the default behavior to occur (which is for the camera to move such that the + // marker is centered and for the marker's info window to open, if it has one). + return false; + } + + @Override + public void onInfoWindowClick(Marker marker) { + Toast.makeText(this, "Click Info Window", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onMarkerDragStart(Marker marker) { + mTopText.setText("onMarkerDragStart"); + } + + @Override + public void onMarkerDragEnd(Marker marker) { + mTopText.setText("onMarkerDragEnd"); + } + + @Override + public void onMarkerDrag(Marker marker) { + mTopText.setText("onMarkerDrag. Current Position: " + marker.getPosition()); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/MultiMapDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/MultiMapDemoActivity.java new file mode 100644 index 00000000..aa1b563d --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/MultiMapDemoActivity.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +/** + * This shows how to create a simple activity with multiple maps on screen. + */ +public class MultiMapDemoActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.multimap_demo); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/MyLocationDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/MyLocationDemoActivity.java new file mode 100755 index 00000000..a4352a81 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/MyLocationDemoActivity.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; + +import android.Manifest; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.widget.Toast; + +/** + * This demo shows how GMS Location can be used to check for changes to the users location. The + * "My Location" button uses GMS Location to set the blue dot representing the users location. + * Permission for {@link android.Manifest.permission#ACCESS_FINE_LOCATION} is requested at run + * time. If the permission has not been granted, the Activity is finished with an error message. + */ +public class MyLocationDemoActivity extends AppCompatActivity + implements + OnMyLocationButtonClickListener, + OnMapReadyCallback, + ActivityCompat.OnRequestPermissionsResultCallback { + + /** + * Request code for location permission request. + * + * @see #onRequestPermissionsResult(int, String[], int[]) + */ + private static final int LOCATION_PERMISSION_REQUEST_CODE = 1; + + /** + * Flag indicating whether a requested permission has been denied after returning in + * {@link #onRequestPermissionsResult(int, String[], int[])}. + */ + private boolean mPermissionDenied = false; + + private GoogleMap mMap; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.my_location_demo); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + mMap = map; + + mMap.setOnMyLocationButtonClickListener(this); + enableMyLocation(); + } + + /** + * Enables the My Location layer if the fine location permission has been granted. + */ + private void enableMyLocation() { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) + != PackageManager.PERMISSION_GRANTED) { + // Permission to access the location is missing. + PermissionUtils.requestPermission(this, LOCATION_PERMISSION_REQUEST_CODE, + Manifest.permission.ACCESS_FINE_LOCATION, true); + } else if (mMap != null) { + // Access to the location has been granted to the app. + mMap.setMyLocationEnabled(true); + } + } + + @Override + public boolean onMyLocationButtonClick() { + Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT).show(); + // Return false so that we don't consume the event and the default behavior still occurs + // (the camera animates to the user's current position). + return false; + } + + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @NonNull int[] grantResults) { + if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) { + return; + } + + if (PermissionUtils.isPermissionGranted(permissions, grantResults, + Manifest.permission.ACCESS_FINE_LOCATION)) { + // Enable the my location layer if the permission has been granted. + enableMyLocation(); + } else { + // Display the missing permission error dialog when the fragments resume. + mPermissionDenied = true; + } + } + + @Override + protected void onResumeFragments() { + super.onResumeFragments(); + if (mPermissionDenied) { + // Permission was not granted, display error dialog. + showMissingPermissionError(); + mPermissionDenied = false; + } + } + + /** + * Displays a dialog with error message explaining that the location permission is missing. + */ + private void showMissingPermissionError() { + PermissionUtils.PermissionDeniedDialog + .newInstance(true).show(getSupportFragmentManager(), "dialog"); + } + +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/OptionsDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/OptionsDemoActivity.java new file mode 100644 index 00000000..618125c3 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/OptionsDemoActivity.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +/** + * An activity that creates a map with some initial options. + */ +public final class OptionsDemoActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.options_demo); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/PermissionUtils.java b/ApiDemos/app/src/main/java/com/example/mapdemo/PermissionUtils.java new file mode 100755 index 00000000..0cb91efb --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/PermissionUtils.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import android.Manifest; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.DialogFragment; +import android.support.v7.app.AppCompatActivity; +import android.widget.Toast; + +/** + * Utility class for access to runtime permissions. + */ +public abstract class PermissionUtils { + + /** + * Requests the fine location permission. If a rationale with an additional explanation should + * be shown to the user, displays a dialog that triggers the request. + */ + public static void requestPermission(AppCompatActivity activity, int requestId, + String permission, boolean finishActivity) { + if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) { + // Display a dialog with rationale. + PermissionUtils.RationaleDialog.newInstance(requestId, finishActivity) + .show(activity.getSupportFragmentManager(), "dialog"); + } else { + // Location permission has not been granted yet, request it. + ActivityCompat.requestPermissions(activity, new String[]{permission}, requestId); + + } + } + + /** + * Checks if the result contains a {@link PackageManager#PERMISSION_GRANTED} result for a + * permission from a runtime permissions request. + * + * @see android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback + */ + public static boolean isPermissionGranted(String[] grantPermissions, int[] grantResults, + String permission) { + for (int i = 0; i < grantPermissions.length; i++) { + if (permission.equals(grantPermissions[i])) { + return grantResults[i] == PackageManager.PERMISSION_GRANTED; + } + } + return false; + } + + /** + * A dialog that displays a permission denied message. + */ + public static class PermissionDeniedDialog extends DialogFragment { + + private static final String ARGUMENT_FINISH_ACTIVITY = "finish"; + + private boolean mFinishActivity = false; + + /** + * Creates a new instance of this dialog and optionally finishes the calling Activity + * when the 'Ok' button is clicked. + */ + public static PermissionDeniedDialog newInstance(boolean finishActivity) { + Bundle arguments = new Bundle(); + arguments.putBoolean(ARGUMENT_FINISH_ACTIVITY, finishActivity); + + PermissionDeniedDialog dialog = new PermissionDeniedDialog(); + dialog.setArguments(arguments); + return dialog; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + mFinishActivity = getArguments().getBoolean(ARGUMENT_FINISH_ACTIVITY); + + return new AlertDialog.Builder(getActivity()) + .setMessage(R.string.location_permission_denied) + .setPositiveButton(android.R.string.ok, null) + .create(); + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + if (mFinishActivity) { + Toast.makeText(getActivity(), R.string.permission_required_toast, + Toast.LENGTH_SHORT).show(); + getActivity().finish(); + } + } + } + + /** + * A dialog that explains the use of the location permission and requests the necessary + * permission. + *

+ * The activity should implement + * {@link android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback} + * to handle permit or denial of this permission request. + */ + public static class RationaleDialog extends DialogFragment { + + private static final String ARGUMENT_PERMISSION_REQUEST_CODE = "requestCode"; + + private static final String ARGUMENT_FINISH_ACTIVITY = "finish"; + + private boolean mFinishActivity = false; + + /** + * Creates a new instance of a dialog displaying the rationale for the use of the location + * permission. + *

+ * The permission is requested after clicking 'ok'. + * + * @param requestCode Id of the request that is used to request the permission. It is + * returned to the + * {@link android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback}. + * @param finishActivity Whether the calling Activity should be finished if the dialog is + * cancelled. + */ + public static RationaleDialog newInstance(int requestCode, boolean finishActivity) { + Bundle arguments = new Bundle(); + arguments.putInt(ARGUMENT_PERMISSION_REQUEST_CODE, requestCode); + arguments.putBoolean(ARGUMENT_FINISH_ACTIVITY, finishActivity); + RationaleDialog dialog = new RationaleDialog(); + dialog.setArguments(arguments); + return dialog; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Bundle arguments = getArguments(); + final int requestCode = arguments.getInt(ARGUMENT_PERMISSION_REQUEST_CODE); + mFinishActivity = arguments.getBoolean(ARGUMENT_FINISH_ACTIVITY); + + return new AlertDialog.Builder(getActivity()) + .setMessage(R.string.permission_rationale_location) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // After click on Ok, request the permission. + ActivityCompat.requestPermissions(getActivity(), + new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, + requestCode); + // Do not finish the Activity while requesting permission. + mFinishActivity = false; + } + }) + .setNegativeButton(android.R.string.cancel, null) + .create(); + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + if (mFinishActivity) { + Toast.makeText(getActivity(), + R.string.permission_required_toast, + Toast.LENGTH_SHORT) + .show(); + getActivity().finish(); + } + } + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/PolygonDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/PolygonDemoActivity.java new file mode 100644 index 00000000..2e5e0150 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/PolygonDemoActivity.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.Polygon; +import com.google.android.gms.maps.model.PolygonOptions; + +import android.graphics.Color; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; + +import java.util.Arrays; +import java.util.List; + +/** + * This shows how to draw polygons on a map. + */ +public class PolygonDemoActivity extends AppCompatActivity + implements OnSeekBarChangeListener, OnMapReadyCallback { + + private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); + + private static final int WIDTH_MAX = 50; + + private static final int HUE_MAX = 360; + + private static final int ALPHA_MAX = 255; + + private Polygon mMutablePolygon; + + private SeekBar mColorBar; + + private SeekBar mAlphaBar; + + private SeekBar mWidthBar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.polygon_demo); + + mColorBar = (SeekBar) findViewById(R.id.hueSeekBar); + mColorBar.setMax(HUE_MAX); + mColorBar.setProgress(0); + + mAlphaBar = (SeekBar) findViewById(R.id.alphaSeekBar); + mAlphaBar.setMax(ALPHA_MAX); + mAlphaBar.setProgress(127); + + mWidthBar = (SeekBar) findViewById(R.id.widthSeekBar); + mWidthBar.setMax(WIDTH_MAX); + mWidthBar.setProgress(10); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + // Override the default content description on the view, for accessibility mode. + // Ideally this string would be localised. + map.setContentDescription("Google Map with polygons."); + + // Create a rectangle with two rectangular holes. + map.addPolygon(new PolygonOptions() + .addAll(createRectangle(new LatLng(-20, 130), 5, 5)) + .addHole(createRectangle(new LatLng(-22, 128), 1, 1)) + .addHole(createRectangle(new LatLng(-18, 133), 0.5, 1.5)) + .fillColor(Color.CYAN) + .strokeColor(Color.BLUE) + .strokeWidth(5)); + + // Create a rectangle centered at Sydney. + PolygonOptions options = new PolygonOptions().addAll(createRectangle(SYDNEY, 5, 8)); + + int fillColor = Color.HSVToColor( + mAlphaBar.getProgress(), new float[]{mColorBar.getProgress(), 1, 1}); + mMutablePolygon = map.addPolygon(options + .strokeWidth(mWidthBar.getProgress()) + .strokeColor(Color.BLACK) + .fillColor(fillColor)); + + mColorBar.setOnSeekBarChangeListener(this); + mAlphaBar.setOnSeekBarChangeListener(this); + mWidthBar.setOnSeekBarChangeListener(this); + + // Move the map so that it is centered on the mutable polygon. + map.moveCamera(CameraUpdateFactory.newLatLng(SYDNEY)); + } + + /** + * Creates a List of LatLngs that form a rectangle with the given dimensions. + */ + private List createRectangle(LatLng center, double halfWidth, double halfHeight) { + return Arrays.asList(new LatLng(center.latitude - halfHeight, center.longitude - halfWidth), + new LatLng(center.latitude - halfHeight, center.longitude + halfWidth), + new LatLng(center.latitude + halfHeight, center.longitude + halfWidth), + new LatLng(center.latitude + halfHeight, center.longitude - halfWidth), + new LatLng(center.latitude - halfHeight, center.longitude - halfWidth)); + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // Don't do anything here. + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // Don't do anything here. + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (mMutablePolygon == null) { + return; + } + + if (seekBar == mColorBar) { + mMutablePolygon.setFillColor(Color.HSVToColor( + Color.alpha(mMutablePolygon.getFillColor()), new float[]{progress, 1, 1})); + } else if (seekBar == mAlphaBar) { + int prevColor = mMutablePolygon.getFillColor(); + mMutablePolygon.setFillColor(Color.argb( + progress, Color.red(prevColor), Color.green(prevColor), + Color.blue(prevColor))); + } else if (seekBar == mWidthBar) { + mMutablePolygon.setStrokeWidth(progress); + } + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/PolylineDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/PolylineDemoActivity.java new file mode 100644 index 00000000..64077bce --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/PolylineDemoActivity.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.Polyline; +import com.google.android.gms.maps.model.PolylineOptions; + +import android.graphics.Color; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; + +/** + * This shows how to draw polylines on a map. + */ +public class PolylineDemoActivity extends AppCompatActivity + implements OnSeekBarChangeListener, OnMapReadyCallback { + + private static final LatLng MELBOURNE = new LatLng(-37.81319, 144.96298); + + private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); + + private static final LatLng ADELAIDE = new LatLng(-34.92873, 138.59995); + + private static final LatLng PERTH = new LatLng(-31.95285, 115.85734); + + private static final LatLng LHR = new LatLng(51.471547, -0.460052); + + private static final LatLng LAX = new LatLng(33.936524, -118.377686); + + private static final LatLng JFK = new LatLng(40.641051, -73.777485); + + private static final LatLng AKL = new LatLng(-37.006254, 174.783018); + + private static final int WIDTH_MAX = 50; + + private static final int HUE_MAX = 360; + + private static final int ALPHA_MAX = 255; + + private Polyline mMutablePolyline; + + private SeekBar mColorBar; + + private SeekBar mAlphaBar; + + private SeekBar mWidthBar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.polyline_demo); + + mColorBar = (SeekBar) findViewById(R.id.hueSeekBar); + mColorBar.setMax(HUE_MAX); + mColorBar.setProgress(0); + + mAlphaBar = (SeekBar) findViewById(R.id.alphaSeekBar); + mAlphaBar.setMax(ALPHA_MAX); + mAlphaBar.setProgress(255); + + mWidthBar = (SeekBar) findViewById(R.id.widthSeekBar); + mWidthBar.setMax(WIDTH_MAX); + mWidthBar.setProgress(10); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + // Override the default content description on the view, for accessibility mode. + // Ideally this string would be localised. + map.setContentDescription("Google Map with polylines."); + + // A simple polyline with the default options from Melbourne-Adelaide-Perth. + map.addPolyline((new PolylineOptions()) + .add(MELBOURNE, ADELAIDE, PERTH)); + + // A geodesic polyline that goes around the world. + map.addPolyline((new PolylineOptions()) + .add(LHR, AKL, LAX, JFK, LHR) + .width(5) + .color(Color.BLUE) + .geodesic(true)); + + // Rectangle centered at Sydney. This polyline will be mutable. + int radius = 5; + PolylineOptions options = new PolylineOptions() + .add(new LatLng(SYDNEY.latitude + radius, SYDNEY.longitude + radius)) + .add(new LatLng(SYDNEY.latitude + radius, SYDNEY.longitude - radius)) + .add(new LatLng(SYDNEY.latitude - radius, SYDNEY.longitude - radius)) + .add(new LatLng(SYDNEY.latitude - radius, SYDNEY.longitude + radius)) + .add(new LatLng(SYDNEY.latitude + radius, SYDNEY.longitude + radius)); + int color = Color.HSVToColor( + mAlphaBar.getProgress(), new float[]{mColorBar.getProgress(), 1, 1}); + mMutablePolyline = map.addPolyline(options + .color(color) + .width(mWidthBar.getProgress())); + + mColorBar.setOnSeekBarChangeListener(this); + mAlphaBar.setOnSeekBarChangeListener(this); + mWidthBar.setOnSeekBarChangeListener(this); + + // Move the map so that it is centered on the mutable polyline. + map.moveCamera(CameraUpdateFactory.newLatLng(SYDNEY)); + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // Don't do anything here. + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // Don't do anything here. + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (mMutablePolyline == null) { + return; + } + + if (seekBar == mColorBar) { + mMutablePolyline.setColor(Color.HSVToColor( + Color.alpha(mMutablePolyline.getColor()), new float[]{progress, 1, 1})); + } else if (seekBar == mAlphaBar) { + float[] prevHSV = new float[3]; + Color.colorToHSV(mMutablePolyline.getColor(), prevHSV); + mMutablePolyline.setColor(Color.HSVToColor(progress, prevHSV)); + } else if (seekBar == mWidthBar) { + mMutablePolyline.setWidth(progress); + } + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/ProgrammaticDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/ProgrammaticDemoActivity.java new file mode 100644 index 00000000..28fa04cb --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/ProgrammaticDemoActivity.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.MarkerOptions; + +import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; + +/** + * Demonstrates how to instantiate a SupportMapFragment programmatically and add a marker to it. + */ +public class ProgrammaticDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + private static final String MAP_FRAGMENT_TAG = "map"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // It isn't possible to set a fragment's id programmatically so we set a tag instead and + // search for it using that. + SupportMapFragment mapFragment = (SupportMapFragment) + getSupportFragmentManager().findFragmentByTag(MAP_FRAGMENT_TAG); + + // We only create a fragment if it doesn't already exist. + if (mapFragment == null) { + // To programmatically add the map, we first create a SupportMapFragment. + mapFragment = SupportMapFragment.newInstance(); + + // Then we add it using a FragmentTransaction. + FragmentTransaction fragmentTransaction = + getSupportFragmentManager().beginTransaction(); + fragmentTransaction.add(android.R.id.content, mapFragment, MAP_FRAGMENT_TAG); + fragmentTransaction.commit(); + } + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + map.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker")); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/RawMapViewDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/RawMapViewDemoActivity.java new file mode 100644 index 00000000..7fe2ae64 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/RawMapViewDemoActivity.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.MapView; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.MarkerOptions; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +/** + * This shows how to create a simple activity with a raw MapView and add a marker to it. This + * requires forwarding all the important lifecycle methods onto MapView. + */ +public class RawMapViewDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + private MapView mMapView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.raw_mapview_demo); + + mMapView = (MapView) findViewById(R.id.map); + mMapView.onCreate(savedInstanceState); + + mMapView.getMapAsync(this); + } + + @Override + protected void onResume() { + super.onResume(); + mMapView.onResume(); + } + + @Override + public void onMapReady(GoogleMap map) { + map.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker")); + } + + @Override + protected void onPause() { + mMapView.onPause(); + super.onPause(); + } + + @Override + protected void onDestroy() { + mMapView.onDestroy(); + super.onDestroy(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mMapView.onLowMemory(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mMapView.onSaveInstanceState(outState); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/RetainMapDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/RetainMapDemoActivity.java new file mode 100755 index 00000000..87acc026 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/RetainMapDemoActivity.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.MarkerOptions; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +/** + * This shows how to retain a map across activity restarts (e.g., from screen rotations), which can + * be faster than relying on state serialization. + */ +public class RetainMapDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.basic_demo); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + + if (savedInstanceState == null) { + // First incarnation of this activity. + mapFragment.setRetainInstance(true); + } + + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + map.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker")); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/SaveStateDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/SaveStateDemoActivity.java new file mode 100755 index 00000000..44d10c29 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/SaveStateDemoActivity.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener; +import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.BitmapDescriptorFactory; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.Marker; +import com.google.android.gms.maps.model.MarkerOptions; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.v7.app.AppCompatActivity; + +import java.util.Random; + +/** + * This activity shows how to save the state of a MapFragment when the activity is recreated, like + * after rotation of the device. + */ +public class SaveStateDemoActivity extends AppCompatActivity { + + /** Default marker position when the activity is first created. */ + private static final LatLng DEFAULT_MARKER_POSITION = new LatLng(48.858179, 2.294576); + + /** List of hues to use for the marker */ + private static final float[] MARKER_HUES = new float[]{ + BitmapDescriptorFactory.HUE_RED, + BitmapDescriptorFactory.HUE_ORANGE, + BitmapDescriptorFactory.HUE_YELLOW, + BitmapDescriptorFactory.HUE_GREEN, + BitmapDescriptorFactory.HUE_CYAN, + BitmapDescriptorFactory.HUE_AZURE, + BitmapDescriptorFactory.HUE_BLUE, + BitmapDescriptorFactory.HUE_VIOLET, + BitmapDescriptorFactory.HUE_MAGENTA, + BitmapDescriptorFactory.HUE_ROSE, + }; + + // Bundle keys. + private static final String OTHER_OPTIONS = "options"; + + private static final String MARKER_POSITION = "markerPosition"; + + private static final String MARKER_INFO = "markerInfo"; + + /** + * Extra info about a marker. + */ + static class MarkerInfo implements Parcelable { + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public MarkerInfo createFromParcel(Parcel in) { + return new MarkerInfo(in); + } + + @Override + public MarkerInfo[] newArray(int size) { + return new MarkerInfo[size]; + } + }; + + float mHue; + + public MarkerInfo(float color) { + mHue = color; + } + + private MarkerInfo(Parcel in) { + mHue = in.readFloat(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeFloat(mHue); + } + } + + /** + * Example of a custom {@code MapFragment} showing how the position of a marker and other + * custom + * {@link Parcelable}s objects can be saved after rotation of the device. + *

+ * Storing custom {@link Parcelable} objects directly in the {@link Bundle} provided by the + * {@link #onActivityCreated(Bundle)} method will throw a {@code ClassNotFoundException}. This + * is due to the fact that this Bundle is parceled (thus losing its ClassLoader attribute at + * this moment) and unparceled later in a different ClassLoader. + *
+ * A workaround to store these objects is to wrap the custom {@link Parcelable} objects in a + * new + * {@link Bundle} object. + *

+ * However, note that it is safe to store {@link Parcelable} objects from the Maps API (eg. + * MarkerOptions, LatLng, etc.) directly in the Bundle provided by the + * {@link #onActivityCreated(Bundle)} method. + */ + public static class SaveStateMapFragment extends SupportMapFragment + implements OnMarkerClickListener, OnMarkerDragListener, OnMapReadyCallback { + + private LatLng mMarkerPosition; + + private MarkerInfo mMarkerInfo; + + private boolean mMoveCameraToMarker; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (savedInstanceState == null) { + // Activity created for the first time. + mMarkerPosition = DEFAULT_MARKER_POSITION; + mMarkerInfo = new MarkerInfo(BitmapDescriptorFactory.HUE_RED); + mMoveCameraToMarker = true; + } else { + // Extract the state of the MapFragment: + // - Objects from the API (eg. LatLng, MarkerOptions, etc.) were stored directly in + // the savedInsanceState Bundle. + // - Custom Parcelable objects were wrapped in another Bundle. + + mMarkerPosition = savedInstanceState.getParcelable(MARKER_POSITION); + + Bundle bundle = savedInstanceState.getBundle(OTHER_OPTIONS); + mMarkerInfo = bundle.getParcelable(MARKER_INFO); + + mMoveCameraToMarker = false; + } + + getMapAsync(this); + } + + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + // All Parcelable objects of the API (eg. LatLng, MarkerOptions, etc.) can be set + // directly in the given Bundle. + outState.putParcelable(MARKER_POSITION, mMarkerPosition); + + // All other custom Parcelable objects must be wrapped in another Bundle. Indeed, + // failing to do so would throw a ClassNotFoundException. This is due to the fact that + // this Bundle is being parceled (losing its ClassLoader at this time) and unparceled + // later in a different ClassLoader. + Bundle bundle = new Bundle(); + bundle.putParcelable(MARKER_INFO, mMarkerInfo); + outState.putBundle(OTHER_OPTIONS, bundle); + } + + @Override + public boolean onMarkerClick(Marker marker) { + float newHue = MARKER_HUES[new Random().nextInt(MARKER_HUES.length)]; + mMarkerInfo.mHue = newHue; + marker.setIcon(BitmapDescriptorFactory.defaultMarker(newHue)); + return true; + } + + @Override + public void onMapReady(GoogleMap map) { + MarkerOptions markerOptions = new MarkerOptions() + .position(mMarkerPosition) + .icon(BitmapDescriptorFactory.defaultMarker(mMarkerInfo.mHue)) + .draggable(true); + map.addMarker(markerOptions); + map.setOnMarkerDragListener(this); + map.setOnMarkerClickListener(this); + + if (mMoveCameraToMarker) { + map.animateCamera(CameraUpdateFactory.newLatLng(mMarkerPosition)); + } + } + + @Override + public void onMarkerDragStart(Marker marker) { + } + + @Override + public void onMarkerDrag(Marker marker) { + } + + @Override + public void onMarkerDragEnd(Marker marker) { + mMarkerPosition = marker.getPosition(); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.save_state_demo); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/SnapshotDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/SnapshotDemoActivity.java new file mode 100755 index 00000000..2473e0af --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/SnapshotDemoActivity.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.GoogleMap.OnMapLoadedCallback; +import com.google.android.gms.maps.GoogleMap.SnapshotReadyCallback; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; + +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.CheckBox; +import android.widget.ImageView; + +/** + * This shows how to take a snapshot of the map. + */ +public class SnapshotDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + /** + * Note that this may be null if the Google Play services APK is not available. + */ + private GoogleMap mMap; + + private CheckBox mWaitForMapLoadCheckBox; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.snapshot_demo); + mWaitForMapLoadCheckBox = (CheckBox) findViewById(R.id.wait_for_map_load); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + mMap = map; + } + + /** + * Called when the snapshot button is clicked. + */ + public void onScreenshot(View view) { + takeSnapshot(); + } + + private void takeSnapshot() { + if (mMap == null) { + return; + } + + final ImageView snapshotHolder = (ImageView) findViewById(R.id.snapshot_holder); + + final SnapshotReadyCallback callback = new SnapshotReadyCallback() { + @Override + public void onSnapshotReady(Bitmap snapshot) { + // Callback is called from the main thread, so we can modify the ImageView safely. + snapshotHolder.setImageBitmap(snapshot); + } + }; + + if (mWaitForMapLoadCheckBox.isChecked()) { + mMap.setOnMapLoadedCallback(new OnMapLoadedCallback() { + @Override + public void onMapLoaded() { + mMap.snapshot(callback); + } + }); + } else { + mMap.snapshot(callback); + } + } + + /** + * Called when the clear button is clicked. + */ + public void onClearScreenshot(View view) { + ImageView snapshotHolder = (ImageView) findViewById(R.id.snapshot_holder); + snapshotHolder.setImageDrawable(null); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/SplitStreetViewPanoramaAndMapDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/SplitStreetViewPanoramaAndMapDemoActivity.java new file mode 100755 index 00000000..ada85879 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/SplitStreetViewPanoramaAndMapDemoActivity.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.OnStreetViewPanoramaReadyCallback; +import com.google.android.gms.maps.StreetViewPanorama; +import com.google.android.gms.maps.StreetViewPanorama.OnStreetViewPanoramaChangeListener; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.SupportStreetViewPanoramaFragment; +import com.google.android.gms.maps.model.BitmapDescriptorFactory; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.Marker; +import com.google.android.gms.maps.model.MarkerOptions; +import com.google.android.gms.maps.model.StreetViewPanoramaLocation; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +/** + * This shows how to create a simple activity with streetview and a map + */ +public class SplitStreetViewPanoramaAndMapDemoActivity extends AppCompatActivity + implements OnMarkerDragListener, OnStreetViewPanoramaChangeListener { + + private static final String MARKER_POSITION_KEY = "MarkerPosition"; + + // George St, Sydney + private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); + + private StreetViewPanorama mStreetViewPanorama; + + private Marker mMarker; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.split_street_view_panorama_and_map_demo); + + final LatLng markerPosition; + if (savedInstanceState == null) { + markerPosition = SYDNEY; + } else { + markerPosition = savedInstanceState.getParcelable(MARKER_POSITION_KEY); + } + + SupportStreetViewPanoramaFragment streetViewPanoramaFragment = + (SupportStreetViewPanoramaFragment) + getSupportFragmentManager().findFragmentById(R.id.streetviewpanorama); + streetViewPanoramaFragment.getStreetViewPanoramaAsync( + new OnStreetViewPanoramaReadyCallback() { + @Override + public void onStreetViewPanoramaReady(StreetViewPanorama panorama) { + mStreetViewPanorama = panorama; + mStreetViewPanorama.setOnStreetViewPanoramaChangeListener( + SplitStreetViewPanoramaAndMapDemoActivity.this); + // Only need to set the position once as the streetview fragment will maintain + // its state. + if (savedInstanceState == null) { + mStreetViewPanorama.setPosition(SYDNEY); + } + } + }); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(new OnMapReadyCallback() { + @Override + public void onMapReady(GoogleMap map) { + map.setOnMarkerDragListener(SplitStreetViewPanoramaAndMapDemoActivity.this); + // Creates a draggable marker. Long press to drag. + mMarker = map.addMarker(new MarkerOptions() + .position(markerPosition) + .icon(BitmapDescriptorFactory.fromResource(R.drawable.pegman)) + .draggable(true)); + } + }); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelable(MARKER_POSITION_KEY, mMarker.getPosition()); + } + + @Override + public void onStreetViewPanoramaChange(StreetViewPanoramaLocation location) { + if (location != null) { + mMarker.setPosition(location.position); + } + } + + @Override + public void onMarkerDragStart(Marker marker) { + } + + @Override + public void onMarkerDragEnd(Marker marker) { + mStreetViewPanorama.setPosition(marker.getPosition(), 150); + } + + @Override + public void onMarkerDrag(Marker marker) { + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaBasicDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaBasicDemoActivity.java new file mode 100755 index 00000000..6eedcf9b --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaBasicDemoActivity.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.OnStreetViewPanoramaReadyCallback; +import com.google.android.gms.maps.StreetViewPanorama; +import com.google.android.gms.maps.SupportStreetViewPanoramaFragment; +import com.google.android.gms.maps.model.LatLng; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +/** + * This shows how to create a simple activity with streetview + */ +public class StreetViewPanoramaBasicDemoActivity extends AppCompatActivity { + + // George St, Sydney + private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.street_view_panorama_basic_demo); + + SupportStreetViewPanoramaFragment streetViewPanoramaFragment = + (SupportStreetViewPanoramaFragment) + getSupportFragmentManager().findFragmentById(R.id.streetviewpanorama); + streetViewPanoramaFragment.getStreetViewPanoramaAsync( + new OnStreetViewPanoramaReadyCallback() { + @Override + public void onStreetViewPanoramaReady(StreetViewPanorama panorama) { + // Only set the panorama to SYDNEY on startup (when no panoramas have been + // loaded which is when the savedInstanceState is null). + if (savedInstanceState == null) { + panorama.setPosition(SYDNEY); + } + } + }); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaEventsDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaEventsDemoActivity.java new file mode 100755 index 00000000..a29e030b --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaEventsDemoActivity.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.OnStreetViewPanoramaReadyCallback; +import com.google.android.gms.maps.StreetViewPanorama; +import com.google.android.gms.maps.StreetViewPanorama.OnStreetViewPanoramaCameraChangeListener; +import com.google.android.gms.maps.StreetViewPanorama.OnStreetViewPanoramaChangeListener; +import com.google.android.gms.maps.StreetViewPanorama.OnStreetViewPanoramaClickListener; +import com.google.android.gms.maps.StreetViewPanorama.OnStreetViewPanoramaLongClickListener; +import com.google.android.gms.maps.SupportStreetViewPanoramaFragment; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.StreetViewPanoramaCamera; +import com.google.android.gms.maps.model.StreetViewPanoramaLocation; +import com.google.android.gms.maps.model.StreetViewPanoramaOrientation; + +import android.graphics.Point; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.widget.TextView; + +/** + * This shows how to listen to some {@link StreetViewPanorama} events. + */ +public class StreetViewPanoramaEventsDemoActivity extends AppCompatActivity + implements OnStreetViewPanoramaChangeListener, OnStreetViewPanoramaCameraChangeListener, + OnStreetViewPanoramaClickListener, OnStreetViewPanoramaLongClickListener { + + // George St, Sydney + private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); + + private StreetViewPanorama mStreetViewPanorama; + + private TextView mPanoChangeTimesTextView; + + private TextView mPanoCameraChangeTextView; + + private TextView mPanoClickTextView; + + private TextView mPanoLongClickTextView; + + private int mPanoChangeTimes = 0; + + private int mPanoCameraChangeTimes = 0; + + private int mPanoClickTimes = 0; + + private int mPanoLongClickTimes = 0; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.street_view_panorama_events_demo); + + mPanoChangeTimesTextView = (TextView) findViewById(R.id.change_pano); + mPanoCameraChangeTextView = (TextView) findViewById(R.id.change_camera); + mPanoClickTextView = (TextView) findViewById(R.id.click_pano); + mPanoLongClickTextView = (TextView) findViewById(R.id.long_click_pano); + + SupportStreetViewPanoramaFragment streetViewPanoramaFragment = + (SupportStreetViewPanoramaFragment) + getSupportFragmentManager().findFragmentById(R.id.streetviewpanorama); + streetViewPanoramaFragment.getStreetViewPanoramaAsync( + new OnStreetViewPanoramaReadyCallback() { + @Override + public void onStreetViewPanoramaReady(StreetViewPanorama panorama) { + mStreetViewPanorama = panorama; + mStreetViewPanorama.setOnStreetViewPanoramaChangeListener( + StreetViewPanoramaEventsDemoActivity.this); + mStreetViewPanorama.setOnStreetViewPanoramaCameraChangeListener( + StreetViewPanoramaEventsDemoActivity.this); + mStreetViewPanorama.setOnStreetViewPanoramaClickListener( + StreetViewPanoramaEventsDemoActivity.this); + mStreetViewPanorama.setOnStreetViewPanoramaLongClickListener( + StreetViewPanoramaEventsDemoActivity.this); + + // Only set the panorama to SYDNEY on startup (when no panoramas have been + // loaded which is when the savedInstanceState is null). + if (savedInstanceState == null) { + mStreetViewPanorama.setPosition(SYDNEY); + } + } + }); + } + + @Override + public void onStreetViewPanoramaChange(StreetViewPanoramaLocation location) { + if (location != null) { + mPanoChangeTimesTextView.setText("Times panorama changed=" + ++mPanoChangeTimes); + } + } + + @Override + public void onStreetViewPanoramaCameraChange(StreetViewPanoramaCamera camera) { + mPanoCameraChangeTextView.setText("Times camera changed=" + ++mPanoCameraChangeTimes); + } + + @Override + public void onStreetViewPanoramaClick(StreetViewPanoramaOrientation orientation) { + Point point = mStreetViewPanorama.orientationToPoint(orientation); + if (point != null) { + mPanoClickTimes++; + mPanoClickTextView.setText( + "Times clicked=" + mPanoClickTimes + " : " + point.toString()); + mStreetViewPanorama.animateTo( + new StreetViewPanoramaCamera.Builder() + .orientation(orientation) + .zoom(mStreetViewPanorama.getPanoramaCamera().zoom) + .build(), 1000); + } + } + + @Override + public void onStreetViewPanoramaLongClick(StreetViewPanoramaOrientation orientation) { + Point point = mStreetViewPanorama.orientationToPoint(orientation); + if (point != null) { + mPanoLongClickTimes++; + mPanoLongClickTextView.setText( + "Times long clicked=" + mPanoLongClickTimes + " : " + point.toString()); + } + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaNavigationDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaNavigationDemoActivity.java new file mode 100755 index 00000000..b60995b0 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaNavigationDemoActivity.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.OnStreetViewPanoramaReadyCallback; +import com.google.android.gms.maps.StreetViewPanorama; +import com.google.android.gms.maps.SupportStreetViewPanoramaFragment; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.StreetViewPanoramaCamera; +import com.google.android.gms.maps.model.StreetViewPanoramaLink; +import com.google.android.gms.maps.model.StreetViewPanoramaLocation; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.SeekBar; +import android.widget.Toast; + +/** + * This shows how to create an activity with access to all the options in Panorama + * which can be adjusted dynamically + */ + +public class StreetViewPanoramaNavigationDemoActivity extends AppCompatActivity { + + // George St, Sydney + private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); + + // Cole St, San Fran + private static final LatLng SAN_FRAN = new LatLng(37.769263, -122.450727); + + // Santorini, Greece + private static final String SANTORINI = "WddsUw1geEoAAAQIt9RnsQ"; + + // LatLng with no panorama + private static final LatLng INVALID = new LatLng(-45.125783, 151.276417); + + /** + * The amount in degrees by which to scroll the camera + */ + private static final int PAN_BY_DEG = 30; + + private static final float ZOOM_BY = 0.5f; + + private StreetViewPanorama mStreetViewPanorama; + + private SeekBar mCustomDurationBar; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.street_view_panorama_navigation_demo); + + SupportStreetViewPanoramaFragment streetViewPanoramaFragment = + (SupportStreetViewPanoramaFragment) + getSupportFragmentManager().findFragmentById(R.id.streetviewpanorama); + streetViewPanoramaFragment.getStreetViewPanoramaAsync( + new OnStreetViewPanoramaReadyCallback() { + @Override + public void onStreetViewPanoramaReady(StreetViewPanorama panorama) { + mStreetViewPanorama = panorama; + // Only set the panorama to SYDNEY on startup (when no panoramas have been + // loaded which is when the savedInstanceState is null). + if (savedInstanceState == null) { + mStreetViewPanorama.setPosition(SYDNEY); + } + } + }); + mCustomDurationBar = (SeekBar) findViewById(R.id.duration_bar); + } + + /** + * When the panorama is not ready the PanoramaView cannot be used. This should be called on + * all entry points that call methods on the Panorama API. + */ + private boolean checkReady() { + if (mStreetViewPanorama == null) { + Toast.makeText(this, R.string.panorama_not_ready, Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + /** + * Called when the Go To San Fran button is clicked. + */ + public void onGoToSanFran(View view) { + if (!checkReady()) { + return; + } + mStreetViewPanorama.setPosition(SAN_FRAN, 30); + } + + /** + * Called when the Animate To Sydney button is clicked. + */ + public void onGoToSydney(View view) { + if (!checkReady()) { + return; + } + mStreetViewPanorama.setPosition(SYDNEY); + } + + /** + * Called when the Animate To Santorini button is clicked. + */ + public void onGoToSantorini(View view) { + if (!checkReady()) { + return; + } + mStreetViewPanorama.setPosition(SANTORINI); + } + + /** + * Called when the Animate To Invalid button is clicked. + */ + public void onGoToInvalid(View view) { + if (!checkReady()) { + return; + } + mStreetViewPanorama.setPosition(INVALID); + } + + public void onZoomIn(View view) { + if (!checkReady()) { + return; + } + + mStreetViewPanorama.animateTo( + new StreetViewPanoramaCamera.Builder().zoom( + mStreetViewPanorama.getPanoramaCamera().zoom + ZOOM_BY) + .tilt(mStreetViewPanorama.getPanoramaCamera().tilt) + .bearing(mStreetViewPanorama.getPanoramaCamera().bearing) + .build(), getDuration()); + } + + public void onZoomOut(View view) { + if (!checkReady()) { + return; + } + + mStreetViewPanorama.animateTo( + new StreetViewPanoramaCamera.Builder().zoom( + mStreetViewPanorama.getPanoramaCamera().zoom - ZOOM_BY) + .tilt(mStreetViewPanorama.getPanoramaCamera().tilt) + .bearing(mStreetViewPanorama.getPanoramaCamera().bearing) + .build(), getDuration()); + } + + public void onPanLeft(View view) { + if (!checkReady()) { + return; + } + + mStreetViewPanorama.animateTo( + new StreetViewPanoramaCamera.Builder().zoom( + mStreetViewPanorama.getPanoramaCamera().zoom) + .tilt(mStreetViewPanorama.getPanoramaCamera().tilt) + .bearing(mStreetViewPanorama.getPanoramaCamera().bearing - PAN_BY_DEG) + .build(), getDuration()); + } + + public void onPanRight(View view) { + if (!checkReady()) { + return; + } + + mStreetViewPanorama.animateTo( + new StreetViewPanoramaCamera.Builder().zoom( + mStreetViewPanorama.getPanoramaCamera().zoom) + .tilt(mStreetViewPanorama.getPanoramaCamera().tilt) + .bearing(mStreetViewPanorama.getPanoramaCamera().bearing + PAN_BY_DEG) + .build(), getDuration()); + + } + + public void onPanUp(View view) { + if (!checkReady()) { + return; + } + + float currentTilt = mStreetViewPanorama.getPanoramaCamera().tilt; + float newTilt = currentTilt + PAN_BY_DEG; + + newTilt = (newTilt > 90) ? 90 : newTilt; + + mStreetViewPanorama.animateTo( + new StreetViewPanoramaCamera.Builder() + .zoom(mStreetViewPanorama.getPanoramaCamera().zoom) + .tilt(newTilt) + .bearing(mStreetViewPanorama.getPanoramaCamera().bearing) + .build(), getDuration()); + } + + public void onPanDown(View view) { + if (!checkReady()) { + return; + } + + float currentTilt = mStreetViewPanorama.getPanoramaCamera().tilt; + float newTilt = currentTilt - PAN_BY_DEG; + + newTilt = (newTilt < -90) ? -90 : newTilt; + + mStreetViewPanorama.animateTo( + new StreetViewPanoramaCamera.Builder() + .zoom(mStreetViewPanorama.getPanoramaCamera().zoom) + .tilt(newTilt) + .bearing(mStreetViewPanorama.getPanoramaCamera().bearing) + .build(), getDuration()); + } + + public void onRequestPosition(View view) { + if (!checkReady()) { + return; + } + if (mStreetViewPanorama.getLocation() != null) { + Toast.makeText(view.getContext(), mStreetViewPanorama.getLocation().position.toString(), + Toast.LENGTH_SHORT).show(); + } + } + + public void onMovePosition(View view) { + StreetViewPanoramaLocation location = mStreetViewPanorama.getLocation(); + StreetViewPanoramaCamera camera = mStreetViewPanorama.getPanoramaCamera(); + if (location != null && location.links != null) { + StreetViewPanoramaLink link = findClosestLinkToBearing(location.links, camera.bearing); + mStreetViewPanorama.setPosition(link.panoId); + } + } + + public static StreetViewPanoramaLink findClosestLinkToBearing(StreetViewPanoramaLink[] links, + float bearing) { + float minBearingDiff = 360; + StreetViewPanoramaLink closestLink = links[0]; + for (StreetViewPanoramaLink link : links) { + if (minBearingDiff > findNormalizedDifference(bearing, link.bearing)) { + minBearingDiff = findNormalizedDifference(bearing, link.bearing); + closestLink = link; + } + } + return closestLink; + } + + // Find the difference between angle a and b as a value between 0 and 180 + public static float findNormalizedDifference(float a, float b) { + float diff = a - b; + float normalizedDiff = diff - (float) (360 * Math.floor(diff / 360.0f)); + return (normalizedDiff < 180.0f) ? normalizedDiff : 360.0f - normalizedDiff; + } + + private long getDuration() { + return mCustomDurationBar.getProgress(); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaOptionsDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaOptionsDemoActivity.java new file mode 100755 index 00000000..e74a8a55 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaOptionsDemoActivity.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.mapdemo; + +import com.google.android.gms.maps.OnStreetViewPanoramaReadyCallback; +import com.google.android.gms.maps.StreetViewPanorama; +import com.google.android.gms.maps.SupportStreetViewPanoramaFragment; +import com.google.android.gms.maps.model.LatLng; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.CheckBox; +import android.widget.Toast; + +/** + * This shows how to create an activity with static streetview (all options have been switched off) + */ +public class StreetViewPanoramaOptionsDemoActivity extends AppCompatActivity { + + // Cole St, San Fran + private static final LatLng SAN_FRAN = new LatLng(37.765927, -122.449972); + + private StreetViewPanorama mStreetViewPanorama; + + private CheckBox mStreetNameCheckbox; + + private CheckBox mNavigationCheckbox; + + private CheckBox mZoomCheckbox; + + private CheckBox mPanningCheckbox; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.street_view_panorama_options_demo); + + mStreetNameCheckbox = (CheckBox) findViewById(R.id.streetnames); + mNavigationCheckbox = (CheckBox) findViewById(R.id.navigation); + mZoomCheckbox = (CheckBox) findViewById(R.id.zoom); + mPanningCheckbox = (CheckBox) findViewById(R.id.panning); + + SupportStreetViewPanoramaFragment streetViewPanoramaFragment = + (SupportStreetViewPanoramaFragment) + getSupportFragmentManager().findFragmentById(R.id.streetviewpanorama); + streetViewPanoramaFragment.getStreetViewPanoramaAsync( + new OnStreetViewPanoramaReadyCallback() { + @Override + public void onStreetViewPanoramaReady(StreetViewPanorama panorama) { + mStreetViewPanorama = panorama; + mStreetViewPanorama.setStreetNamesEnabled(mStreetNameCheckbox.isChecked()); + mStreetViewPanorama + .setUserNavigationEnabled(mNavigationCheckbox.isChecked()); + mStreetViewPanorama.setZoomGesturesEnabled(mZoomCheckbox.isChecked()); + mStreetViewPanorama.setPanningGesturesEnabled(mPanningCheckbox.isChecked()); + + // Only set the panorama to SAN_FRAN on startup (when no panoramas have been + // loaded which is when the savedInstanceState is null). + if (savedInstanceState == null) { + mStreetViewPanorama.setPosition(SAN_FRAN); + } + } + }); + } + + private boolean checkReady() { + if (mStreetViewPanorama == null) { + Toast.makeText(this, R.string.map_not_ready, Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + public void onStreetNamesToggled(View view) { + if (!checkReady()) { + return; + } + mStreetViewPanorama.setStreetNamesEnabled(mStreetNameCheckbox.isChecked()); + } + + public void onNavigationToggled(View view) { + if (!checkReady()) { + return; + } + mStreetViewPanorama.setUserNavigationEnabled(mNavigationCheckbox.isChecked()); + } + + public void onZoomToggled(View view) { + if (!checkReady()) { + return; + } + mStreetViewPanorama.setZoomGesturesEnabled(mZoomCheckbox.isChecked()); + } + + public void onPanningToggled(View view) { + if (!checkReady()) { + return; + } + mStreetViewPanorama.setPanningGesturesEnabled(mPanningCheckbox.isChecked()); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaViewDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaViewDemoActivity.java new file mode 100755 index 00000000..11d1fa41 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/StreetViewPanoramaViewDemoActivity.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.StreetViewPanoramaOptions; +import com.google.android.gms.maps.StreetViewPanoramaView; +import com.google.android.gms.maps.model.LatLng; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.ViewGroup.LayoutParams; + +/** + * This shows how to create a simple activity with streetview + */ +public class StreetViewPanoramaViewDemoActivity extends AppCompatActivity { + + // George St, Sydney + private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); + + private StreetViewPanoramaView mStreetViewPanoramaView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + StreetViewPanoramaOptions options = new StreetViewPanoramaOptions(); + if (savedInstanceState == null) { + options.position(SYDNEY); + } + + mStreetViewPanoramaView = new StreetViewPanoramaView(this, options); + addContentView(mStreetViewPanoramaView, + new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + + mStreetViewPanoramaView.onCreate(savedInstanceState); + } + + @Override + protected void onResume() { + mStreetViewPanoramaView.onResume(); + super.onResume(); + } + + @Override + protected void onPause() { + mStreetViewPanoramaView.onPause(); + super.onPause(); + } + + @Override + protected void onDestroy() { + mStreetViewPanoramaView.onDestroy(); + super.onPause(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mStreetViewPanoramaView.onSaveInstanceState(outState); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/TileCoordinateDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/TileCoordinateDemoActivity.java new file mode 100755 index 00000000..b0ecf5df --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/TileCoordinateDemoActivity.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.Tile; +import com.google.android.gms.maps.model.TileOverlayOptions; +import com.google.android.gms.maps.model.TileProvider; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +import java.io.ByteArrayOutputStream; + +/** + * This demonstrates tile overlay coordinates. + */ +public class TileCoordinateDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tile_coordinate_demo); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + TileProvider coordTileProvider = new CoordTileProvider(this.getApplicationContext()); + map.addTileOverlay(new TileOverlayOptions().tileProvider(coordTileProvider)); + } + + private static class CoordTileProvider implements TileProvider { + + private static final int TILE_SIZE_DP = 256; + + private final float mScaleFactor; + + private final Bitmap mBorderTile; + + public CoordTileProvider(Context context) { + /* Scale factor based on density, with a 0.6 multiplier to increase tile generation + * speed */ + mScaleFactor = context.getResources().getDisplayMetrics().density * 0.6f; + Paint borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + borderPaint.setStyle(Paint.Style.STROKE); + mBorderTile = Bitmap.createBitmap((int) (TILE_SIZE_DP * mScaleFactor), + (int) (TILE_SIZE_DP * mScaleFactor), android.graphics.Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(mBorderTile); + canvas.drawRect(0, 0, TILE_SIZE_DP * mScaleFactor, TILE_SIZE_DP * mScaleFactor, + borderPaint); + } + + @Override + public Tile getTile(int x, int y, int zoom) { + Bitmap coordTile = drawTileCoords(x, y, zoom); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + coordTile.compress(Bitmap.CompressFormat.PNG, 0, stream); + byte[] bitmapData = stream.toByteArray(); + return new Tile((int) (TILE_SIZE_DP * mScaleFactor), + (int) (TILE_SIZE_DP * mScaleFactor), bitmapData); + } + + private Bitmap drawTileCoords(int x, int y, int zoom) { + // Synchronize copying the bitmap to avoid a race condition in some devices. + Bitmap copy = null; + synchronized (mBorderTile) { + copy = mBorderTile.copy(android.graphics.Bitmap.Config.ARGB_8888, true); + } + Canvas canvas = new Canvas(copy); + String tileCoords = "(" + x + ", " + y + ")"; + String zoomLevel = "zoom = " + zoom; + /* Paint is not thread safe. */ + Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTextPaint.setTextAlign(Paint.Align.CENTER); + mTextPaint.setTextSize(18 * mScaleFactor); + canvas.drawText(tileCoords, TILE_SIZE_DP * mScaleFactor / 2, + TILE_SIZE_DP * mScaleFactor / 2, mTextPaint); + canvas.drawText(zoomLevel, TILE_SIZE_DP * mScaleFactor / 2, + TILE_SIZE_DP * mScaleFactor * 2 / 3, mTextPaint); + return copy; + } + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/TileOverlayDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/TileOverlayDemoActivity.java new file mode 100644 index 00000000..960b7e80 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/TileOverlayDemoActivity.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.TileOverlay; +import com.google.android.gms.maps.model.TileOverlayOptions; +import com.google.android.gms.maps.model.TileProvider; +import com.google.android.gms.maps.model.UrlTileProvider; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.CheckBox; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Locale; + +/** + * This demonstrates how to add a tile overlay to a map. + */ +public class TileOverlayDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + /** This returns moon tiles. */ + private static final String MOON_MAP_URL_FORMAT = + "http://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/%d/%d/%d.jpg"; + + private TileOverlay mMoonTiles; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tile_overlay_demo); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + map.setMapType(GoogleMap.MAP_TYPE_NONE); + + TileProvider tileProvider = new UrlTileProvider(256, 256) { + @Override + public synchronized URL getTileUrl(int x, int y, int zoom) { + // The moon tile coordinate system is reversed. This is not normal. + int reversedY = (1 << zoom) - y - 1; + String s = String.format(Locale.US, MOON_MAP_URL_FORMAT, zoom, x, reversedY); + URL url = null; + try { + url = new URL(s); + } catch (MalformedURLException e) { + throw new AssertionError(e); + } + return url; + } + }; + + mMoonTiles = map.addTileOverlay(new TileOverlayOptions().tileProvider(tileProvider)); + } + + public void setFadeIn(View v) { + if (mMoonTiles == null) { + return; + } + mMoonTiles.setFadeIn(((CheckBox) v).isChecked()); + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/UiSettingsDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/UiSettingsDemoActivity.java new file mode 100755 index 00000000..d27e62f0 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/UiSettingsDemoActivity.java @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.UiSettings; + +import android.Manifest; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.CheckBox; +import android.widget.Toast; + +/** + * This shows how UI settings can be toggled. + */ +public class UiSettingsDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + private GoogleMap mMap; + + private UiSettings mUiSettings; + + private CheckBox mMyLocationButtonCheckbox; + + private CheckBox mMyLocationLayerCheckbox; + + private static final int MY_LOCATION_PERMISSION_REQUEST_CODE = 1; + + private static final int LOCATION_LAYER_PERMISSION_REQUEST_CODE = 2; + + /** + * Flag indicating whether a requested permission has been denied after returning in + * {@link #onRequestPermissionsResult(int, String[], int[])}. + */ + private boolean mLocationPermissionDenied = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.ui_settings_demo); + + mMyLocationButtonCheckbox = (CheckBox) findViewById(R.id.mylocationbutton_toggle); + mMyLocationLayerCheckbox = (CheckBox) findViewById(R.id.mylocationlayer_toggle); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + /** + * Returns whether the checkbox with the given id is checked. + */ + private boolean isChecked(int id) { + return ((CheckBox) findViewById(id)).isChecked(); + } + + @Override + public void onMapReady(GoogleMap map) { + mMap = map; + + mUiSettings = mMap.getUiSettings(); + + // Keep the UI Settings state in sync with the checkboxes. + mUiSettings.setZoomControlsEnabled(isChecked(R.id.zoom_buttons_toggle)); + mUiSettings.setCompassEnabled(isChecked(R.id.compass_toggle)); + mUiSettings.setMyLocationButtonEnabled(isChecked(R.id.mylocationbutton_toggle)); + mMap.setMyLocationEnabled(isChecked(R.id.mylocationlayer_toggle)); + mUiSettings.setScrollGesturesEnabled(isChecked(R.id.scroll_toggle)); + mUiSettings.setZoomGesturesEnabled(isChecked(R.id.zoom_gestures_toggle)); + mUiSettings.setTiltGesturesEnabled(isChecked(R.id.tilt_toggle)); + mUiSettings.setRotateGesturesEnabled(isChecked(R.id.rotate_toggle)); + } + + /** + * Checks if the map is ready (which depends on whether the Google Play services APK is + * available. This should be called prior to calling any methods on GoogleMap. + */ + private boolean checkReady() { + if (mMap == null) { + Toast.makeText(this, R.string.map_not_ready, Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + public void setZoomButtonsEnabled(View v) { + if (!checkReady()) { + return; + } + // Enables/disables the zoom controls (+/- buttons in the bottom-right of the map for LTR + // locale or bottom-left for RTL locale). + mUiSettings.setZoomControlsEnabled(((CheckBox) v).isChecked()); + } + + public void setCompassEnabled(View v) { + if (!checkReady()) { + return; + } + // Enables/disables the compass (icon in the top-left for LTR locale or top-right for RTL + // locale that indicates the orientation of the map). + mUiSettings.setCompassEnabled(((CheckBox) v).isChecked()); + } + + public void setMyLocationButtonEnabled(View v) { + if (!checkReady()) { + return; + } + // Enables/disables the my location button (this DOES NOT enable/disable the my location + // dot/chevron on the map). The my location button will never appear if the my location + // layer is not enabled. + // First verify that the location permission has been granted. + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED) { + mUiSettings.setMyLocationButtonEnabled(mMyLocationButtonCheckbox.isChecked()); + } else { + // Uncheck the box and request missing location permission. + mMyLocationButtonCheckbox.setChecked(false); + requestLocationPermission(MY_LOCATION_PERMISSION_REQUEST_CODE); + } + } + + public void setMyLocationLayerEnabled(View v) { + if (!checkReady()) { + return; + } + // Enables/disables the my location layer (i.e., the dot/chevron on the map). If enabled, it + // will also cause the my location button to show (if it is enabled); if disabled, the my + // location button will never show. + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED) { + mMap.setMyLocationEnabled(mMyLocationLayerCheckbox.isChecked()); + } else { + // Uncheck the box and request missing location permission. + mMyLocationLayerCheckbox.setChecked(false); + PermissionUtils.requestPermission(this, LOCATION_LAYER_PERMISSION_REQUEST_CODE, + Manifest.permission.ACCESS_FINE_LOCATION, false); + } + } + + public void setScrollGesturesEnabled(View v) { + if (!checkReady()) { + return; + } + // Enables/disables scroll gestures (i.e. panning the map). + mUiSettings.setScrollGesturesEnabled(((CheckBox) v).isChecked()); + } + + public void setZoomGesturesEnabled(View v) { + if (!checkReady()) { + return; + } + // Enables/disables zoom gestures (i.e., double tap, pinch & stretch). + mUiSettings.setZoomGesturesEnabled(((CheckBox) v).isChecked()); + } + + public void setTiltGesturesEnabled(View v) { + if (!checkReady()) { + return; + } + // Enables/disables tilt gestures. + mUiSettings.setTiltGesturesEnabled(((CheckBox) v).isChecked()); + } + + public void setRotateGesturesEnabled(View v) { + if (!checkReady()) { + return; + } + // Enables/disables rotate gestures. + mUiSettings.setRotateGesturesEnabled(((CheckBox) v).isChecked()); + } + + /** + * Requests the fine location permission. If a rationale with an additional explanation should + * be shown to the user, displays a dialog that triggers the request. + */ + public void requestLocationPermission(int requestCode) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.ACCESS_FINE_LOCATION)) { + // Display a dialog with rationale. + PermissionUtils.RationaleDialog + .newInstance(requestCode, false).show( + getSupportFragmentManager(), "dialog"); + } else { + // Location permission has not been granted yet, request it. + PermissionUtils.requestPermission(this, requestCode, + Manifest.permission.ACCESS_FINE_LOCATION, false); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @NonNull int[] grantResults) { + if (requestCode == MY_LOCATION_PERMISSION_REQUEST_CODE) { + // Enable the My Location button if the permission has been granted. + if (PermissionUtils.isPermissionGranted(permissions, grantResults, + Manifest.permission.ACCESS_FINE_LOCATION)) { + mUiSettings.setMyLocationButtonEnabled(true); + mMyLocationButtonCheckbox.setChecked(true); + } else { + mLocationPermissionDenied = true; + } + + } else if (requestCode == LOCATION_LAYER_PERMISSION_REQUEST_CODE) { + // Enable the My Location layer if the permission has been granted. + if (PermissionUtils.isPermissionGranted(permissions, grantResults, + Manifest.permission.ACCESS_FINE_LOCATION)) { + mMap.setMyLocationEnabled(true); + mMyLocationLayerCheckbox.setChecked(true); + } else { + mLocationPermissionDenied = true; + } + } + } + + @Override + protected void onResumeFragments() { + super.onResumeFragments(); + if (mLocationPermissionDenied) { + PermissionUtils.PermissionDeniedDialog + .newInstance(false).show(getSupportFragmentManager(), "dialog"); + mLocationPermissionDenied = false; + } + } +} diff --git a/ApiDemos/app/src/main/java/com/example/mapdemo/VisibleRegionDemoActivity.java b/ApiDemos/app/src/main/java/com/example/mapdemo/VisibleRegionDemoActivity.java new file mode 100755 index 00000000..fdd97540 --- /dev/null +++ b/ApiDemos/app/src/main/java/com/example/mapdemo/VisibleRegionDemoActivity.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mapdemo; + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.CameraPosition; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.LatLngBounds; +import com.google.android.gms.maps.model.MarkerOptions; + +import android.os.Bundle; +import android.os.Handler; +import android.os.SystemClock; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.animation.Interpolator; +import android.view.animation.OvershootInterpolator; +import android.widget.TextView; +import android.widget.Toast; + +/** + * This shows how to use setPadding to allow overlays that obscure part of the map without + * obscuring the map UI or copyright notices. + */ +public class VisibleRegionDemoActivity extends AppCompatActivity implements OnMapReadyCallback { + + /** + * Note that this may be null if the Google Play services APK is not available. + */ + private GoogleMap mMap; + + private static final LatLng SOH = new LatLng(-33.85704, 151.21522); + + private static final LatLng SFO = new LatLng(37.614631, -122.385153); + + private static final LatLngBounds AUS = new LatLngBounds( + new LatLng(-44, 113), new LatLng(-10, 154)); + + private TextView mMessageView; + + /** Keep track of current values for padding, so we can animate from them. */ + int currentLeft = 150; + + int currentTop = 0; + + int currentRight = 0; + + int currentBottom = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.visible_region_demo); + mMessageView = (TextView) findViewById(R.id.message_text); + + SupportMapFragment mapFragment = + (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync(this); + } + + @Override + public void onMapReady(GoogleMap map) { + mMap = map; + + // Move to a place with indoor (SFO airport). + mMap.setPadding(currentLeft, currentTop, currentRight, currentBottom); + mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(SFO, 18)); + // Add a marker to the Opera House. + mMap.addMarker(new MarkerOptions().position(SOH).title("Sydney Opera House")); + // Add a camera change listener. + mMap.setOnCameraChangeListener(new OnCameraChangeListener() { + @Override + public void onCameraChange(CameraPosition pos) { + mMessageView.setText("CameraChangeListener: " + pos); + } + }); + } + + /** + * Checks if the map is ready (which depends on whether the Google Play services APK is + * available. This should be called prior to calling any methods on GoogleMap. + */ + private boolean checkReady() { + if (mMap == null) { + Toast.makeText(this, R.string.map_not_ready, Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + public void moveToOperaHouse(View view) { + if (!checkReady()) { + return; + } + mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(SOH, 16)); + } + + public void moveToSFO(View view) { + if (!checkReady()) { + return; + } + mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(SFO, 18)); + } + + public void moveToAUS(View view) { + if (!checkReady()) { + return; + } + mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(AUS, 0)); + } + + public void setNoPadding(View view) { + if (!checkReady()) { + return; + } + animatePadding(150, 0, 0, 0); + } + + public void setMorePadding(View view) { + if (!checkReady()) { + return; + } + View mapView = ((SupportMapFragment) + getSupportFragmentManager().findFragmentById(R.id.map)).getView(); + int left = 150; + int top = 0; + int right = mapView.getWidth() / 3; + int bottom = mapView.getHeight() / 4; + animatePadding(left, top, right, bottom); + } + + public void animatePadding( + final int toLeft, final int toTop, final int toRight, final int toBottom) { + + final Handler handler = new Handler(); + final long start = SystemClock.uptimeMillis(); + final long duration = 1000; + + final Interpolator interpolator = new OvershootInterpolator(); + + final int startLeft = currentLeft; + final int startTop = currentTop; + final int startRight = currentRight; + final int startBottom = currentBottom; + + currentLeft = toLeft; + currentTop = toTop; + currentRight = toRight; + currentBottom = toBottom; + + handler.post(new Runnable() { + @Override + public void run() { + long elapsed = SystemClock.uptimeMillis() - start; + float t = interpolator.getInterpolation((float) elapsed / duration); + + int left = (int) (startLeft + ((toLeft - startLeft) * t)); + int top = (int) (startTop + ((toTop - startTop) * t)); + int right = (int) (startRight + ((toRight - startRight) * t)); + int bottom = (int) (startBottom + ((toBottom - startBottom) * t)); + + mMap.setPadding(left, top, right, bottom); + + if (elapsed < duration) { + // Post again 16ms later. + handler.postDelayed(this, 16); + } + } + }); + } +} diff --git a/ApiDemos/app/src/main/res/drawable-hdpi/arrow.png b/ApiDemos/app/src/main/res/drawable-hdpi/arrow.png new file mode 100644 index 00000000..7e1da1f6 Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-hdpi/arrow.png differ diff --git a/ApiDemos/app/src/main/res/drawable-hdpi/badge_nsw.png b/ApiDemos/app/src/main/res/drawable-hdpi/badge_nsw.png new file mode 100644 index 00000000..3a121046 Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-hdpi/badge_nsw.png differ diff --git a/ApiDemos/app/src/main/res/drawable-hdpi/badge_qld.png b/ApiDemos/app/src/main/res/drawable-hdpi/badge_qld.png new file mode 100644 index 00000000..9787fb15 Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-hdpi/badge_qld.png differ diff --git a/ApiDemos/app/src/main/res/drawable-hdpi/badge_sa.png b/ApiDemos/app/src/main/res/drawable-hdpi/badge_sa.png new file mode 100644 index 00000000..11aa229f Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-hdpi/badge_sa.png differ diff --git a/ApiDemos/app/src/main/res/drawable-hdpi/badge_victoria.png b/ApiDemos/app/src/main/res/drawable-hdpi/badge_victoria.png new file mode 100644 index 00000000..80db77e7 Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-hdpi/badge_victoria.png differ diff --git a/ApiDemos/app/src/main/res/drawable-hdpi/badge_wa.png b/ApiDemos/app/src/main/res/drawable-hdpi/badge_wa.png new file mode 100644 index 00000000..7c0dc76c Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-hdpi/badge_wa.png differ diff --git a/ApiDemos/app/src/main/res/drawable-hdpi/custom_info_bubble.9.png b/ApiDemos/app/src/main/res/drawable-hdpi/custom_info_bubble.9.png new file mode 100644 index 00000000..21dc176f Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-hdpi/custom_info_bubble.9.png differ diff --git a/ApiDemos/app/src/main/res/drawable-hdpi/pegman.png b/ApiDemos/app/src/main/res/drawable-hdpi/pegman.png new file mode 100755 index 00000000..9508e910 Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-hdpi/pegman.png differ diff --git a/ApiDemos/app/src/main/res/drawable-mdpi/arrow.png b/ApiDemos/app/src/main/res/drawable-mdpi/arrow.png new file mode 100644 index 00000000..77b3f5aa Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-mdpi/arrow.png differ diff --git a/ApiDemos/app/src/main/res/drawable-mdpi/custom_info_bubble.9.png b/ApiDemos/app/src/main/res/drawable-mdpi/custom_info_bubble.9.png new file mode 100644 index 00000000..b6bf33b7 Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-mdpi/custom_info_bubble.9.png differ diff --git a/ApiDemos/app/src/main/res/drawable-mdpi/pegman.png b/ApiDemos/app/src/main/res/drawable-mdpi/pegman.png new file mode 100755 index 00000000..bcb7aee4 Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-mdpi/pegman.png differ diff --git a/ApiDemos/app/src/main/res/drawable-xhdpi/pegman.png b/ApiDemos/app/src/main/res/drawable-xhdpi/pegman.png new file mode 100755 index 00000000..f1c8b5cc Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-xhdpi/pegman.png differ diff --git a/ApiDemos/app/src/main/res/drawable-xxhdpi/pegman.png b/ApiDemos/app/src/main/res/drawable-xxhdpi/pegman.png new file mode 100755 index 00000000..8ff1e335 Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable-xxhdpi/pegman.png differ diff --git a/ApiDemos/app/src/main/res/drawable/newark_nj_1922.png b/ApiDemos/app/src/main/res/drawable/newark_nj_1922.png new file mode 100644 index 00000000..6139abb1 Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable/newark_nj_1922.png differ diff --git a/ApiDemos/app/src/main/res/drawable/newark_prudential_sunny.jpg b/ApiDemos/app/src/main/res/drawable/newark_prudential_sunny.jpg new file mode 100755 index 00000000..294fe5ef Binary files /dev/null and b/ApiDemos/app/src/main/res/drawable/newark_prudential_sunny.jpg differ diff --git a/ApiDemos/app/src/main/res/layout-land/snapshot_demo.xml b/ApiDemos/app/src/main/res/layout-land/snapshot_demo.xml new file mode 100755 index 00000000..ef009a6a --- /dev/null +++ b/ApiDemos/app/src/main/res/layout-land/snapshot_demo.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + +