react-native-brouter 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +125 -0
- package/android/build.gradle +110 -0
- package/android/generated/java/com/jhotadhari/reactnative/brouter/NativeBRouterSpec.java +39 -0
- package/android/generated/jni/CMakeLists.txt +28 -0
- package/android/generated/jni/RNBRouterSpec-generated.cpp +32 -0
- package/android/generated/jni/RNBRouterSpec.h +31 -0
- package/android/generated/jni/react/renderer/components/RNBRouterSpec/RNBRouterSpecJSI.h +38 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/aidl/btools/routingapp/IBRouterService.aidl +47 -0
- package/android/src/main/java/com/jhotadhari/reactnative/brouter/BRouterClient.java +205 -0
- package/android/src/main/java/com/jhotadhari/reactnative/brouter/BRouterError.java +38 -0
- package/android/src/main/java/com/jhotadhari/reactnative/brouter/BRouterModule.java +135 -0
- package/android/src/main/java/com/jhotadhari/reactnative/brouter/BRouterPackage.kt +33 -0
- package/android/src/main/java/com/jhotadhari/reactnative/brouter/BRouterServiceConnection.java +54 -0
- package/android/src/main/java/com/jhotadhari/reactnative/brouter/ParamMapper.java +174 -0
- package/android/src/test/java/com/jhotadhari/reactnative/brouter/BRouterClientTest.java +247 -0
- package/android/src/test/java/com/jhotadhari/reactnative/brouter/BRouterErrorTest.java +48 -0
- package/android/src/test/java/com/jhotadhari/reactnative/brouter/BRouterModuleTest.java +137 -0
- package/android/src/test/java/com/jhotadhari/reactnative/brouter/ParamMapperTest.java +279 -0
- package/lib/module/NativeBRouter.js +5 -0
- package/lib/module/NativeBRouter.js.map +1 -0
- package/lib/module/geojson/index.js +235 -0
- package/lib/module/geojson/index.js.map +1 -0
- package/lib/module/index.js +297 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/release.config.d.ts +11 -0
- package/lib/typescript/release.config.d.ts.map +1 -0
- package/lib/typescript/src/NativeBRouter.d.ts +9 -0
- package/lib/typescript/src/NativeBRouter.d.ts.map +1 -0
- package/lib/typescript/src/geojson/index.d.ts +122 -0
- package/lib/typescript/src/geojson/index.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +13 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +93 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +159 -0
- package/react-native.config.js +12 -0
- package/src/NativeBRouter.ts +8 -0
- package/src/geojson/index.ts +371 -0
- package/src/index.tsx +344 -0
- package/src/types.ts +112 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
package com.jhotadhari.reactnative.brouter;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
import androidx.annotation.Nullable;
|
|
7
|
+
|
|
8
|
+
import btools.routingapp.IBRouterService;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Manages the bind lifecycle to the external BRouter Android app's AIDL service.
|
|
12
|
+
*
|
|
13
|
+
* <p>This replaces the previous {@code BRouterConnector} singleton with an
|
|
14
|
+
* instance-based design — each {@link BRouterModule} owns one client, keyed
|
|
15
|
+
* to its {@code ReactContext}, so connection timeouts and lifecycle are
|
|
16
|
+
* scoped correctly.
|
|
17
|
+
*
|
|
18
|
+
* <p>The bind-and-poll pattern is derived from OsmAnd's
|
|
19
|
+
* {@code BRouterServiceConnection} usage (the polling loop is necessary
|
|
20
|
+
* because the external service process needs time to start after the bind
|
|
21
|
+
* intent is sent).
|
|
22
|
+
*/
|
|
23
|
+
public class BRouterClient {
|
|
24
|
+
|
|
25
|
+
private final Context ctx;
|
|
26
|
+
private final int connectTimeoutMs;
|
|
27
|
+
|
|
28
|
+
@Nullable
|
|
29
|
+
private BRouterServiceConnection connection;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The error code from the most recent failed {@link #connect()} call,
|
|
33
|
+
* or {@code null} if the last connection attempt succeeded.
|
|
34
|
+
*/
|
|
35
|
+
@Nullable
|
|
36
|
+
private String lastError;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param ctx Android context used to bind the BRouter service.
|
|
40
|
+
* @param connectTimeoutMs maximum time (ms) to wait for the service process
|
|
41
|
+
* to start. Default 1000.
|
|
42
|
+
*/
|
|
43
|
+
public BRouterClient( @NonNull Context ctx, int connectTimeoutMs ) {
|
|
44
|
+
this.ctx = ctx.getApplicationContext();
|
|
45
|
+
this.connectTimeoutMs = connectTimeoutMs;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Bind to the BRouter service and wait for it to become available.
|
|
50
|
+
*
|
|
51
|
+
* <p>Safe to call multiple times — if already connected this is a no-op.
|
|
52
|
+
*
|
|
53
|
+
* <p>The early-return / connection-creation path is synchronized, but the
|
|
54
|
+
* polling loop runs outside the monitor so that a main-thread
|
|
55
|
+
* {@link #disconnect()} (via {@code invalidate()}) is not blocked.
|
|
56
|
+
*
|
|
57
|
+
* @return the AIDL service interface, or {@code null} if the connection
|
|
58
|
+
* could not be established. Call {@link #getLastError()} for
|
|
59
|
+
* the specific failure code.
|
|
60
|
+
*/
|
|
61
|
+
@Nullable
|
|
62
|
+
public IBRouterService connect() {
|
|
63
|
+
BRouterServiceConnection localConn;
|
|
64
|
+
|
|
65
|
+
synchronized ( this ) {
|
|
66
|
+
if ( connection != null ) {
|
|
67
|
+
IBRouterService svc = connection.getBRouterService();
|
|
68
|
+
if ( svc != null && svc.asBinder().isBinderAlive() ) {
|
|
69
|
+
lastError = null;
|
|
70
|
+
return svc;
|
|
71
|
+
}
|
|
72
|
+
// Binder died — reconnect below
|
|
73
|
+
disconnect();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
connection = BRouterServiceConnection.connect( ctx );
|
|
77
|
+
if ( connection == null ) {
|
|
78
|
+
lastError = BRouterError.SERVICE_NOT_INSTALLED;
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
localConn = connection;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Poll until the service process starts, or timeout.
|
|
85
|
+
// Pattern copied from OsmAnd — the service process needs time to start
|
|
86
|
+
// after the bind intent fires, and there is no callback for "process ready".
|
|
87
|
+
// Polling runs OUTSIDE the synchronized block so that a main-thread
|
|
88
|
+
// invalidate() -> disconnect() can proceed without blocking.
|
|
89
|
+
int i = 0;
|
|
90
|
+
try {
|
|
91
|
+
while ( localConn.getBRouterService() == null && i * 100 < connectTimeoutMs ) {
|
|
92
|
+
Thread.sleep( 100 );
|
|
93
|
+
i += 1;
|
|
94
|
+
}
|
|
95
|
+
} catch ( InterruptedException e ) {
|
|
96
|
+
Thread.currentThread().interrupt();
|
|
97
|
+
lastError = BRouterError.CONNECTION_TIMEOUT;
|
|
98
|
+
disconnect();
|
|
99
|
+
return null;
|
|
100
|
+
} catch ( Exception e ) {
|
|
101
|
+
e.printStackTrace();
|
|
102
|
+
lastError = BRouterError.UNKNOWN;
|
|
103
|
+
disconnect();
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if ( localConn.getBRouterService() == null ) {
|
|
108
|
+
lastError = BRouterError.CONNECTION_TIMEOUT;
|
|
109
|
+
disconnect();
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
lastError = null;
|
|
114
|
+
return localConn.getBRouterService();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Return the error code from the most recent failed {@link #connect()}
|
|
119
|
+
* call, or {@code null} if the last connection attempt succeeded.
|
|
120
|
+
*
|
|
121
|
+
* <p>Use this after {@link #connect()} returns {@code null} (or
|
|
122
|
+
* {@link #getRoute} throws) to distinguish "app not installed" from a
|
|
123
|
+
* transient connection timeout.
|
|
124
|
+
*/
|
|
125
|
+
@Nullable
|
|
126
|
+
public String getLastError() {
|
|
127
|
+
return lastError;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Return the connection timeout in milliseconds.
|
|
132
|
+
*/
|
|
133
|
+
public int getConnectTimeoutMs() {
|
|
134
|
+
return connectTimeoutMs;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Return the current service interface, reconnecting transparently if the
|
|
139
|
+
* binder has died.
|
|
140
|
+
*
|
|
141
|
+
* <p>Copied pattern from OsmAnd's {@code getBRouterService()}.
|
|
142
|
+
*/
|
|
143
|
+
@Nullable
|
|
144
|
+
public synchronized IBRouterService getService() {
|
|
145
|
+
if ( connection == null ) {
|
|
146
|
+
return connect();
|
|
147
|
+
}
|
|
148
|
+
IBRouterService service = connection.getBRouterService();
|
|
149
|
+
if ( service == null ) {
|
|
150
|
+
return connect();
|
|
151
|
+
}
|
|
152
|
+
if ( ! service.asBinder().isBinderAlive() ) {
|
|
153
|
+
return connect();
|
|
154
|
+
}
|
|
155
|
+
lastError = null;
|
|
156
|
+
return service;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Call the BRouter service with the given parameter bundle.
|
|
161
|
+
*
|
|
162
|
+
* @param params the Bundle produced by {@link ParamMapper#toBundle}.
|
|
163
|
+
* @return the track result string, or {@code null} if routing failed.
|
|
164
|
+
* @throws IllegalStateException if the service is unavailable (call
|
|
165
|
+
* {@link #getLastError()} for the specific error code).
|
|
166
|
+
* @throws Exception if the AIDL call itself fails.
|
|
167
|
+
*/
|
|
168
|
+
@Nullable
|
|
169
|
+
public String getRoute( @NonNull android.os.Bundle params ) throws Exception {
|
|
170
|
+
IBRouterService service = getService();
|
|
171
|
+
if ( service == null ) {
|
|
172
|
+
String code = lastError != null ? lastError : BRouterError.SERVICE_UNAVAILABLE;
|
|
173
|
+
throw new IllegalStateException( code );
|
|
174
|
+
}
|
|
175
|
+
return service.getTrackFromParams( params );
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Whether the service is currently connected and alive.
|
|
180
|
+
*/
|
|
181
|
+
public synchronized boolean isConnected() {
|
|
182
|
+
if ( connection == null ) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
IBRouterService svc = connection.getBRouterService();
|
|
186
|
+
return svc != null && svc.asBinder().isBinderAlive();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Unbind from the BRouter service and release resources.
|
|
191
|
+
*
|
|
192
|
+
* <p>Safe to call multiple times. After calling this, the next
|
|
193
|
+
* {@link #connect()} will create a fresh binding.
|
|
194
|
+
*/
|
|
195
|
+
public synchronized void disconnect() {
|
|
196
|
+
if ( connection != null ) {
|
|
197
|
+
try {
|
|
198
|
+
connection.disconnect( ctx );
|
|
199
|
+
} catch ( Exception e ) {
|
|
200
|
+
// Best-effort cleanup — the context may already be gone.
|
|
201
|
+
}
|
|
202
|
+
connection = null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
package com.jhotadhari.reactnative.brouter;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Structured error codes for the BRouter native module.
|
|
5
|
+
*
|
|
6
|
+
* <p>Each error code maps to a distinct failure scenario so that JS consumers
|
|
7
|
+
* can react programmatically (e.g. prompt the user to install BRouter vs.
|
|
8
|
+
* retry a transient connection failure).
|
|
9
|
+
*
|
|
10
|
+
* <p>Errors are passed to JS via {@code promise.reject(code, message)}.
|
|
11
|
+
*/
|
|
12
|
+
public final class BRouterError {
|
|
13
|
+
|
|
14
|
+
/** The BRouter Android app is not installed on the device. */
|
|
15
|
+
public static final String SERVICE_NOT_INSTALLED = "SERVICE_NOT_INSTALLED";
|
|
16
|
+
|
|
17
|
+
/** Bound to the BRouter process but could not obtain the AIDL interface. */
|
|
18
|
+
public static final String SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE";
|
|
19
|
+
|
|
20
|
+
/** The BRouter service process did not start within the connect timeout. */
|
|
21
|
+
public static final String CONNECTION_TIMEOUT = "CONNECTION_TIMEOUT";
|
|
22
|
+
|
|
23
|
+
/** The routing calculation exceeded {@code maxRunningTime}. */
|
|
24
|
+
public static final String ROUTING_TIMEOUT = "ROUTING_TIMEOUT";
|
|
25
|
+
|
|
26
|
+
/** The request parameters are invalid (e.g. fewer than 2 waypoints). */
|
|
27
|
+
public static final String INVALID_PARAMS = "INVALID_PARAMS";
|
|
28
|
+
|
|
29
|
+
/** BRouter could not find a route between the given waypoints. */
|
|
30
|
+
public static final String ROUTING_FAILED = "ROUTING_FAILED";
|
|
31
|
+
|
|
32
|
+
/** An unexpected error occurred. See the message for details. */
|
|
33
|
+
public static final String UNKNOWN = "UNKNOWN";
|
|
34
|
+
|
|
35
|
+
private BRouterError() {
|
|
36
|
+
// static constants only
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
package com.jhotadhari.reactnative.brouter;
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
import androidx.annotation.Nullable;
|
|
7
|
+
|
|
8
|
+
import com.facebook.react.bridge.Promise;
|
|
9
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
10
|
+
import com.facebook.react.bridge.ReactMethod;
|
|
11
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
12
|
+
import com.facebook.react.module.annotations.ReactModule;
|
|
13
|
+
|
|
14
|
+
import btools.routingapp.IBRouterService;
|
|
15
|
+
|
|
16
|
+
@ReactModule(name = BRouterModule.NAME)
|
|
17
|
+
public class BRouterModule extends NativeBRouterSpec {
|
|
18
|
+
|
|
19
|
+
public static final String NAME = "BRouter";
|
|
20
|
+
|
|
21
|
+
private static final int DEFAULT_CONNECT_TIMEOUT_MS = 1000;
|
|
22
|
+
|
|
23
|
+
@Nullable
|
|
24
|
+
BRouterClient client;
|
|
25
|
+
|
|
26
|
+
public BRouterModule( ReactApplicationContext reactContext ) {
|
|
27
|
+
super( reactContext );
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@NonNull
|
|
31
|
+
@Override
|
|
32
|
+
public String getName() {
|
|
33
|
+
return NAME;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Return the BRouter client, creating it lazily if necessary.
|
|
38
|
+
*
|
|
39
|
+
* <p>Synchronized so two concurrent {@code getRoute()} calls cannot
|
|
40
|
+
* race and create duplicate clients (each with its own active
|
|
41
|
+
* {@code ServiceConnection} binding).
|
|
42
|
+
*
|
|
43
|
+
* <p>If the client already exists and the caller passes a different
|
|
44
|
+
* {@code connectTimeout}, the old client is disconnected and a fresh
|
|
45
|
+
* one is created — per-request timeouts are supported rather than
|
|
46
|
+
* being locked to the first call's value.
|
|
47
|
+
*/
|
|
48
|
+
@NonNull
|
|
49
|
+
synchronized BRouterClient getClient( @NonNull ReadableMap params ) {
|
|
50
|
+
int timeout = params.hasKey( "connectTimeout" )
|
|
51
|
+
? params.getInt( "connectTimeout" )
|
|
52
|
+
: DEFAULT_CONNECT_TIMEOUT_MS;
|
|
53
|
+
|
|
54
|
+
if ( client != null ) {
|
|
55
|
+
if ( client.getConnectTimeoutMs() != timeout ) {
|
|
56
|
+
client.disconnect();
|
|
57
|
+
client = null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if ( client == null ) {
|
|
62
|
+
client = new BRouterClient( getReactApplicationContext(), timeout );
|
|
63
|
+
}
|
|
64
|
+
return client;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@Override
|
|
68
|
+
@ReactMethod
|
|
69
|
+
public void getRoute( @NonNull ReadableMap params, @NonNull Promise promise ) {
|
|
70
|
+
android.util.Log.d( "BRouterModule", "getRoute keys: " + params.toHashMap().keySet() );
|
|
71
|
+
try {
|
|
72
|
+
// Validate waypoints
|
|
73
|
+
if ( ! params.hasKey( "lonlats" ) || ! params.hasKey( "lats" ) || ! params.hasKey( "lons" ) ) {
|
|
74
|
+
promise.reject(
|
|
75
|
+
BRouterError.INVALID_PARAMS,
|
|
76
|
+
"At least 2 waypoints are required"
|
|
77
|
+
);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Build the AIDL Bundle
|
|
82
|
+
Bundle brouterParams = ParamMapper.toBundle( params );
|
|
83
|
+
|
|
84
|
+
// Use client.getRoute() which handles transparent reconnect
|
|
85
|
+
// on binder death — the raw service reference is never exposed.
|
|
86
|
+
BRouterClient brouterClient = getClient( params );
|
|
87
|
+
String track = brouterClient.getRoute( brouterParams );
|
|
88
|
+
|
|
89
|
+
if ( track == null ) {
|
|
90
|
+
promise.reject(
|
|
91
|
+
BRouterError.ROUTING_FAILED,
|
|
92
|
+
"No route found between the given waypoints"
|
|
93
|
+
);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
promise.resolve( track );
|
|
98
|
+
} catch ( Exception e ) {
|
|
99
|
+
e.printStackTrace();
|
|
100
|
+
|
|
101
|
+
// Map known error codes from BRouterClient.getLastError()
|
|
102
|
+
String code = BRouterError.UNKNOWN;
|
|
103
|
+
String message = e.toString();
|
|
104
|
+
|
|
105
|
+
if ( e instanceof IllegalStateException ) {
|
|
106
|
+
String detail = e.getMessage();
|
|
107
|
+
if ( detail != null ) {
|
|
108
|
+
// BRouterClient.getRoute() passes the error code as the
|
|
109
|
+
// exception message when the service is unavailable.
|
|
110
|
+
if ( detail.equals( BRouterError.SERVICE_NOT_INSTALLED )
|
|
111
|
+
|| detail.equals( BRouterError.CONNECTION_TIMEOUT )
|
|
112
|
+
|| detail.equals( BRouterError.SERVICE_UNAVAILABLE ) ) {
|
|
113
|
+
code = detail;
|
|
114
|
+
message = detail.equals( BRouterError.SERVICE_NOT_INSTALLED )
|
|
115
|
+
? "The BRouter app is not installed on this device"
|
|
116
|
+
: detail.equals( BRouterError.CONNECTION_TIMEOUT )
|
|
117
|
+
? "Timed out waiting for the BRouter service to start"
|
|
118
|
+
: "BRouter service is not available";
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
promise.reject( code, message );
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@Override
|
|
128
|
+
public void invalidate() {
|
|
129
|
+
if ( client != null ) {
|
|
130
|
+
client.disconnect();
|
|
131
|
+
client = null;
|
|
132
|
+
}
|
|
133
|
+
super.invalidate();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
package com.jhotadhari.reactnative.brouter
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.BaseReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.module.model.ReactModuleInfo
|
|
7
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
8
|
+
import java.util.HashMap
|
|
9
|
+
|
|
10
|
+
class BRouterPackage : BaseReactPackage() {
|
|
11
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
12
|
+
return if (name == BRouterModule.NAME) {
|
|
13
|
+
BRouterModule(reactContext)
|
|
14
|
+
} else {
|
|
15
|
+
null
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
|
|
20
|
+
return ReactModuleInfoProvider {
|
|
21
|
+
val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
|
|
22
|
+
moduleInfos[BRouterModule.NAME] = ReactModuleInfo(
|
|
23
|
+
BRouterModule.NAME,
|
|
24
|
+
BRouterModule.NAME,
|
|
25
|
+
false, // canOverrideExistingModule
|
|
26
|
+
false, // needsEagerInit
|
|
27
|
+
false, // isCxxModule
|
|
28
|
+
true // isTurboModule
|
|
29
|
+
)
|
|
30
|
+
moduleInfos
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
package/android/src/main/java/com/jhotadhari/reactnative/brouter/BRouterServiceConnection.java
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
package com.jhotadhari.reactnative.brouter;
|
|
2
|
+
|
|
3
|
+
import android.content.ComponentName;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.content.Intent;
|
|
6
|
+
import android.content.ServiceConnection;
|
|
7
|
+
import android.os.IBinder;
|
|
8
|
+
|
|
9
|
+
import androidx.annotation.NonNull;
|
|
10
|
+
import androidx.annotation.Nullable;
|
|
11
|
+
|
|
12
|
+
import btools.routingapp.IBRouterService;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Copy of https://github.com/osmandapp/OsmAnd/blob/master/OsmAnd/src/btools/routingapp/BRouterServiceConnection.java
|
|
16
|
+
*/
|
|
17
|
+
public class BRouterServiceConnection implements ServiceConnection {
|
|
18
|
+
|
|
19
|
+
private volatile IBRouterService brouterService;
|
|
20
|
+
|
|
21
|
+
public void onServiceConnected(ComponentName className, IBinder boundService) {
|
|
22
|
+
brouterService = IBRouterService.Stub.asInterface(boundService);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public void onServiceDisconnected(ComponentName className) {
|
|
26
|
+
brouterService = null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public void disconnect(@NonNull Context ctx) {
|
|
30
|
+
ctx.unbindService(this);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Nullable
|
|
34
|
+
public IBRouterService getBRouterService() {
|
|
35
|
+
return brouterService;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Nullable
|
|
39
|
+
public static BRouterServiceConnection connect( @NonNull Context ctx ) {
|
|
40
|
+
BRouterServiceConnection conn = new BRouterServiceConnection();
|
|
41
|
+
Intent intent = new Intent();
|
|
42
|
+
intent.setClassName("btools.routingapp", "btools.routingapp.BRouterService");
|
|
43
|
+
boolean hasBRouter = ctx.bindService(
|
|
44
|
+
intent,
|
|
45
|
+
conn,
|
|
46
|
+
Context.BIND_AUTO_CREATE
|
|
47
|
+
);
|
|
48
|
+
if ( ! hasBRouter ) {
|
|
49
|
+
conn = null;
|
|
50
|
+
}
|
|
51
|
+
return conn;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
package com.jhotadhari.reactnative.brouter;
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle;
|
|
4
|
+
|
|
5
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
6
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
7
|
+
import com.facebook.react.bridge.ReadableType;
|
|
8
|
+
|
|
9
|
+
import androidx.annotation.NonNull;
|
|
10
|
+
import androidx.annotation.Nullable;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Converts a {@link ReadableMap} (serialized from the JS {@code RouteRequest})
|
|
14
|
+
* into an Android {@link Bundle} matching the key/type contract documented in
|
|
15
|
+
* {@code IBRouterService.aidl}.
|
|
16
|
+
*
|
|
17
|
+
* <p>Every key listed in the AIDL comment block is mapped here. This is the
|
|
18
|
+
* single place where JS-to-AIDL key name translation lives — adding a new
|
|
19
|
+
* param means adding one field to the JS type and one {@code putX} call here.
|
|
20
|
+
*/
|
|
21
|
+
public final class ParamMapper {
|
|
22
|
+
|
|
23
|
+
private ParamMapper() {
|
|
24
|
+
// static utility — no instances
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Convert the JS-serialized route request into a Bundle suitable for
|
|
29
|
+
* {@code IBRouterService.getTrackFromParams(Bundle)}.
|
|
30
|
+
*/
|
|
31
|
+
@NonNull
|
|
32
|
+
public static Bundle toBundle( @NonNull ReadableMap params ) {
|
|
33
|
+
return toBundle( params, new Bundle() );
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Overload that writes into an existing Bundle (useful for testing
|
|
38
|
+
* with a mocked Bundle).
|
|
39
|
+
*/
|
|
40
|
+
@NonNull
|
|
41
|
+
static Bundle toBundle( @NonNull ReadableMap params, @NonNull Bundle b ) {
|
|
42
|
+
|
|
43
|
+
// ── Waypoints ──────────────────────────────────────────────
|
|
44
|
+
// JS pre-serializes waypoints into lonlats, lats, lons, straight
|
|
45
|
+
putString( b, params, "lonlats" );
|
|
46
|
+
putDoubleArray( b, params, "lats" );
|
|
47
|
+
putDoubleArray( b, params, "lons" );
|
|
48
|
+
putString( b, params, "straight" );
|
|
49
|
+
|
|
50
|
+
// ── Profile ────────────────────────────────────────────────
|
|
51
|
+
putString( b, params, "profile" );
|
|
52
|
+
putString( b, params, "remoteProfile" );
|
|
53
|
+
|
|
54
|
+
// ── Vehicle / speed ────────────────────────────────────────
|
|
55
|
+
putString( b, params, "v" );
|
|
56
|
+
if ( params.hasKey( "fast" ) ) {
|
|
57
|
+
b.putInt( "fast", params.getInt( "fast" ) );
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ── Output format ──────────────────────────────────────────
|
|
61
|
+
putString( b, params, "trackFormat" );
|
|
62
|
+
|
|
63
|
+
// ── Alternative index ──────────────────────────────────────
|
|
64
|
+
if ( params.hasKey( "alternativeidx" ) ) {
|
|
65
|
+
b.putInt( "alternativeidx", params.getInt( "alternativeidx" ) );
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ── Export waypoints ───────────────────────────────────────
|
|
69
|
+
if ( params.hasKey( "exportWaypoints" ) ) {
|
|
70
|
+
b.putInt( "exportWaypoints", params.getInt( "exportWaypoints" ) );
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ── Turn instructions ──────────────────────────────────────
|
|
74
|
+
putString( b, params, "turnInstructionFormat" );
|
|
75
|
+
if ( params.hasKey( "timode" ) ) {
|
|
76
|
+
b.putInt( "timode", params.getInt( "timode" ) );
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ── Heading / direction ────────────────────────────────────
|
|
80
|
+
if ( params.hasKey( "heading" ) ) {
|
|
81
|
+
b.putDouble( "heading", params.getDouble( "heading" ) );
|
|
82
|
+
}
|
|
83
|
+
if ( params.hasKey( "direction" ) ) {
|
|
84
|
+
b.putDouble( "direction", params.getDouble( "direction" ) );
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ── Engine mode (elevation) ────────────────────────────────
|
|
88
|
+
if ( params.hasKey( "engineMode" ) ) {
|
|
89
|
+
b.putInt( "engineMode", params.getInt( "engineMode" ) );
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ── Timeout ────────────────────────────────────────────────
|
|
93
|
+
if ( params.hasKey( "maxRunningTime" ) ) {
|
|
94
|
+
b.putString( "maxRunningTime", String.valueOf( params.getInt( "maxRunningTime" ) ) );
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ── File output ────────────────────────────────────────────
|
|
98
|
+
putString( b, params, "pathToFileResult" );
|
|
99
|
+
|
|
100
|
+
// ── Compression ────────────────────────────────────────────
|
|
101
|
+
if ( params.hasKey( "acceptCompressedResult" ) ) {
|
|
102
|
+
b.putBoolean( "acceptCompressedResult", params.getBoolean( "acceptCompressedResult" ) );
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ── Extra params (profile setup key=value) ─────────────────
|
|
106
|
+
if ( params.hasKey( "extraParams" ) ) {
|
|
107
|
+
ReadableMap extra = params.getMap( "extraParams" );
|
|
108
|
+
if ( extra != null ) {
|
|
109
|
+
Bundle extraBundle = new Bundle();
|
|
110
|
+
com.facebook.react.bridge.ReadableMapKeySetIterator iterator =
|
|
111
|
+
extra.keySetIterator();
|
|
112
|
+
while ( iterator.hasNextKey() ) {
|
|
113
|
+
String key = iterator.nextKey();
|
|
114
|
+
ReadableType type = extra.getType( key );
|
|
115
|
+
if ( type == ReadableType.String ) {
|
|
116
|
+
extraBundle.putString( key, extra.getString( key ) );
|
|
117
|
+
} else if ( type == ReadableType.Number ) {
|
|
118
|
+
extraBundle.putDouble( key, extra.getDouble( key ) );
|
|
119
|
+
} else if ( type == ReadableType.Boolean ) {
|
|
120
|
+
extraBundle.putBoolean( key, extra.getBoolean( key ) );
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
b.putBundle( "extraParams", extraBundle );
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── Nogo areas ─────────────────────────────────────────────
|
|
128
|
+
putString( b, params, "nogos" );
|
|
129
|
+
putDoubleArray( b, params, "nogoLats" );
|
|
130
|
+
putDoubleArray( b, params, "nogoLons" );
|
|
131
|
+
putDoubleArray( b, params, "nogoRadi" );
|
|
132
|
+
|
|
133
|
+
// ── Polylines / polygons ──────────────────────────────────
|
|
134
|
+
putString( b, params, "polylines" );
|
|
135
|
+
putString( b, params, "polygons" );
|
|
136
|
+
|
|
137
|
+
// ── POIs ──────────────────────────────────────────────────
|
|
138
|
+
putString( b, params, "pois" );
|
|
139
|
+
|
|
140
|
+
return b;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ── Helpers ────────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
private static void putString(
|
|
146
|
+
@NonNull Bundle b,
|
|
147
|
+
@NonNull ReadableMap params,
|
|
148
|
+
@NonNull String key
|
|
149
|
+
) {
|
|
150
|
+
if ( params.hasKey( key ) ) {
|
|
151
|
+
String value = params.getString( key );
|
|
152
|
+
if ( value != null ) {
|
|
153
|
+
b.putString( key, value );
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private static void putDoubleArray(
|
|
159
|
+
@NonNull Bundle b,
|
|
160
|
+
@NonNull ReadableMap params,
|
|
161
|
+
@NonNull String key
|
|
162
|
+
) {
|
|
163
|
+
if ( params.hasKey( key ) ) {
|
|
164
|
+
ReadableArray arr = params.getArray( key );
|
|
165
|
+
if ( arr != null && arr.size() > 0 ) {
|
|
166
|
+
double[] doubles = new double[ arr.size() ];
|
|
167
|
+
for ( int i = 0; i < arr.size(); i++ ) {
|
|
168
|
+
doubles[ i ] = arr.getDouble( i );
|
|
169
|
+
}
|
|
170
|
+
b.putDoubleArray( key, doubles );
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|