update: change code to dismiss the "deprecation or unused" warning messages
add: set 6sec to timeout for getMyLocation()
MODIFY
plugin.xml
plugin.xml
<?xml version='1.0' encoding='utf-8'?>
-<plugin id="cordova-plugin-googlemaps" version="2.2.0-beta-20180117-2320" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
+<plugin id="cordova-plugin-googlemaps" version="2.2.0-beta-20180118-1456" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
<name>cordova-plugin-googlemaps</name>
<js-module name="BaseClass" src="www/BaseClass.js">
<runs />

MODIFY
src/android/plugin/google/maps/PluginGeolocation.java
src/android/plugin/google/maps/PluginGeolocation.java
@@ -10,6 +10,7 @@ import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.util.Log;
@@ -20,8 +21,10 @@ import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
+import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
+import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
@@ -36,6 +39,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -55,6 +59,7 @@ public class PluginGeolocation extends CordovaPlugin {
super.initialize(cordova, webView);
activity = cordova.getActivity();
}
+ private static Location lastLocation = null;
@Override
@@ -111,6 +116,23 @@ public class PluginGeolocation extends CordovaPlugin {
return;
}
}
+ if (Calendar.getInstance().getTimeInMillis() - lastLocation.getTime() <= 2000) {
+ //---------------------------------------------------------------------
+ // If the user requests the location in two seconds from the last time,
+ // return the last result in order to save battery usage.
+ // (Don't request the device location too much! Save battery usage!)
+ //---------------------------------------------------------------------
+ JSONObject result;
+ try {
+ result = PluginUtil.location2Json(lastLocation);
+ result.put("status", true);
+ callbackContext.success(result);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ return;
+ }
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(activity)
@@ -279,50 +301,32 @@ public class PluginGeolocation extends CordovaPlugin {
}
LocationRequest locationRequest= LocationRequest.create()
- .setExpirationTime(5000)
+ //.setExpirationTime(5000)
+ .setFastestInterval(1000)
.setNumUpdates(2)
.setSmallestDisplacement(0)
.setPriority(priority)
- .setInterval(5000);
-
+ .setMaxWaitTime(6000)
+ .setInterval(3000);
- final PendingResult<Status> result = LocationServices.FusedLocationApi.requestLocationUpdates(
- googleApiClient, locationRequest, new LocationListener() {
+ LocationServices.getFusedLocationProviderClient(cordova.getActivity())
+ .requestLocationUpdates(locationRequest, new LocationCallback() {
@Override
- public void onLocationChanged(Location location) {
- /*
- if (callbackContext.isFinished()) {
- return;
- }
- */
- JSONObject result;
- try {
- result = PluginUtil.location2Json(location);
- result.put("status", true);
- callbackContext.success(result);
- } catch (JSONException e) {
- e.printStackTrace();
+ public void onLocationResult(LocationResult locationResult) {
+ Location location = null;
+ if (locationResult.getLocations().size() > 0) {
+ location = locationResult.getLocations().get(0);
+ lastLocation = location;
+ } else if (locationResult.getLastLocation() != null) {
+ location = locationResult.getLastLocation();
}
- googleApiClient.disconnect();
- }
-
- });
-
- result.setResultCallback(new ResultCallback<Status>() {
-
- public void onResult(Status status) {
- if (!status.isSuccess()) {
- String errorMsg = status.getStatusMessage();
- PluginResult result = new PluginResult(PluginResult.Status.ERROR, errorMsg);
- callbackContext.sendPluginResult(result);
- } else {
- // no update location
- Location location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
+ Log.d(TAG, "===> location =" + location);
if (location != null) {
+ JSONObject result;
try {
- JSONObject result = PluginUtil.location2Json(location);
+ result = PluginUtil.location2Json(location);
result.put("status", true);
callbackContext.success(result);
} catch (JSONException e) {
@@ -355,9 +359,11 @@ public class PluginGeolocation extends CordovaPlugin {
callbackContext.error(result);
}
}
+
+ googleApiClient.disconnect();
}
- }
- });
+ }, Looper.myLooper());
+
}
private void _onActivityResultLocationPage(Bundle bundle) {

MODIFY
src/ios/GoogleMaps/CordovaGoogleMaps.m
src/ios/GoogleMaps/CordovaGoogleMaps.m
NSString *bundleName = [NSString stringWithFormat:@"%@", [info objectForKey:@"CFBundleDisplayName"]];
NSString *message = [NSString stringWithFormat:@"Please replace 'API_KEY_FOR_IOS' in the platforms/ios/%@/%@-Info.plist with your API Key!", bundleName, bundleName];
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"API key is not setted."
+ UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"API key is not setted."
message:message
- delegate:self
- cancelButtonTitle:@"CLOSE"
- otherButtonTitles:nil];
- [alert show];
+ preferredStyle:UIAlertControllerStyleAlert];
+
+ UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"CLOSE", @"CLOSE")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction* action)
+ {
+ [alert dismissViewControllerAnimated:YES completion:nil];
+ }];
+
+ [alert addAction:ok];
+
return;
}

