mirror of
https://github.com/googlemaps/android-samples.git
synced 2025-12-08 18:02:20 +00:00
chore: Add Kotlin version of CurrentPlaceDetailsOnMap. (#215)
This commit is contained in:
parent
2dccc34eca
commit
693275318b
@ -24,12 +24,24 @@ update_configs:
|
||||
commit_message:
|
||||
prefix: "chore(deps)"
|
||||
|
||||
- package_manager: "java:gradle"
|
||||
directory: "./tutorials/kotlin/CurrentPlaceDetailsOnMap/"
|
||||
update_schedule: "daily"
|
||||
commit_message:
|
||||
prefix: "chore(deps)"
|
||||
|
||||
- package_manager: "java:gradle"
|
||||
directory: "./tutorials/java/MapWithMarker/"
|
||||
update_schedule: "daily"
|
||||
commit_message:
|
||||
prefix: "chore(deps)"
|
||||
|
||||
- package_manager: "java:gradle"
|
||||
directory: "./tutorials/kotlin/MapWithMarker/"
|
||||
update_schedule: "daily"
|
||||
commit_message:
|
||||
prefix: "chore(deps)"
|
||||
|
||||
- package_manager: "java:gradle"
|
||||
directory: "./tutorials/java/Polygons/"
|
||||
update_schedule: "daily"
|
||||
@ -37,13 +49,13 @@ update_configs:
|
||||
prefix: "chore(deps)"
|
||||
|
||||
- package_manager: "java:gradle"
|
||||
directory: "./tutorials/java/StyledMap/"
|
||||
directory: "./tutorials/kotlin/Polygons/"
|
||||
update_schedule: "daily"
|
||||
commit_message:
|
||||
prefix: "chore(deps)"
|
||||
|
||||
- package_manager: "java:gradle"
|
||||
directory: "./tutorials/kotlin/MapWithMarker/"
|
||||
directory: "./tutorials/java/StyledMap/"
|
||||
update_schedule: "daily"
|
||||
commit_message:
|
||||
prefix: "chore(deps)"
|
||||
|
||||
@ -62,75 +62,88 @@ public class MapsActivityCurrentPlace extends AppCompatActivity
|
||||
implements OnMapReadyCallback {
|
||||
|
||||
private static final String TAG = MapsActivityCurrentPlace.class.getSimpleName();
|
||||
private GoogleMap mMap;
|
||||
private CameraPosition mCameraPosition;
|
||||
private GoogleMap map;
|
||||
private CameraPosition cameraPosition;
|
||||
|
||||
// The entry point to the Places API.
|
||||
private PlacesClient mPlacesClient;
|
||||
private PlacesClient placesClient;
|
||||
|
||||
// The entry point to the Fused Location Provider.
|
||||
private FusedLocationProviderClient mFusedLocationProviderClient;
|
||||
private FusedLocationProviderClient fusedLocationProviderClient;
|
||||
|
||||
// A default location (Sydney, Australia) and default zoom to use when location permission is
|
||||
// not granted.
|
||||
private final LatLng mDefaultLocation = new LatLng(-33.8523341, 151.2106085);
|
||||
private final LatLng defaultLocation = new LatLng(-33.8523341, 151.2106085);
|
||||
private static final int DEFAULT_ZOOM = 15;
|
||||
private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
|
||||
private boolean mLocationPermissionGranted;
|
||||
private boolean locationPermissionGranted;
|
||||
|
||||
// The geographical location where the device is currently located. That is, the last-known
|
||||
// location retrieved by the Fused Location Provider.
|
||||
private Location mLastKnownLocation;
|
||||
private Location lastKnownLocation;
|
||||
|
||||
// Keys for storing activity state.
|
||||
// [START maps_current_place_state_keys]
|
||||
private static final String KEY_CAMERA_POSITION = "camera_position";
|
||||
private static final String KEY_LOCATION = "location";
|
||||
// [END maps_current_place_state_keys]
|
||||
|
||||
// Used for selecting the current place.
|
||||
private static final int M_MAX_ENTRIES = 5;
|
||||
private String[] mLikelyPlaceNames;
|
||||
private String[] mLikelyPlaceAddresses;
|
||||
private List[] mLikelyPlaceAttributions;
|
||||
private LatLng[] mLikelyPlaceLatLngs;
|
||||
private String[] likelyPlaceNames;
|
||||
private String[] likelyPlaceAddresses;
|
||||
private List[] likelyPlaceAttributions;
|
||||
private LatLng[] likelyPlaceLatLngs;
|
||||
|
||||
// [START maps_current_place_on_create]
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// [START_EXCLUDE silent]
|
||||
// [START maps_current_place_on_create_save_instance_state]
|
||||
// Retrieve location and camera position from saved instance state.
|
||||
if (savedInstanceState != null) {
|
||||
mLastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION);
|
||||
mCameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
|
||||
lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION);
|
||||
cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
|
||||
}
|
||||
// [END maps_current_place_on_create_save_instance_state]
|
||||
// [END_EXCLUDE]
|
||||
|
||||
// Retrieve the content view that renders the map.
|
||||
setContentView(R.layout.activity_maps);
|
||||
|
||||
// [START_EXCLUDE silent]
|
||||
// Construct a PlacesClient
|
||||
Places.initialize(getApplicationContext(), getString(R.string.google_maps_key));
|
||||
mPlacesClient = Places.createClient(this);
|
||||
placesClient = Places.createClient(this);
|
||||
|
||||
// Construct a FusedLocationProviderClient.
|
||||
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
|
||||
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
|
||||
|
||||
// Build the map.
|
||||
// [START maps_current_place_map_fragment]
|
||||
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.map);
|
||||
mapFragment.getMapAsync(this);
|
||||
|
||||
// [END maps_current_place_map_fragment]
|
||||
// [END_EXCLUDE]
|
||||
}
|
||||
// [END maps_current_place_on_create]
|
||||
|
||||
/**
|
||||
* Saves the state of the map when the activity is paused.
|
||||
*/
|
||||
// [START maps_current_place_on_save_instance_state]
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
if (mMap != null) {
|
||||
outState.putParcelable(KEY_CAMERA_POSITION, mMap.getCameraPosition());
|
||||
outState.putParcelable(KEY_LOCATION, mLastKnownLocation);
|
||||
super.onSaveInstanceState(outState);
|
||||
if (map != null) {
|
||||
outState.putParcelable(KEY_CAMERA_POSITION, map.getCameraPosition());
|
||||
outState.putParcelable(KEY_LOCATION, lastKnownLocation);
|
||||
}
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
// [END maps_current_place_on_save_instance_state]
|
||||
|
||||
/**
|
||||
* Sets up the options menu.
|
||||
@ -148,6 +161,7 @@ public class MapsActivityCurrentPlace extends AppCompatActivity
|
||||
* @param item The menu item to handle.
|
||||
* @return Boolean.
|
||||
*/
|
||||
// [START maps_current_place_on_options_item_selected]
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.option_get_place) {
|
||||
@ -155,18 +169,22 @@ public class MapsActivityCurrentPlace extends AppCompatActivity
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// [END maps_current_place_on_options_item_selected]
|
||||
|
||||
/**
|
||||
* Manipulates the map when it's available.
|
||||
* This callback is triggered when the map is ready to be used.
|
||||
*/
|
||||
// [START maps_current_place_on_map_ready]
|
||||
@Override
|
||||
public void onMapReady(GoogleMap map) {
|
||||
mMap = map;
|
||||
this.map = map;
|
||||
|
||||
// [START_EXCLUDE]
|
||||
// [START map_current_place_set_info_window_adapter]
|
||||
// Use a custom info window adapter to handle multiple lines of text in the
|
||||
// info window contents.
|
||||
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
|
||||
this.map.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
|
||||
|
||||
@Override
|
||||
// Return null here, so that getInfoContents() is called next.
|
||||
@ -189,9 +207,11 @@ public class MapsActivityCurrentPlace extends AppCompatActivity
|
||||
return infoWindow;
|
||||
}
|
||||
});
|
||||
// [END map_current_place_set_info_window_adapter]
|
||||
|
||||
// Prompt the user for permission.
|
||||
getLocationPermission();
|
||||
// [END_EXCLUDE]
|
||||
|
||||
// Turn on the My Location layer and the related control on the map.
|
||||
updateLocationUI();
|
||||
@ -199,48 +219,51 @@ public class MapsActivityCurrentPlace extends AppCompatActivity
|
||||
// Get the current location of the device and set the position of the map.
|
||||
getDeviceLocation();
|
||||
}
|
||||
// [END maps_current_place_on_map_ready]
|
||||
|
||||
/**
|
||||
* Gets the current location of the device, and positions the map's camera.
|
||||
*/
|
||||
// [START maps_current_place_get_device_location]
|
||||
private void getDeviceLocation() {
|
||||
/*
|
||||
* Get the best and most recent location of the device, which may be null in rare
|
||||
* cases when a location is not available.
|
||||
*/
|
||||
try {
|
||||
if (mLocationPermissionGranted) {
|
||||
Task<Location> locationResult = mFusedLocationProviderClient.getLastLocation();
|
||||
if (locationPermissionGranted) {
|
||||
Task<Location> locationResult = fusedLocationProviderClient.getLastLocation();
|
||||
locationResult.addOnCompleteListener(this, new OnCompleteListener<Location>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Location> task) {
|
||||
if (task.isSuccessful()) {
|
||||
// Set the map's camera position to the current location of the device.
|
||||
mLastKnownLocation = task.getResult();
|
||||
if (mLastKnownLocation != null) {
|
||||
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
|
||||
new LatLng(mLastKnownLocation.getLatitude(),
|
||||
mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
|
||||
lastKnownLocation = task.getResult();
|
||||
if (lastKnownLocation != null) {
|
||||
map.moveCamera(CameraUpdateFactory.newLatLngZoom(
|
||||
new LatLng(lastKnownLocation.getLatitude(),
|
||||
lastKnownLocation.getLongitude()), DEFAULT_ZOOM));
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Current location is null. Using defaults.");
|
||||
Log.e(TAG, "Exception: %s", task.getException());
|
||||
mMap.moveCamera(CameraUpdateFactory
|
||||
.newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
|
||||
mMap.getUiSettings().setMyLocationButtonEnabled(false);
|
||||
map.moveCamera(CameraUpdateFactory
|
||||
.newLatLngZoom(defaultLocation, DEFAULT_ZOOM));
|
||||
map.getUiSettings().setMyLocationButtonEnabled(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
Log.e("Exception: %s", e.getMessage());
|
||||
Log.e("Exception: %s", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// [END maps_current_place_get_device_location]
|
||||
|
||||
/**
|
||||
* Prompts the user for permission to use the device location.
|
||||
*/
|
||||
// [START maps_current_place_location_permission]
|
||||
private void getLocationPermission() {
|
||||
/*
|
||||
* Request location permission, so that we can get the location of the
|
||||
@ -250,44 +273,48 @@ public class MapsActivityCurrentPlace extends AppCompatActivity
|
||||
if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
|
||||
android.Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
mLocationPermissionGranted = true;
|
||||
locationPermissionGranted = true;
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
|
||||
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
|
||||
}
|
||||
}
|
||||
// [END maps_current_place_location_permission]
|
||||
|
||||
/**
|
||||
* Handles the result of the request for location permissions.
|
||||
*/
|
||||
// [START maps_current_place_on_request_permissions_result]
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
@NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
mLocationPermissionGranted = false;
|
||||
locationPermissionGranted = false;
|
||||
switch (requestCode) {
|
||||
case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
mLocationPermissionGranted = true;
|
||||
locationPermissionGranted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
updateLocationUI();
|
||||
}
|
||||
// [END maps_current_place_on_request_permissions_result]
|
||||
|
||||
/**
|
||||
* Prompts the user to select the current place from a list of likely places, and shows the
|
||||
* current place on the map - provided the user has granted location permission.
|
||||
*/
|
||||
// [START maps_current_place_show_current_place]
|
||||
private void showCurrentPlace() {
|
||||
if (mMap == null) {
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mLocationPermissionGranted) {
|
||||
if (locationPermissionGranted) {
|
||||
// Use fields to define the data types to return.
|
||||
List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS,
|
||||
Place.Field.LAT_LNG);
|
||||
@ -300,7 +327,7 @@ public class MapsActivityCurrentPlace extends AppCompatActivity
|
||||
// are the best match for the device's current location.
|
||||
@SuppressWarnings("MissingPermission") final
|
||||
Task<FindCurrentPlaceResponse> placeResult =
|
||||
mPlacesClient.findCurrentPlace(request);
|
||||
placesClient.findCurrentPlace(request);
|
||||
placeResult.addOnCompleteListener (new OnCompleteListener<FindCurrentPlaceResponse>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
|
||||
@ -316,18 +343,18 @@ public class MapsActivityCurrentPlace extends AppCompatActivity
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
mLikelyPlaceNames = new String[count];
|
||||
mLikelyPlaceAddresses = new String[count];
|
||||
mLikelyPlaceAttributions = new List[count];
|
||||
mLikelyPlaceLatLngs = new LatLng[count];
|
||||
likelyPlaceNames = new String[count];
|
||||
likelyPlaceAddresses = new String[count];
|
||||
likelyPlaceAttributions = new List[count];
|
||||
likelyPlaceLatLngs = new LatLng[count];
|
||||
|
||||
for (PlaceLikelihood placeLikelihood : likelyPlaces.getPlaceLikelihoods()) {
|
||||
// Build a list of likely places to show the user.
|
||||
mLikelyPlaceNames[i] = placeLikelihood.getPlace().getName();
|
||||
mLikelyPlaceAddresses[i] = placeLikelihood.getPlace().getAddress();
|
||||
mLikelyPlaceAttributions[i] = placeLikelihood.getPlace()
|
||||
likelyPlaceNames[i] = placeLikelihood.getPlace().getName();
|
||||
likelyPlaceAddresses[i] = placeLikelihood.getPlace().getAddress();
|
||||
likelyPlaceAttributions[i] = placeLikelihood.getPlace()
|
||||
.getAttributions();
|
||||
mLikelyPlaceLatLngs[i] = placeLikelihood.getPlace().getLatLng();
|
||||
likelyPlaceLatLngs[i] = placeLikelihood.getPlace().getLatLng();
|
||||
|
||||
i++;
|
||||
if (i > (count - 1)) {
|
||||
@ -349,40 +376,42 @@ public class MapsActivityCurrentPlace extends AppCompatActivity
|
||||
Log.i(TAG, "The user did not grant location permission.");
|
||||
|
||||
// Add a default marker, because the user hasn't selected a place.
|
||||
mMap.addMarker(new MarkerOptions()
|
||||
map.addMarker(new MarkerOptions()
|
||||
.title(getString(R.string.default_info_title))
|
||||
.position(mDefaultLocation)
|
||||
.position(defaultLocation)
|
||||
.snippet(getString(R.string.default_info_snippet)));
|
||||
|
||||
// Prompt the user for permission.
|
||||
getLocationPermission();
|
||||
}
|
||||
}
|
||||
// [END maps_current_place_show_current_place]
|
||||
|
||||
/**
|
||||
* Displays a form allowing the user to select a place from a list of likely places.
|
||||
*/
|
||||
// [START maps_current_place_open_places_dialog]
|
||||
private void openPlacesDialog() {
|
||||
// Ask the user to choose the place where they are now.
|
||||
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// The "which" argument contains the position of the selected item.
|
||||
LatLng markerLatLng = mLikelyPlaceLatLngs[which];
|
||||
String markerSnippet = mLikelyPlaceAddresses[which];
|
||||
if (mLikelyPlaceAttributions[which] != null) {
|
||||
markerSnippet = markerSnippet + "\n" + mLikelyPlaceAttributions[which];
|
||||
LatLng markerLatLng = likelyPlaceLatLngs[which];
|
||||
String markerSnippet = likelyPlaceAddresses[which];
|
||||
if (likelyPlaceAttributions[which] != null) {
|
||||
markerSnippet = markerSnippet + "\n" + likelyPlaceAttributions[which];
|
||||
}
|
||||
|
||||
// Add a marker for the selected place, with an info window
|
||||
// showing information about that place.
|
||||
mMap.addMarker(new MarkerOptions()
|
||||
.title(mLikelyPlaceNames[which])
|
||||
map.addMarker(new MarkerOptions()
|
||||
.title(likelyPlaceNames[which])
|
||||
.position(markerLatLng)
|
||||
.snippet(markerSnippet));
|
||||
|
||||
// Position the map's camera at the location of the marker.
|
||||
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(markerLatLng,
|
||||
map.moveCamera(CameraUpdateFactory.newLatLngZoom(markerLatLng,
|
||||
DEFAULT_ZOOM));
|
||||
}
|
||||
};
|
||||
@ -390,29 +419,32 @@ public class MapsActivityCurrentPlace extends AppCompatActivity
|
||||
// Display the dialog.
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.pick_place)
|
||||
.setItems(mLikelyPlaceNames, listener)
|
||||
.setItems(likelyPlaceNames, listener)
|
||||
.show();
|
||||
}
|
||||
// [END maps_current_place_open_places_dialog]
|
||||
|
||||
/**
|
||||
* Updates the map's UI settings based on whether the user has granted location permission.
|
||||
*/
|
||||
// [START maps_current_place_update_location_ui]
|
||||
private void updateLocationUI() {
|
||||
if (mMap == null) {
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (mLocationPermissionGranted) {
|
||||
mMap.setMyLocationEnabled(true);
|
||||
mMap.getUiSettings().setMyLocationButtonEnabled(true);
|
||||
if (locationPermissionGranted) {
|
||||
map.setMyLocationEnabled(true);
|
||||
map.getUiSettings().setMyLocationButtonEnabled(true);
|
||||
} else {
|
||||
mMap.setMyLocationEnabled(false);
|
||||
mMap.getUiSettings().setMyLocationButtonEnabled(false);
|
||||
mLastKnownLocation = null;
|
||||
map.setMyLocationEnabled(false);
|
||||
map.getUiSettings().setMyLocationButtonEnabled(false);
|
||||
lastKnownLocation = null;
|
||||
getLocationPermission();
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
Log.e("Exception: %s", e.getMessage());
|
||||
}
|
||||
}
|
||||
// [END maps_current_place_update_location_ui]
|
||||
}
|
||||
|
||||
9
tutorials/kotlin/CurrentPlaceDetailsOnMap/.gitignore
vendored
Normal file
9
tutorials/kotlin/CurrentPlaceDetailsOnMap/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
46
tutorials/kotlin/CurrentPlaceDetailsOnMap/README.md
Normal file
46
tutorials/kotlin/CurrentPlaceDetailsOnMap/README.md
Normal file
@ -0,0 +1,46 @@
|
||||
Google Maps Android API Sample: Current Place Details
|
||||
=====================================================
|
||||
|
||||
This sample goes hand in hand with a tutorial for the Google Maps Android API:
|
||||
[Select Current Place and Show Details on a Map](https://developers.google.com/maps/documentation/android-api/current-place-tutorial).
|
||||
|
||||
Prerequisites
|
||||
--------------
|
||||
|
||||
- Android SDK v24
|
||||
- Latest Android Build Tools
|
||||
- Android Support Repository
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
This sample uses the Gradle build system.
|
||||
|
||||
1. Download the samples by cloning this repository or downloading an archived
|
||||
snapshot. (See the options at the top of the page.)
|
||||
1. In Android Studio, create a new project and choose the "Import non-Android Studio project" or
|
||||
"Import Project" option.
|
||||
1. Select the `CurrentPlaceDetailsOnMap` directory that you downloaded with this repository.
|
||||
1. If prompted for a gradle configuration, accept the default settings.
|
||||
Alternatively use the "gradlew build" command to build the project directly.
|
||||
1. Add your API key to your app's `gradle.properties` file.
|
||||
(For information on getting an API key, see the
|
||||
[documentation](https://developers.google.com/maps/documentation/android-api/signup).)
|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Please refer to the [LICENSE](https://github.com/googlemaps/android-samples/blob/master/LICENSE) at the root of this repo.
|
||||
1
tutorials/kotlin/CurrentPlaceDetailsOnMap/app/.gitignore
vendored
Normal file
1
tutorials/kotlin/CurrentPlaceDetailsOnMap/app/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
||||
40
tutorials/kotlin/CurrentPlaceDetailsOnMap/app/build.gradle
Normal file
40
tutorials/kotlin/CurrentPlaceDetailsOnMap/app/build.gradle
Normal file
@ -0,0 +1,40 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion '28.0.3'
|
||||
defaultConfig {
|
||||
applicationId "com.example.currentplacedetailsonmap"
|
||||
minSdkVersion 17
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
resValue "string", "google_maps_key", (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.2', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'com.google.android.gms:play-services-maps:17.0.0'
|
||||
implementation 'com.google.android.libraries.places:places:2.2.0'
|
||||
testImplementation'junit:junit:4.13'
|
||||
implementation "androidx.core:core-ktx:1.2.0"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
28
tutorials/kotlin/CurrentPlaceDetailsOnMap/app/proguard-rules.pro
vendored
Normal file
28
tutorials/kotlin/CurrentPlaceDetailsOnMap/app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
#
|
||||
# Proguard config for a Google Maps Android API sample project.
|
||||
#
|
||||
# This file only contains the proguard options required by the Google Maps
|
||||
# Android API v2. You should use these settings in addition to those provided by the
|
||||
# Android SDK (<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 Android 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 Android 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();
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.currentplacedetailsonmap">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
<!--
|
||||
The API key for Google Maps-based APIs.
|
||||
-->
|
||||
<meta-data
|
||||
android:name="com.google.android.geo.API_KEY"
|
||||
android:value="@string/google_maps_key" />
|
||||
|
||||
<activity
|
||||
android:name="com.example.currentplacedetailsonmap.MapsActivityCurrentPlace"
|
||||
android:label="@string/title_activity_maps">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -0,0 +1,411 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package com.example.currentplacedetailsonmap
|
||||
|
||||
import android.Manifest
|
||||
import android.content.DialogInterface
|
||||
import android.content.pm.PackageManager
|
||||
import android.location.Location
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.gms.location.FusedLocationProviderClient
|
||||
import com.google.android.gms.location.LocationServices
|
||||
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.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.Marker
|
||||
import com.google.android.gms.maps.model.MarkerOptions
|
||||
import com.google.android.libraries.places.api.Places
|
||||
import com.google.android.libraries.places.api.model.Place
|
||||
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest
|
||||
import com.google.android.libraries.places.api.net.PlacesClient
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* An activity that displays a map showing the place at the device's current location.
|
||||
*/
|
||||
class MapsActivityCurrentPlace : AppCompatActivity(), OnMapReadyCallback {
|
||||
private var map: GoogleMap? = null
|
||||
private var cameraPosition: CameraPosition? = null
|
||||
|
||||
// The entry point to the Places API.
|
||||
private lateinit var placesClient: PlacesClient
|
||||
|
||||
// The entry point to the Fused Location Provider.
|
||||
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
|
||||
|
||||
// A default location (Sydney, Australia) and default zoom to use when location permission is
|
||||
// not granted.
|
||||
private val defaultLocation = LatLng(-33.8523341, 151.2106085)
|
||||
private var locationPermissionGranted = false
|
||||
|
||||
// The geographical location where the device is currently located. That is, the last-known
|
||||
// location retrieved by the Fused Location Provider.
|
||||
private var lastKnownLocation: Location? = null
|
||||
private var likelyPlaceNames: Array<String?> = arrayOfNulls(0)
|
||||
private var likelyPlaceAddresses: Array<String?> = arrayOfNulls(0)
|
||||
private var likelyPlaceAttributions: Array<List<*>?> = arrayOfNulls(0)
|
||||
private var likelyPlaceLatLngs: Array<LatLng?> = arrayOfNulls(0)
|
||||
|
||||
// [START maps_current_place_on_create]
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// [START_EXCLUDE silent]
|
||||
// Retrieve location and camera position from saved instance state.
|
||||
// [START maps_current_place_on_create_save_instance_state]
|
||||
if (savedInstanceState != null) {
|
||||
lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION)
|
||||
cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION)
|
||||
}
|
||||
// [END maps_current_place_on_create_save_instance_state]
|
||||
// [END_EXCLUDE]
|
||||
|
||||
// Retrieve the content view that renders the map.
|
||||
setContentView(R.layout.activity_maps)
|
||||
|
||||
// [START_EXCLUDE silent]
|
||||
// Construct a PlacesClient
|
||||
Places.initialize(applicationContext, getString(R.string.google_maps_key))
|
||||
placesClient = Places.createClient(this)
|
||||
|
||||
// Construct a FusedLocationProviderClient.
|
||||
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
|
||||
|
||||
// Build the map.
|
||||
// [START maps_current_place_map_fragment]
|
||||
val mapFragment = supportFragmentManager
|
||||
.findFragmentById(R.id.map) as SupportMapFragment?
|
||||
mapFragment?.getMapAsync(this)
|
||||
// [END maps_current_place_map_fragment]
|
||||
// [END_EXCLUDE]
|
||||
}
|
||||
// [END maps_current_place_on_create]
|
||||
|
||||
/**
|
||||
* Saves the state of the map when the activity is paused.
|
||||
*/
|
||||
// [START maps_current_place_on_save_instance_state]
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
if (map != null) {
|
||||
outState.putParcelable(KEY_CAMERA_POSITION, map!!.cameraPosition)
|
||||
outState.putParcelable(KEY_LOCATION, lastKnownLocation)
|
||||
}
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
// [END maps_current_place_on_save_instance_state]
|
||||
|
||||
/**
|
||||
* Sets up the options menu.
|
||||
* @param menu The options menu.
|
||||
* @return Boolean.
|
||||
*/
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.current_place_menu, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a click on the menu option to get a place.
|
||||
* @param item The menu item to handle.
|
||||
* @return Boolean.
|
||||
*/
|
||||
// [START maps_current_place_on_options_item_selected]
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == R.id.option_get_place) {
|
||||
showCurrentPlace()
|
||||
}
|
||||
return true
|
||||
}
|
||||
// [END maps_current_place_on_options_item_selected]
|
||||
|
||||
/**
|
||||
* Manipulates the map when it's available.
|
||||
* This callback is triggered when the map is ready to be used.
|
||||
*/
|
||||
// [START maps_current_place_on_map_ready]
|
||||
override fun onMapReady(map: GoogleMap) {
|
||||
this.map = map
|
||||
|
||||
// [START_EXCLUDE]
|
||||
// [START map_current_place_set_info_window_adapter]
|
||||
// Use a custom info window adapter to handle multiple lines of text in the
|
||||
// info window contents.
|
||||
this.map?.setInfoWindowAdapter(object : InfoWindowAdapter {
|
||||
// Return null here, so that getInfoContents() is called next.
|
||||
override fun getInfoWindow(arg0: Marker): View? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getInfoContents(marker: Marker): View {
|
||||
// Inflate the layouts for the info window, title and snippet.
|
||||
val infoWindow = layoutInflater.inflate(R.layout.custom_info_contents,
|
||||
findViewById<FrameLayout>(R.id.map), false)
|
||||
val title = infoWindow.findViewById<TextView>(R.id.title)
|
||||
title.text = marker.title
|
||||
val snippet = infoWindow.findViewById<TextView>(R.id.snippet)
|
||||
snippet.text = marker.snippet
|
||||
return infoWindow
|
||||
}
|
||||
})
|
||||
// [END map_current_place_set_info_window_adapter]
|
||||
|
||||
// Prompt the user for permission.
|
||||
getLocationPermission()
|
||||
// [END_EXCLUDE]
|
||||
|
||||
// Turn on the My Location layer and the related control on the map.
|
||||
updateLocationUI()
|
||||
|
||||
// Get the current location of the device and set the position of the map.
|
||||
getDeviceLocation()
|
||||
}
|
||||
// [END maps_current_place_on_map_ready]
|
||||
|
||||
/**
|
||||
* Gets the current location of the device, and positions the map's camera.
|
||||
*/
|
||||
// [START maps_current_place_get_device_location]
|
||||
private fun getDeviceLocation() {
|
||||
/*
|
||||
* Get the best and most recent location of the device, which may be null in rare
|
||||
* cases when a location is not available.
|
||||
*/
|
||||
try {
|
||||
if (locationPermissionGranted) {
|
||||
val locationResult = fusedLocationProviderClient.lastLocation
|
||||
locationResult.addOnCompleteListener(this) { task ->
|
||||
if (task.isSuccessful) {
|
||||
// Set the map's camera position to the current location of the device.
|
||||
lastKnownLocation = task.result
|
||||
if (lastKnownLocation != null) {
|
||||
map!!.moveCamera(CameraUpdateFactory.newLatLngZoom(
|
||||
LatLng(lastKnownLocation!!.latitude,
|
||||
lastKnownLocation!!.longitude), DEFAULT_ZOOM.toFloat()))
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Current location is null. Using defaults.")
|
||||
Log.e(TAG, "Exception: %s", task.exception)
|
||||
map?.moveCamera(CameraUpdateFactory
|
||||
.newLatLngZoom(defaultLocation, DEFAULT_ZOOM.toFloat()))
|
||||
map?.uiSettings?.isMyLocationButtonEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: SecurityException) {
|
||||
Log.e("Exception: %s", e.message, e)
|
||||
}
|
||||
}
|
||||
// [END maps_current_place_get_device_location]
|
||||
|
||||
/**
|
||||
* Prompts the user for permission to use the device location.
|
||||
*/
|
||||
// [START maps_current_place_location_permission]
|
||||
private fun getLocationPermission() {
|
||||
/*
|
||||
* Request location permission, so that we can get the location of the
|
||||
* device. The result of the permission request is handled by a callback,
|
||||
* onRequestPermissionsResult.
|
||||
*/
|
||||
if (ContextCompat.checkSelfPermission(this.applicationContext,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
locationPermissionGranted = true
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
|
||||
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION)
|
||||
}
|
||||
}
|
||||
// [END maps_current_place_location_permission]
|
||||
|
||||
/**
|
||||
* Handles the result of the request for location permissions.
|
||||
*/
|
||||
// [START maps_current_place_on_request_permissions_result]
|
||||
override fun onRequestPermissionsResult(requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray) {
|
||||
locationPermissionGranted = false
|
||||
when (requestCode) {
|
||||
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION -> {
|
||||
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.isNotEmpty() &&
|
||||
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
locationPermissionGranted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
updateLocationUI()
|
||||
}
|
||||
// [END maps_current_place_on_request_permissions_result]
|
||||
|
||||
/**
|
||||
* Prompts the user to select the current place from a list of likely places, and shows the
|
||||
* current place on the map - provided the user has granted location permission.
|
||||
*/
|
||||
// [START maps_current_place_show_current_place]
|
||||
private fun showCurrentPlace() {
|
||||
if (map == null) {
|
||||
return
|
||||
}
|
||||
if (locationPermissionGranted) {
|
||||
// Use fields to define the data types to return.
|
||||
val placeFields = listOf(Place.Field.NAME, Place.Field.ADDRESS, Place.Field.LAT_LNG)
|
||||
|
||||
// Use the builder to create a FindCurrentPlaceRequest.
|
||||
val request = FindCurrentPlaceRequest.newInstance(placeFields)
|
||||
|
||||
// Get the likely places - that is, the businesses and other points of interest that
|
||||
// are the best match for the device's current location.
|
||||
val placeResult = placesClient.findCurrentPlace(request)
|
||||
placeResult.addOnCompleteListener { task ->
|
||||
if (task.isSuccessful && task.result != null) {
|
||||
val likelyPlaces = task.result
|
||||
|
||||
// Set the count, handling cases where less than 5 entries are returned.
|
||||
val count = if (likelyPlaces != null && likelyPlaces.placeLikelihoods.size < M_MAX_ENTRIES) {
|
||||
likelyPlaces.placeLikelihoods.size
|
||||
} else {
|
||||
M_MAX_ENTRIES
|
||||
}
|
||||
var i = 0
|
||||
likelyPlaceNames = arrayOfNulls(count)
|
||||
likelyPlaceAddresses = arrayOfNulls(count)
|
||||
likelyPlaceAttributions = arrayOfNulls<List<*>?>(count)
|
||||
likelyPlaceLatLngs = arrayOfNulls(count)
|
||||
for (placeLikelihood in likelyPlaces?.placeLikelihoods ?: emptyList()) {
|
||||
// Build a list of likely places to show the user.
|
||||
likelyPlaceNames[i] = placeLikelihood.place.name
|
||||
likelyPlaceAddresses[i] = placeLikelihood.place.address
|
||||
likelyPlaceAttributions[i] = placeLikelihood.place.attributions
|
||||
likelyPlaceLatLngs[i] = placeLikelihood.place.latLng
|
||||
i++
|
||||
if (i > count - 1) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Show a dialog offering the user the list of likely places, and add a
|
||||
// marker at the selected place.
|
||||
openPlacesDialog()
|
||||
} else {
|
||||
Log.e(TAG, "Exception: %s", task.exception)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The user has not granted permission.
|
||||
Log.i(TAG, "The user did not grant location permission.")
|
||||
|
||||
// Add a default marker, because the user hasn't selected a place.
|
||||
map!!.addMarker(MarkerOptions()
|
||||
.title(getString(R.string.default_info_title))
|
||||
.position(defaultLocation)
|
||||
.snippet(getString(R.string.default_info_snippet)))
|
||||
|
||||
// Prompt the user for permission.
|
||||
getLocationPermission()
|
||||
}
|
||||
}
|
||||
// [END maps_current_place_show_current_place]
|
||||
|
||||
/**
|
||||
* Displays a form allowing the user to select a place from a list of likely places.
|
||||
*/
|
||||
// [START maps_current_place_open_places_dialog]
|
||||
private fun openPlacesDialog() {
|
||||
// Ask the user to choose the place where they are now.
|
||||
val listener = DialogInterface.OnClickListener { dialog, which -> // The "which" argument contains the position of the selected item.
|
||||
val markerLatLng = likelyPlaceLatLngs[which]
|
||||
var markerSnippet = likelyPlaceAddresses[which]
|
||||
if (likelyPlaceAttributions[which] != null) {
|
||||
markerSnippet = """
|
||||
$markerSnippet
|
||||
${likelyPlaceAttributions[which]}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
// Add a marker for the selected place, with an info window
|
||||
// showing information about that place.
|
||||
map!!.addMarker(MarkerOptions()
|
||||
.title(likelyPlaceNames[which])
|
||||
.position(markerLatLng!!)
|
||||
.snippet(markerSnippet))
|
||||
|
||||
// Position the map's camera at the location of the marker.
|
||||
map!!.moveCamera(CameraUpdateFactory.newLatLngZoom(markerLatLng,
|
||||
DEFAULT_ZOOM.toFloat()))
|
||||
}
|
||||
|
||||
// Display the dialog.
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(R.string.pick_place)
|
||||
.setItems(likelyPlaceNames, listener)
|
||||
.show()
|
||||
}
|
||||
// [END maps_current_place_open_places_dialog]
|
||||
|
||||
/**
|
||||
* Updates the map's UI settings based on whether the user has granted location permission.
|
||||
*/
|
||||
// [START maps_current_place_update_location_ui]
|
||||
private fun updateLocationUI() {
|
||||
if (map == null) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
if (locationPermissionGranted) {
|
||||
map!!.isMyLocationEnabled = true
|
||||
map!!.uiSettings.isMyLocationButtonEnabled = true
|
||||
} else {
|
||||
map!!.isMyLocationEnabled = false
|
||||
map!!.uiSettings.isMyLocationButtonEnabled = false
|
||||
lastKnownLocation = null
|
||||
getLocationPermission()
|
||||
}
|
||||
} catch (e: SecurityException) {
|
||||
Log.e("Exception: %s", e.message, e)
|
||||
}
|
||||
}
|
||||
// [END maps_current_place_update_location_ui]
|
||||
|
||||
companion object {
|
||||
private val TAG = MapsActivityCurrentPlace::class.java.simpleName
|
||||
private const val DEFAULT_ZOOM = 15
|
||||
private const val PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1
|
||||
|
||||
// Keys for storing activity state.
|
||||
// [START maps_current_place_state_keys]
|
||||
private const val KEY_CAMERA_POSITION = "camera_position"
|
||||
private const val KEY_LOCATION = "location"
|
||||
// [END maps_current_place_state_keys]
|
||||
|
||||
// Used for selecting the current place.
|
||||
private const val M_MAX_ENTRIES = 5
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/map"
|
||||
android:name="com.google.android.gms.maps.SupportMapFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.example.currentplacedetailsonmap.MapsActivityCurrentPlace" />
|
||||
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layoutDirection="locale"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:textColor="#ff000000"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/snippet"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#ff7f7f7f" />
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Copyright (C) 2016 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.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/option_get_place"
|
||||
android:title="@string/option_get_place"
|
||||
app:showAsAction="always"/>
|
||||
</menu>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
</resources>
|
||||
@ -0,0 +1,8 @@
|
||||
<resources>
|
||||
<string name="app_name">Current Place Details</string>
|
||||
<string name="title_activity_maps">Current Place Details</string>
|
||||
<string name="default_info_title">Default Location</string>
|
||||
<string name="default_info_snippet">No places found, because location permission is disabled.</string>
|
||||
<string name="option_get_place">Get place</string>
|
||||
<string name="pick_place">Choose a place</string>
|
||||
</resources>
|
||||
@ -0,0 +1,11 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
29
tutorials/kotlin/CurrentPlaceDetailsOnMap/build.gradle
Normal file
29
tutorials/kotlin/CurrentPlaceDetailsOnMap/build.gradle
Normal file
@ -0,0 +1,29 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.72'
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://maven.google.com'
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
24
tutorials/kotlin/CurrentPlaceDetailsOnMap/gradle.properties
Normal file
24
tutorials/kotlin/CurrentPlaceDetailsOnMap/gradle.properties
Normal file
@ -0,0 +1,24 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
# Replace the value below with your own Google API key for Android app.
|
||||
# To learn how to get a Google Maps Platform API key, visit:
|
||||
# https://developers.google.com/maps/gmp-get-started
|
||||
GOOGLE_MAPS_API_KEY=YOUR_API_KEY
|
||||
BIN
tutorials/kotlin/CurrentPlaceDetailsOnMap/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
tutorials/kotlin/CurrentPlaceDetailsOnMap/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
tutorials/kotlin/CurrentPlaceDetailsOnMap/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
tutorials/kotlin/CurrentPlaceDetailsOnMap/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
#Wed Apr 15 11:26:52 PDT 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||
160
tutorials/kotlin/CurrentPlaceDetailsOnMap/gradlew
vendored
Executable file
160
tutorials/kotlin/CurrentPlaceDetailsOnMap/gradlew
vendored
Executable file
@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
90
tutorials/kotlin/CurrentPlaceDetailsOnMap/gradlew.bat
vendored
Normal file
90
tutorials/kotlin/CurrentPlaceDetailsOnMap/gradlew.bat
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@ -0,0 +1 @@
|
||||
include ':app'
|
||||
Loading…
x
Reference in New Issue
Block a user