diff --git a/demo/app/tests/internal/activity-recognition/recognizers/index.ts b/demo/app/tests/internal/activity-recognition/recognizers/index.ts index 90852c1..c7fa130 100644 --- a/demo/app/tests/internal/activity-recognition/recognizers/index.ts +++ b/demo/app/tests/internal/activity-recognition/recognizers/index.ts @@ -6,6 +6,7 @@ import { Resolution, HumanActivity, } from "nativescript-context-apis/internal/activity-recognition"; +import { StartOptions } from "nativescript-context-apis/internal/activity-recognition/recognizers"; import { RecognizerManager } from "nativescript-context-apis/internal/activity-recognition/recognizers/recognizer-manager"; export function createCallbackManagerMock(): RecognizerCallbackManager { @@ -30,7 +31,13 @@ export function createRecognizersStateStoreMock(): RecognizerStateStore { isActive(recognizer: Resolution): Promise { return Promise.resolve(false); }, - markAsActive(recognizer: Resolution): Promise { + getStartOptions(recognizer: Resolution): Promise { + return Promise.resolve(null); + }, + markAsActive( + recognizer: Resolution, + startOptions: StartOptions + ): Promise { return Promise.resolve(); }, markAsInactive(recognizer: Resolution): Promise { diff --git a/demo/app/tests/internal/activity-recognition/recognizers/low-res/android/recognizer.android.ts b/demo/app/tests/internal/activity-recognition/recognizers/low-res/android/recognizer.android.ts index 5efc3a2..8a5bd99 100644 --- a/demo/app/tests/internal/activity-recognition/recognizers/low-res/android/recognizer.android.ts +++ b/demo/app/tests/internal/activity-recognition/recognizers/low-res/android/recognizer.android.ts @@ -3,6 +3,7 @@ import { RecognizerManager } from "nativescript-context-apis/internal/activity-r import { RecognizerCallbackManager } from "nativescript-context-apis/internal/activity-recognition/recognizers/callback-manager"; import { AndroidLowResRecognizer } from "nativescript-context-apis/internal/activity-recognition/recognizers/low-res/android/recognizer.android"; import { Resolution } from "nativescript-context-apis/internal/activity-recognition"; +import { StartOptions } from "nativescript-context-apis/internal/activity-recognition/recognizers"; import { createRecognizersStateStoreMock, createCallbackManagerMock, @@ -16,6 +17,7 @@ import { describe("Android low resolution activity recognizer", () => { const recognizerType = Resolution.LOW; + const startOptions: StartOptions = {}; let recognizerState: RecognizerStateStore; let callbackManager: RecognizerCallbackManager; @@ -32,7 +34,7 @@ describe("Android low resolution activity recognizer", () => { recognizerManager ); spyOn(recognizerState, "markAsActive") - .withArgs(recognizerType) + .withArgs(recognizerType, startOptions) .and.returnValue(Promise.resolve()); spyOn(recognizerState, "markAsInactive") .withArgs(recognizerType) @@ -63,8 +65,13 @@ describe("Android low resolution activity recognizer", () => { spyOn(recognizerState, "isActive") .withArgs(recognizerType) .and.returnValue(Promise.resolve(true)); + spyOn(recognizerState, "getStartOptions").and.returnValue( + Promise.resolve(startOptions) + ); await recognizer.setup(); - expect(recognizerManager.startListening).toHaveBeenCalled(); + expect(recognizerManager.startListening).toHaveBeenCalledWith( + startOptions + ); }); it("does not (re)start listening when inactive", async () => { @@ -78,10 +85,11 @@ describe("Android low resolution activity recognizer", () => { it("allows to start the recognition by activating the underlying subsystem", async () => { spyOn(recognizerManager, "startListening"); - await recognizer.startRecognizing(); + await recognizer.startRecognizing(startOptions); expect(recognizerManager.startListening).toHaveBeenCalled(); expect(recognizerState.markAsActive).toHaveBeenCalledWith( - recognizerType + recognizerType, + startOptions ); }); @@ -91,9 +99,7 @@ describe("Android low resolution activity recognizer", () => { await expectAsync(recognizer.startRecognizing()).toBeRejectedWith( listenError ); - expect(recognizerState.markAsActive).not.toHaveBeenCalledWith( - recognizerType - ); + expect(recognizerState.markAsActive).not.toHaveBeenCalled(); }); it("allows to stop the recognition by deactivating the underlying subsystem", async () => { diff --git a/demo/app/tests/internal/activity-recognition/recognizers/medium-res/android/recognizer.android.ts b/demo/app/tests/internal/activity-recognition/recognizers/medium-res/android/recognizer.android.ts index a06c078..d36299e 100644 --- a/demo/app/tests/internal/activity-recognition/recognizers/medium-res/android/recognizer.android.ts +++ b/demo/app/tests/internal/activity-recognition/recognizers/medium-res/android/recognizer.android.ts @@ -3,6 +3,7 @@ import { RecognizerManager } from "nativescript-context-apis/internal/activity-r import { RecognizerCallbackManager } from "nativescript-context-apis/internal/activity-recognition/recognizers/callback-manager"; import { AndroidMediumResRecognizer } from "nativescript-context-apis/internal/activity-recognition/recognizers/medium-res/android/recognizer.android"; import { Resolution } from "nativescript-context-apis/internal/activity-recognition"; +import { StartOptions } from "nativescript-context-apis/internal/activity-recognition/recognizers"; import { createRecognizersStateStoreMock, createCallbackManagerMock, @@ -16,6 +17,7 @@ import { describe("Android medium resolution activity recognizer", () => { const recognizerType = Resolution.MEDIUM; + const startOptions: StartOptions = { detectionInterval: 60000 }; let recognizerState: RecognizerStateStore; let callbackManager: RecognizerCallbackManager; @@ -32,7 +34,7 @@ describe("Android medium resolution activity recognizer", () => { recognizerManager ); spyOn(recognizerState, "markAsActive") - .withArgs(recognizerType) + .withArgs(recognizerType, startOptions) .and.returnValue(Promise.resolve()); spyOn(recognizerState, "markAsInactive") .withArgs(recognizerType) @@ -63,8 +65,13 @@ describe("Android medium resolution activity recognizer", () => { spyOn(recognizerState, "isActive") .withArgs(recognizerType) .and.returnValue(Promise.resolve(true)); + spyOn(recognizerState, "getStartOptions").and.returnValue( + Promise.resolve(startOptions) + ); await recognizer.setup(); - expect(recognizerManager.startListening).toHaveBeenCalled(); + expect(recognizerManager.startListening).toHaveBeenCalledWith( + startOptions + ); }); it("does not (re)start listening when inactive", async () => { @@ -78,22 +85,21 @@ describe("Android medium resolution activity recognizer", () => { it("allows to start the recognition by activating the underlying subsystem", async () => { spyOn(recognizerManager, "startListening"); - await recognizer.startRecognizing(); + await recognizer.startRecognizing(startOptions); expect(recognizerManager.startListening).toHaveBeenCalled(); expect(recognizerState.markAsActive).toHaveBeenCalledWith( - recognizerType + recognizerType, + startOptions ); }); it("does not mark the recognizer as active if the activation fails", async () => { const listenError = new Error("Could not start listening"); spyOn(recognizerManager, "startListening").and.rejectWith(listenError); - await expectAsync(recognizer.startRecognizing()).toBeRejectedWith( - listenError - ); - expect(recognizerState.markAsActive).not.toHaveBeenCalledWith( - recognizerType - ); + await expectAsync( + recognizer.startRecognizing(startOptions) + ).toBeRejectedWith(listenError); + expect(recognizerState.markAsActive).not.toHaveBeenCalled(); }); it("allows to stop the recognition by deactivating the underlying subsystem", async () => { diff --git a/demo/app/tests/internal/activity-recognition/recognizers/state-store.ts b/demo/app/tests/internal/activity-recognition/recognizers/state-store.ts index ffc5f6f..d69fae1 100644 --- a/demo/app/tests/internal/activity-recognition/recognizers/state-store.ts +++ b/demo/app/tests/internal/activity-recognition/recognizers/state-store.ts @@ -3,6 +3,7 @@ import { Resolution, HumanActivity, } from "nativescript-context-apis/internal/activity-recognition"; +import { StartOptions } from "nativescript-context-apis/internal/activity-recognition/recognizers"; describe("Recognizers state store", () => { const recognizer = Resolution.HIGH; @@ -12,8 +13,28 @@ describe("Recognizers state store", () => { expect(isActive == true || isActive == false).toBeTrue(); }); + it("returns the start options of a recognizer marked as active", async () => { + const expectedStartOptions: StartOptions = { detectionInterval: 60000 }; + await recognizersStateStoreDb.markAsActive( + recognizer, + expectedStartOptions + ); + const startOptions = await recognizersStateStoreDb.getStartOptions( + recognizer + ); + expect(startOptions).toEqual(expectedStartOptions); + }); + + it("returns no start options when the recognizer is marked as inactive", async () => { + await recognizersStateStoreDb.markAsInactive(recognizer); + const startOptions = await recognizersStateStoreDb.getStartOptions( + recognizer + ); + expect(startOptions).toBeNull(); + }); + it("marks a recognizer as active", async () => { - await recognizersStateStoreDb.markAsActive(recognizer); + await recognizersStateStoreDb.markAsActive(recognizer, {}); const isActive = await recognizersStateStoreDb.isActive(recognizer); expect(isActive).toBeTrue(); }); @@ -33,7 +54,7 @@ describe("Recognizers state store", () => { }); it("successfully updates the last activity of an active recognizer", async () => { - await recognizersStateStoreDb.markAsActive(recognizer); + await recognizersStateStoreDb.markAsActive(recognizer, {}); const activity = HumanActivity.RUNNING; await recognizersStateStoreDb.updateLastActivity(recognizer, activity); const lastActivity = await recognizersStateStoreDb.getLastActivity( diff --git a/src/geolocation/index.ts b/src/geolocation/index.ts index 2cc0948..cf62f1c 100644 --- a/src/geolocation/index.ts +++ b/src/geolocation/index.ts @@ -2,6 +2,7 @@ export { getGeolocationProvider, GeolocationProvider, Geolocation, + GeolocationLike, AcquireOptions, StreamOptions, } from "../internal/geolocation"; diff --git a/src/internal/activity-recognition/recognizers/abstract-recognizer.ts b/src/internal/activity-recognition/recognizers/abstract-recognizer.ts index 03b1b44..6c950aa 100644 --- a/src/internal/activity-recognition/recognizers/abstract-recognizer.ts +++ b/src/internal/activity-recognition/recognizers/abstract-recognizer.ts @@ -24,13 +24,16 @@ export abstract class AbstractActivityRecognizer implements ActivityRecognizer { async setup(): Promise { const active = await this.recognizerState.isActive(this.recognizerType); if (active) { - await this.recognitionManager.startListening(); + const startOptions = await this.recognizerState.getStartOptions( + this.recognizerType + ); + await this.recognitionManager.startListening(startOptions); } } async startRecognizing(options: StartOptions = {}): Promise { await this.recognitionManager.startListening(options); - await this.recognizerState.markAsActive(this.recognizerType); + await this.recognizerState.markAsActive(this.recognizerType, options); } async stopRecognizing(): Promise { diff --git a/src/internal/activity-recognition/recognizers/state/model.ts b/src/internal/activity-recognition/recognizers/state/model.ts index 11c3ef9..6b24fcb 100644 --- a/src/internal/activity-recognition/recognizers/state/model.ts +++ b/src/internal/activity-recognition/recognizers/state/model.ts @@ -5,6 +5,7 @@ export const recognizersStateModel: InanoSQLTableConfig = { model: { "id:string": { pk: true }, "active:boolean": {}, + "startOptions:string": {}, "lastActivity:string": {}, }, }; diff --git a/src/internal/activity-recognition/recognizers/state/store.ts b/src/internal/activity-recognition/recognizers/state/store.ts index b45e474..f8e25b1 100644 --- a/src/internal/activity-recognition/recognizers/state/store.ts +++ b/src/internal/activity-recognition/recognizers/state/store.ts @@ -1,10 +1,14 @@ -import { HumanActivity, Resolution } from "../../index"; +import { HumanActivity, Resolution, StartOptions } from "../../index"; import { pluginDb } from "../../../persistence/plugin-db"; import { recognizersStateModel } from "./model"; export interface RecognizerStateStore { isActive(recognizer: Resolution): Promise; - markAsActive(recognizer: Resolution): Promise; + getStartOptions(recognizer: Resolution): Promise; + markAsActive( + recognizer: Resolution, + startOptions: StartOptions + ): Promise; markAsInactive(recognizer: Resolution): Promise; getLastActivity(recognizer: Resolution): Promise; updateLastActivity( @@ -17,19 +21,31 @@ class RecognizersStateStoreDb implements RecognizerStateStore { private tableName = recognizersStateModel.name; async isActive(recognizer: Resolution): Promise { - const instance = await this.db(); - const rows = await instance - .query("select") - .where(["id", "=", recognizer]) - .exec(); - if (rows.length === 0) { + const recognizerData = await this.getRecognizerData(recognizer); + if (!recognizerData) { return false; } - return rows[0].active; + return recognizerData.active; + } + + async getStartOptions(recognizer: Resolution): Promise { + const isActive = await this.isActive(recognizer); + if (!isActive) { + return null; + } + + const recognizerData = await this.getRecognizerData(recognizer); + if (!recognizerData) { + return null; + } + return JSON.parse(recognizerData.startOptions); } - async markAsActive(recognizer: Resolution): Promise { - await this.updateStatus(recognizer, true); + async markAsActive( + recognizer: Resolution, + startOptions: StartOptions + ): Promise { + await this.updateStatus(recognizer, true, startOptions); } async markAsInactive(recognizer: Resolution): Promise { @@ -64,13 +80,36 @@ class RecognizersStateStoreDb implements RecognizerStateStore { .exec(); } - private async updateStatus(recognizer: Resolution, active: boolean) { + private async updateStatus( + recognizer: Resolution, + active: boolean, + startOptions: StartOptions = {} + ) { const instance = await this.db(); await instance - .query("upsert", { id: recognizer, active, lastActivity: null }) + .query("upsert", { + id: recognizer, + active, + startOptions: JSON.stringify(startOptions), + lastActivity: null, + }) .exec(); } + private async getRecognizerData( + recognizer: Resolution + ): Promise<{ [key: string]: any }> { + const instance = await this.db(); + const rows = await instance + .query("select") + .where(["id", "=", recognizer]) + .exec(); + if (rows.length === 0) { + return null; + } + return rows[0]; + } + private db(tableName = this.tableName) { return pluginDb.instance(tableName); } diff --git a/src/internal/geolocation/index.ts b/src/internal/geolocation/index.ts index 6260b09..a82a267 100644 --- a/src/internal/geolocation/index.ts +++ b/src/internal/geolocation/index.ts @@ -55,7 +55,7 @@ export interface StreamOptions extends AcquireOptions { saveBattery?: boolean; } -export { Geolocation } from "./geolocation"; +export { Geolocation, GeolocationLike } from "./geolocation"; function geolocationOptionsToPluginOptions( options: AcquireOptions | StreamOptions