MODIFY
src/ios/GoogleMaps/GoogleMapsViewController.m
src/ios/GoogleMaps/GoogleMapsViewController.m
}
// Calculate the size for the title strings
- textSize = [title sizeWithFont:titleFont constrainedToSize: CGSizeMake(mapView.frame.size.width - 13, mapView.frame.size.height - 13)];
+ CGRect textRect = [title boundingRectWithSize:CGSizeMake(mapView.frame.size.width - 13, mapView.frame.size.height - 13)
+ options:NSStringDrawingUsesLineFragmentOrigin
+ attributes:@{NSFontAttributeName:titleFont}
+ context:nil];
+ textSize = textRect.size;
rectSize = CGSizeMake(textSize.width + 10, textSize.height + 22);
// Calculate the size for the snippet strings
if (snippet) {
snippetFont = [UIFont systemFontOfSize:12.0f];
snippet = [snippet stringByReplacingOccurrencesOfString:@"\n" withString:@""];
- snippetSize = [snippet sizeWithFont:snippetFont constrainedToSize: CGSizeMake(mapView.frame.size.width - 13, mapView.frame.size.height - 13)];
+ textRect = [snippet boundingRectWithSize:CGSizeMake(mapView.frame.size.width - 13, mapView.frame.size.height - 13)
+ options:NSStringDrawingUsesLineFragmentOrigin
+ attributes:@{NSFontAttributeName:snippetFont}
+ context:nil];
+ snippetSize = textRect.size;
rectSize.height += snippetSize.height + 4;
if (rectSize.width < snippetSize.width + leftImg.size.width) {
rectSize.width = snippetSize.width + leftImg.size.width;

MODIFY
src/ios/GoogleMaps/PluginCircle.m
src/ios/GoogleMaps/PluginCircle.m
[self.mapCtrl.executeQueue addOperationWithBlock:^{
NSString *key = [command.arguments objectAtIndex:0];
- GMSCircle *circle = (GMSCircle *)[self.mapCtrl.objects objectForKey:key];
+ //GMSCircle *circle = (GMSCircle *)[self.mapCtrl.objects objectForKey:key];
Boolean isClickable = [[command.arguments objectAtIndex:1] boolValue];
// Update the property

MODIFY
src/ios/GoogleMaps/PluginGeolocation.m
src/ios/GoogleMaps/PluginGeolocation.m
- (void)pluginInitialize
{
self.locationCommandQueue = [[NSMutableArray alloc] init];
-
+ self.lastLocation = nil;
}
/**
// kCLAuthorizationStatusDenied
// kCLAuthorizationStatusRestricted
//----------------------------------------------------
- UIAlertView *alertView = [[UIAlertView alloc]
- initWithTitle:@"Location Services disabled"
+ UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Location Services disabled"
message:@"This app needs access to your location. Please turn on Location Services in your device settings."
- delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
- [alertView show];
+ preferredStyle:UIAlertControllerStyleAlert];
+ UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"CLOSE", @"CLOSE")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction* action)
+ {
NSString *error_code = @"service_denied";
NSString *error_message = @"This app has rejected to use Location Services.";
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:json];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+ [alert dismissViewControllerAnimated:YES completion:nil];
+ }];
+
+ [alert addAction:ok];
+
+
+
} else {
if (self.locationManager == nil) {
//http://stackoverflow.com/questions/24268070/ignore-ios8-code-in-xcode-5-compilation
[self.locationManager requestWhenInUseAuthorization];
+ NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
+
+ if (timeStamp - self.lastLocation.timestamp.timeIntervalSince1970 < 2000) {
+ //---------------------------------------------------------------------
+ // If the user requests the location in two seconds from the last time,
+ // return the last result in order to save battery usage.
+ // (Don't request the device location too much! Save battery usage!)
+ //---------------------------------------------------------------------
+ CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:self.lastResult];
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+ return;
+ }
+
+ if (self.locationCommandQueue.count == 0) {
+ // Executes getMyLocation() first time
+
+ [self.locationManager stopUpdatingLocation];
+ [NSTimer scheduledTimerWithTimeInterval:6000 repeats:NO block:^(NSTimer *timer) {
+ if (self.lastLocation != nil) {
+ return;
+ }
+
+ // Timeout
[self.locationManager stopUpdatingLocation];
+
+ NSMutableDictionary *json = [NSMutableDictionary dictionary];
+ [json setObject:[NSNumber numberWithBool:NO] forKey:@"status"];
+ NSString *error_code = @"error";
+ NSString *error_message = @"Cannot get your location.";
+ [json setObject:[NSString stringWithString:error_message] forKey:@"error_message"];
+ [json setObject:[NSString stringWithString:error_code] forKey:@"error_code"];
+
+ for (CDVInvokedUrlCommand *command in self.locationCommandQueue) {
+ CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:json];
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+ }
+ [self.locationCommandQueue removeAllObjects];
+ }];
[self.locationManager startUpdatingLocation];
+ }
[self.locationCommandQueue addObject:command];
//CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
+ self.lastLocation = self.locationManager.location;
+
NSMutableDictionary *latLng = [NSMutableDictionary dictionary];
[latLng setObject:[NSNumber numberWithFloat:self.locationManager.location.coordinate.latitude] forKey:@"lat"];
[latLng setObject:[NSNumber numberWithFloat:self.locationManager.location.coordinate.longitude] forKey:@"lng"];
[json setObject:[NSNumber numberWithFloat:[self.locationManager.location horizontalAccuracy]] forKey:@"accuracy"];
[json setObject:[NSNumber numberWithDouble:[self.locationManager.location.timestamp timeIntervalSince1970]] forKey:@"time"];
[json setObject:[NSNumber numberWithInteger:[self.locationManager.location hash]] forKey:@"hashCode"];
+ self.lastResult = json;
for (CDVInvokedUrlCommand *command in self.locationCommandQueue) {
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:json];
//self.locationManager = nil;
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
+ self.lastLocation = nil;
+ self.lastResult = nil;
+
NSMutableDictionary *json = [NSMutableDictionary dictionary];
[json setObject:[NSNumber numberWithBool:NO] forKey:@"status"];
NSString *error_code = @"error";
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:json];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
+ [self.locationCommandQueue removeAllObjects];
}

MODIFY
src/ios/GoogleMaps/PluginGroundOverlay.m
src/ios/GoogleMaps/PluginGroundOverlay.m
[self.mapCtrl.executeQueue addOperationWithBlock:^{
NSString *key = [command.arguments objectAtIndex:0];
- GMSGroundOverlay *groundOverlay = (GMSGroundOverlay *)[self.mapCtrl.objects objectForKey:key];
+ //GMSGroundOverlay *groundOverlay = (GMSGroundOverlay *)[self.mapCtrl.objects objectForKey:key];
Boolean isClickable = [[command.arguments objectAtIndex:1] boolValue];
// Update the property
}
-
- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock
{
[self.mapCtrl.executeQueue addOperationWithBlock:^{
}
+ //-------------------------------------------------------------
+ // Use NSURLSessionDataTask instead of [NSURLConnection sendAsynchronousRequest]
+ // https://stackoverflow.com/a/20871647
+ //-------------------------------------------------------------
+ NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
+ NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
+ NSURLSessionDataTask *getTask = [session dataTaskWithRequest:req
+ completionHandler:^(NSData *data, NSURLResponse *res, NSError *error) {
+ [session finishTasksAndInvalidate];
+
+ UIImage *image = [UIImage imageWithData:data];
+ if (image) {
+ completionBlock(YES, image);
+ return;
+ }
+
+ completionBlock(NO, nil);
+
+ }];
+ [getTask resume];
+ //-------------------------------------------------------------
+ // NSURLConnection sendAsynchronousRequest is deprecated.
+ //-------------------------------------------------------------
+ /*
[NSURLConnection sendAsynchronousRequest:req
queue:self.mapCtrl.executeQueue
completionHandler:^(NSURLResponse *res, NSData *data, NSError *error) {
if ( !error ) {
+ [self.icons setObject:data forKey:uniqueKey cost:data.length];
UIImage *image = [UIImage imageWithData:data];
completionBlock(YES, image);
} else {
}
}];
+ */
+
+
}];
}

MODIFY
src/ios/GoogleMaps/PluginPolygon.m
src/ios/GoogleMaps/PluginPolygon.m
NSString *polygonKey = [command.arguments objectAtIndex:0];
NSInteger holeIndex = [[command.arguments objectAtIndex:1] integerValue];
NSInteger pointIndex = [[command.arguments objectAtIndex:2] integerValue];
- GMSPolygon *polygon = (GMSPolygon *)[self.mapCtrl.objects objectForKey:polygonKey];
+ //GMSPolygon *polygon = (GMSPolygon *)[self.mapCtrl.objects objectForKey:polygonKey];
// Get properties
NSString *polygonKey = [command.arguments objectAtIndex:0];
NSInteger index = [[command.arguments objectAtIndex:1] integerValue];
- GMSPolygon *polygon = (GMSPolygon *)[self.mapCtrl.objects objectForKey:polygonKey];
+ //GMSPolygon *polygon = (GMSPolygon *)[self.mapCtrl.objects objectForKey:polygonKey];
// Get properties
NSString *propertyId = [polygonKey stringByReplacingOccurrencesOfString:@"polygon_" withString:@"polygon_property_"];
[self.mapCtrl.executeQueue addOperationWithBlock:^{
NSString *polygonKey = [command.arguments objectAtIndex:0];
- GMSPolygon *polygon = [self.mapCtrl.objects objectForKey:polygonKey];
+ //GMSPolygon *polygon = [self.mapCtrl.objects objectForKey:polygonKey];
Boolean isClickable = [[command.arguments objectAtIndex:1] boolValue];
// Get properties

- update: change code to dismiss the "deprecation or unused" warning messages
- add: set 6sec to timeout for getMyLocation() (#2005)