Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(geolocation): Add new alias for coarse location #684

Merged
merged 2 commits into from
Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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