Skip to content

Commit

Permalink
feat(geolocation): Add new alias for coarse location (#684)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcesarmobile authored Nov 8, 2021
1 parent 64df932 commit 7563040
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 27 deletions.
39 changes: 28 additions & 11 deletions geolocation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const printCurrentPosition = async () => {
* [`watchPosition(...)`](#watchposition)
* [`clearWatch(...)`](#clearwatch)
* [`checkPermissions()`](#checkpermissions)
* [`requestPermissions()`](#requestpermissions)
* [`requestPermissions(...)`](#requestpermissions)
* [Interfaces](#interfaces)
* [Type Aliases](#type-aliases)

Expand Down Expand Up @@ -140,14 +140,18 @@ Check location permissions
--------------------


### requestPermissions()
### requestPermissions(...)

```typescript
requestPermissions() => Promise<PermissionStatus>
requestPermissions(permissions?: GeolocationPluginPermissions | undefined) => Promise<PermissionStatus>
```

Request location permissions

| Param | Type |
| ----------------- | ------------------------------------------------------------------------------------- |
| **`permissions`** | <code><a href="#geolocationpluginpermissions">GeolocationPluginPermissions</a></code> |

**Returns:** <code>Promise&lt;<a href="#permissionstatus">PermissionStatus</a>&gt;</code>

**Since:** 1.0.0
Expand All @@ -168,11 +172,11 @@ Request location permissions

#### PositionOptions

| Prop | Type | Description | Default | Since |
| ------------------------ | -------------------- | ------------------------------------------------------------------------------------------ | ------------------ | ----- |
| **`enableHighAccuracy`** | <code>boolean</code> | High accuracy mode (such as GPS, if available) | <code>false</code> | 1.0.0 |
| **`timeout`** | <code>number</code> | The maximum wait time in milliseconds for location updates | <code>10000</code> | 1.0.0 |
| **`maximumAge`** | <code>number</code> | The maximum age in milliseconds of a possible cached position that is acceptable to return | <code>0</code> | 1.0.0 |
| Prop | Type | Description | Default | Since |
| ------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- |
| **`enableHighAccuracy`** | <code>boolean</code> | High accuracy mode (such as GPS, if available) On Android 12+ devices it will be ignored if users didn't grant ACCESS_FINE_LOCATION permissions (can be checked with location alias). | <code>false</code> | 1.0.0 |
| **`timeout`** | <code>number</code> | The maximum wait time in milliseconds for location updates | <code>10000</code> | 1.0.0 |
| **`maximumAge`** | <code>number</code> | The maximum age in milliseconds of a possible cached position that is acceptable to return | <code>0</code> | 1.0.0 |


#### ClearWatchOptions
Expand All @@ -184,9 +188,17 @@ Request location permissions

#### PermissionStatus

| Prop | Type |
| -------------- | ----------------------------------------------------------- |
| **`location`** | <code><a href="#permissionstate">PermissionState</a></code> |
| Prop | Type | Description | Since |
| -------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- |
| **`location`** | <code><a href="#permissionstate">PermissionState</a></code> | Permission state for location alias. On Android it requests/checks both ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permissions. On iOS and web it requests/checks location permission. | 1.0.0 |
| **`coarseLocation`** | <code><a href="#permissionstate">PermissionState</a></code> | Permission state for coarseLocation alias. On Android it requests/checks ACCESS_COARSE_LOCATION. On Android 12+, users can choose between Approximate location (ACCESS_COARSE_LOCATION) or Precise location (ACCESS_FINE_LOCATION), so this alias can be used if the app doesn't need high accuracy. On iOS and web it will have the same value as location alias. | 1.2.0 |


#### GeolocationPluginPermissions

| Prop | Type |
| ----------------- | ---------------------------------------- |
| **`permissions`** | <code>GeolocationPermissionType[]</code> |


### Type Aliases
Expand All @@ -206,4 +218,9 @@ Request location permissions

<code>'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'</code>


#### GeolocationPermissionType

<code>'location' | 'coarseLocation'</code>

</docgen-api>
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,17 @@
@CapacitorPlugin(
name = "Geolocation",
permissions = {
@Permission(strings = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION }, alias = "location")
@Permission(
strings = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION },
alias = GeolocationPlugin.LOCATION
),
@Permission(strings = { Manifest.permission.ACCESS_COARSE_LOCATION }, alias = GeolocationPlugin.COARSE_LOCATION)
}
)
public class GeolocationPlugin extends Plugin {

static final String LOCATION = "location";
static final String COARSE_LOCATION = "coarseLocation";
private Geolocation implementation;
private Map<String, PluginCall> watchingCalls = new HashMap<>();

Expand All @@ -38,8 +44,9 @@ public void load() {
*/
@PluginMethod
public void getCurrentPosition(final PluginCall call) {
if (getPermissionState("location") != PermissionState.GRANTED) {
requestAllPermissions(call, "completeCurrentPosition");
String alias = getAlias(call);
if (getPermissionState(alias) != PermissionState.GRANTED) {
requestPermissionForAlias(alias, call, "completeCurrentPosition");
} else {
getPosition(call);
}
Expand All @@ -52,12 +59,11 @@ public void getCurrentPosition(final PluginCall call) {
*/
@PermissionCallback
private void completeCurrentPosition(PluginCall call) {
if (getPermissionState("location") == PermissionState.GRANTED) {
boolean enableHighAccuracy = call.getBoolean("enableHighAccuracy", false);
if (getPermissionState(GeolocationPlugin.COARSE_LOCATION) == PermissionState.GRANTED) {
int timeout = call.getInt("timeout", 10000);

implementation.sendLocation(
enableHighAccuracy,
isHighAccuracy(call),
timeout,
true,
new LocationResultCallback() {
Expand Down Expand Up @@ -86,8 +92,9 @@ public void error(String message) {
@PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
public void watchPosition(PluginCall call) {
call.setKeepAlive(true);
if (getPermissionState("location") != PermissionState.GRANTED) {
requestAllPermissions(call, "completeWatchPosition");
String alias = getAlias(call);
if (getPermissionState(alias) != PermissionState.GRANTED) {
requestPermissionForAlias(alias, call, "completeWatchPosition");
} else {
startWatch(call);
}
Expand All @@ -100,7 +107,7 @@ public void watchPosition(PluginCall call) {
*/
@PermissionCallback
private void completeWatchPosition(PluginCall call) {
if (getPermissionState("location") == PermissionState.GRANTED) {
if (getPermissionState(GeolocationPlugin.COARSE_LOCATION) == PermissionState.GRANTED) {
startWatch(call);
} else {
call.reject("Location permission was denied");
Expand All @@ -109,15 +116,14 @@ private void completeWatchPosition(PluginCall call) {

@SuppressWarnings("MissingPermission")
private void getPosition(PluginCall call) {
boolean enableHighAccuracy = call.getBoolean("enableHighAccuracy", false);
int timeout = call.getInt("timeout", 10000);
int maximumAge = call.getInt("maximumAge", 0);
Location location = implementation.getLastLocation(maximumAge);
if (location != null) {
call.resolve(getJSObjectForLocation(location));
} else {
implementation.sendLocation(
enableHighAccuracy,
isHighAccuracy(call),
timeout,
true,
new LocationResultCallback() {
Expand All @@ -137,11 +143,10 @@ public void error(String message) {

@SuppressWarnings("MissingPermission")
private void startWatch(final PluginCall call) {
boolean enableHighAccuracy = call.getBoolean("enableHighAccuracy", false);
int timeout = call.getInt("timeout", 10000);

implementation.requestLocationUpdates(
enableHighAccuracy,
isHighAccuracy(call),
timeout,
false,
new LocationResultCallback() {
Expand Down Expand Up @@ -202,4 +207,21 @@ private JSObject getJSObjectForLocation(Location location) {
coords.put("heading", location.getBearing());
return ret;
}

private String getAlias(PluginCall call) {
String alias = GeolocationPlugin.LOCATION;
// TODO replace with Build.VERSION_CODES.S once we target SDK 31
if (Build.VERSION.SDK_INT >= 31) {
boolean enableHighAccuracy = call.getBoolean("enableHighAccuracy", false);
if (!enableHighAccuracy) {
alias = GeolocationPlugin.COARSE_LOCATION;
}
}
return alias;
}

private boolean isHighAccuracy(PluginCall call) {
boolean enableHighAccuracy = call.getBoolean("enableHighAccuracy", false);
return enableHighAccuracy && getPermissionState(GeolocationPlugin.LOCATION) == PermissionState.GRANTED;
}
}
3 changes: 2 additions & 1 deletion geolocation/ios/Plugin/GeolocationPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ public class GeolocationPlugin: CAPPlugin, CLLocationManagerDelegate {
}

let result = [
"location": status
"location": status,
"coarseLocation": status
]

call.resolve(result)
Expand Down
38 changes: 37 additions & 1 deletion geolocation/src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,38 @@ import type { PermissionState } from '@capacitor/core';
export type CallbackID = string;

export interface PermissionStatus {
/**
* Permission state for location alias.
*
* On Android it requests/checks both ACCESS_COARSE_LOCATION and
* ACCESS_FINE_LOCATION permissions.
*
* On iOS and web it requests/checks location permission.
*
* @since 1.0.0
*/
location: PermissionState;

/**
* Permission state for coarseLocation alias.
*
* On Android it requests/checks ACCESS_COARSE_LOCATION.
*
* On Android 12+, users can choose between Approximate location (ACCESS_COARSE_LOCATION) or
* Precise location (ACCESS_FINE_LOCATION), so this alias can be used if the app doesn't
* need high accuracy.
*
* On iOS and web it will have the same value as location alias.
*
* @since 1.2.0
*/
coarseLocation: PermissionState;
}

export type GeolocationPermissionType = 'location' | 'coarseLocation';

export interface GeolocationPluginPermissions {
permissions: GeolocationPermissionType[];
}

export interface GeolocationPlugin {
Expand Down Expand Up @@ -44,7 +75,9 @@ export interface GeolocationPlugin {
*
* @since 1.0.0
*/
requestPermissions(): Promise<PermissionStatus>;
requestPermissions(
permissions?: GeolocationPluginPermissions,
): Promise<PermissionStatus>;
}

export interface ClearWatchOptions {
Expand Down Expand Up @@ -122,6 +155,9 @@ export interface PositionOptions {
/**
* High accuracy mode (such as GPS, if available)
*
* On Android 12+ devices it will be ignored if users didn't grant
* ACCESS_FINE_LOCATION permissions (can be checked with location alias).
*
* @default false
* @since 1.0.0
*/
Expand Down
2 changes: 1 addition & 1 deletion geolocation/src/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class GeolocationWeb extends WebPlugin implements GeolocationPlugin {
const permission = await window.navigator.permissions.query({
name: 'geolocation',
});
return { location: permission.state };
return { location: permission.state, coarseLocation: permission.state };
}

async requestPermissions(): Promise<PermissionStatus> {
Expand Down

0 comments on commit 7563040

Please sign in to comment.