diff --git a/.github/actions/create-native-bundle/action.yml b/.github/actions/create-native-bundle/action.yml index 5525fec65..dcf9fc0f6 100644 --- a/.github/actions/create-native-bundle/action.yml +++ b/.github/actions/create-native-bundle/action.yml @@ -41,7 +41,7 @@ runs: env: NODE_OPTIONS: --max_old_space_size=6144 - name: "Upload bundle for ${{ inputs.platform }}" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: ${{ inputs.platform }}-bundle path: ${{ inputs.platform }} diff --git a/.github/workflows/NativePipeline.yml b/.github/workflows/NativePipeline.yml index e277d0501..6fcaee180 100644 --- a/.github/workflows/NativePipeline.yml +++ b/.github/workflows/NativePipeline.yml @@ -32,10 +32,10 @@ jobs: runs-on: ubuntu-22.04 steps: - name: "Check out code" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 - name: "Get Mendix version" id: get-mendix-version - uses: notiz-dev/github-action-json-property@v0.2.0 + uses: notiz-dev/github-action-json-property@7a701887f4b568b23eb7b78bb0fc49aaeb1b68d3 # v0.2.0 with: path: configs/e2e/mendix-versions.json prop_path: latest @@ -48,7 +48,7 @@ jobs: MENDIX_VERSION: ${{ needs.mendix-version.outputs.mendix-version }} steps: - name: "Login to GitHub Container Registry" - uses: docker/login-action@v2.1.0 + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -58,11 +58,11 @@ jobs: docker manifest inspect ghcr.io/mendix/native-widgets/mxbuild:${{ env.MENDIX_VERSION }} || EXIT_CODE=$? echo "IMAGE_MISSING=$EXIT_CODE" >> $GITHUB_ENV - name: "Check out code" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 if: ${{ env.IMAGE_MISSING != 0 }} - name: "Build mxbuild image" if: ${{ env.IMAGE_MISSING != 0 }} - uses: docker/build-push-action@v4.0.0 + uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 with: file: ./.github/scripts/mxbuild.Dockerfile context: ./.github/scripts @@ -79,11 +79,11 @@ jobs: contents: read steps: - name: "Check out code" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 with: fetch-depth: 0 - name: "Set up node" - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 with: node-version-file: .nvmrc cache: yarn @@ -96,7 +96,7 @@ jobs: env: NODE_OPTIONS: --max_old_space_size=6144 - name: "Upload resources artifact" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: resources path: | @@ -115,11 +115,11 @@ jobs: - name: "Download test project" run: curl -L -o project.zip https://github.com/mendix/Native-Mobile-Resources/archive/refs/heads/main.zip - name: "Extract test project" - uses: montudor/action-zip@v1.0.0 + uses: montudor/action-zip@0852c26906e00f8a315c704958823928d8018b28 # v1.0.0 with: args: unzip -qq project.zip - name: "Download resources artifact" - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: resources path: resources @@ -146,9 +146,9 @@ jobs: mv -f resources/jsActions/nanoflow-actions-native/* Native-Mobile-Resources-main/javascriptsource/nanoflowcommons/actions/ fi - name: "Build test project" - run: mxbuild -o automation.mda Native-Mobile-Resources-main/NativeComponentsTestProject.mpr + run: mxbuild -o automation.mda --loose-version-check Native-Mobile-Resources-main/NativeComponentsTestProject.mpr - name: "Upload MDA" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: mda path: automation.mda @@ -158,9 +158,9 @@ jobs: container: ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix-version }} steps: - name: "Check out code" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 - name: "Download deployment package" - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda - name: "Create Android bundle" @@ -174,9 +174,9 @@ jobs: container: ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix-version }} steps: - name: "Check out code" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 - name: "Download project MDA file" - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda - name: "Create iOS bundle" @@ -189,22 +189,22 @@ jobs: runs-on: ubuntu-22.04 steps: - name: "Check out Native Template for Native Components Test Project" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 with: repository: mendix/native-template ref: master path: native-template - name: "Check out code" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 with: path: native-widgets - name: "Download Android bundle and assets" - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: android-bundle path: bundles/android - name: "Set up Node" - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 with: node-version-file: native-template/.nvmrc cache: npm @@ -219,17 +219,17 @@ jobs: - name: "Install dependencies" working-directory: native-template run: npm i - - name: "Setup JDK 11" - uses: actions/setup-java@v3.10.0 + - name: "Setup JDK 17" + uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 with: - java-version: 11 + java-version: 17 distribution: temurin cache: gradle - name: "Build Android app" working-directory: native-template/android run: ./gradlew assembleAppstoreDebug assembleAppstoreDebugAndroidTest - name: "Archive Android app" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: android-app path: native-template/android/app/build/outputs/apk/**/*.apk @@ -238,22 +238,22 @@ jobs: runs-on: macos-12 steps: - name: "Check out Native Template for Native Components Test Project" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 with: repository: mendix/native-template ref: master path: native-template - name: "Check out code" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 with: path: native-widgets - name: "Download iOS bundle and assets" - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: ios-bundle path: bundles/ios - name: "Set up Node" - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 with: node-version-file: native-template/.nvmrc cache: npm @@ -269,7 +269,7 @@ jobs: run: npm i - name: "Setup Pods cache" - uses: actions/cache@v3.3.1 + uses: actions/cache@937d24475381cd9c75ae6db12cb4e79714b926ed # v2 with: path: native-template/Pods key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} @@ -282,7 +282,7 @@ jobs: working-directory: native-template/ios run: xcodebuild -workspace NativeTemplate.xcworkspace -scheme nativeTemplate -configuration Debug -sdk iphonesimulator -derivedDataPath build ONLY_ACTIVE_ARCH=YES VALID_ARCHS="i386 x86_64" - name: "Archive iOS app" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: ios-app path: native-template/ios/build/Build/Products/**/*.app @@ -290,9 +290,9 @@ jobs: runs-on: macos-12 steps: - name: "Check out code" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 - name: "Setup AVD cache" - uses: actions/cache@v3.3.1 + uses: actions/cache@937d24475381cd9c75ae6db12cb4e79714b926ed # v2 id: avd-cache with: path: | @@ -302,7 +302,7 @@ jobs: key: pixel_30_x86_64_default_3core_and_system_images - name: "Create AVD and generate snapshot for caching" if: steps.avd-cache.outputs.cache-hit != 'true' - uses: reactivecircus/android-emulator-runner@v2.27.0 + uses: reactivecircus/android-emulator-runner@6b0df4b0efb23bb0ec63d881db79aefbc976e4b2 # v2.30.1 with: api-level: 30 target: default @@ -321,18 +321,18 @@ jobs: runs-on: macos-12 steps: - name: "Check out code" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 with: fetch-depth: 0 - name: "Set up node" - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 with: node-version-file: .nvmrc cache: yarn - name: "Install dependencies" run: yarn install --immutable - name: "Download project MDA file" - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda - name: "Start runtime" @@ -341,7 +341,7 @@ jobs: mda-file: automation.mda mendix-version: ${{ needs.mendix-version.outputs.mendix-version }} - name: "Download Android app" - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: android-app path: android-app @@ -350,7 +350,7 @@ jobs: mkdir -p detox/apps find android-app -type f -iname "*.apk" -exec mv {} detox/apps/ \; - name: "Setup AVD cache" - uses: actions/cache@v3.3.1 + uses: actions/cache@937d24475381cd9c75ae6db12cb4e79714b926ed # v2 id: avd-cache with: path: | @@ -359,7 +359,7 @@ jobs: /Users/runner/Library/Android/sdk/system-images/**/* key: pixel_30_x86_64_default_3core_and_system_images - name: "Run tests" - uses: reactivecircus/android-emulator-runner@v2.27.0 + uses: reactivecircus/android-emulator-runner@6b0df4b0efb23bb0ec63d881db79aefbc976e4b2 # v2.30.1 with: api-level: 30 target: default @@ -381,14 +381,14 @@ jobs: adb shell pm install -r -g -t /data/local/tmp/detox/Test.apk 2>/dev/null yarn workspaces foreach ${{ needs.scope.outputs.scope }} run test:e2e:android - name: "Archive runtime logs" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: always() with: name: android-runtime-logs path: log/*.log if-no-files-found: ignore - name: "Archive test screenshot diff results" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: failure() with: name: android-screenshot-results @@ -397,7 +397,7 @@ jobs: ${{ github.workspace }}/packages/**/e2e/images/actual/**/*.png if-no-files-found: ignore - name: "Archive artifacts" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: always() with: name: android-artifacts @@ -408,18 +408,18 @@ jobs: runs-on: macos-12 steps: - name: "Check out code" - uses: actions/checkout@v3.4.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 with: fetch-depth: 0 - name: "Set up node" - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3 with: node-version-file: .nvmrc cache: yarn - name: "Install dependencies" run: yarn install --immutable - name: "Download project MDA file" - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda # Used when new xCode version of simulator should be created @@ -435,7 +435,7 @@ jobs: mda-file: automation.mda mendix-version: ${{ needs.mendix-version.outputs.mendix-version }} - name: "Download iOS app" - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: ios-app path: ios-app @@ -458,14 +458,14 @@ jobs: - name: "Run tests" run: yarn workspaces foreach ${{ needs.scope.outputs.scope }} run test:e2e:ios - name: "Archive runtime logs" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: always() with: name: ios-runtime-logs path: log/*.log if-no-files-found: ignore - name: "Archive test screenshot diff results" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: failure() with: name: ios-screenshot-results @@ -474,7 +474,7 @@ jobs: ${{ github.workspace }}/packages/**/e2e/images/actual/**/*.png if-no-files-found: ignore - name: "Archive artifacts" - uses: actions/upload-artifact@v3.1.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: always() with: name: ios-artifacts diff --git a/packages/jsActions/mobile-resources-native/CHANGELOG.md b/packages/jsActions/mobile-resources-native/CHANGELOG.md index 2b936acbb..65ddc642c 100644 --- a/packages/jsActions/mobile-resources-native/CHANGELOG.md +++ b/packages/jsActions/mobile-resources-native/CHANGELOG.md @@ -8,6 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Changed +- Added CheckGenericPermission and updated RequestGenericPermission to support SCHEDULE_EXACT_ALARM_ANDROID permission for Android (relevant for Android 14). + +### Changed + - fixed an Android issue in Download file action. ## [6.0.0] Native Mobile Resources - 2024-01-24 diff --git a/packages/jsActions/mobile-resources-native/package.json b/packages/jsActions/mobile-resources-native/package.json index c3af87247..0b94fad72 100644 --- a/packages/jsActions/mobile-resources-native/package.json +++ b/packages/jsActions/mobile-resources-native/package.json @@ -39,6 +39,7 @@ "react-native-localize": "1.4.2", "react-native-permissions": "3.3.1", "react-native-push-notification": "8.1.1", + "react-native-schedule-exact-alarm-permission": "^0.1.3", "react-native-sound": "0.11.0", "react-native-touch-id": "4.4.1", "url-parse": "^1.4.7" diff --git a/packages/jsActions/mobile-resources-native/src/permissions/CheckGenericPermission.ts b/packages/jsActions/mobile-resources-native/src/permissions/CheckGenericPermission.ts new file mode 100644 index 000000000..2fca380aa --- /dev/null +++ b/packages/jsActions/mobile-resources-native/src/permissions/CheckGenericPermission.ts @@ -0,0 +1,78 @@ +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +import { Platform, NativeModules } from "react-native"; +import { check, Permission, PERMISSIONS as RNPermissions } from "react-native-permissions"; +import { ANDROIDPermissionName, IOSPermissionName } from "../../typings/RequestGenericPermission"; + +// BEGIN EXTRA CODE + +const PERMISSIONS = { + ANDROID: { + ...RNPermissions.ANDROID, + SCHEDULE_EXACT_ALARM: "android.permission.SCHEDULE_EXACT_ALARM" + }, + IOS: RNPermissions.IOS +}; + +function mapPermissionName(permissionName: string): Permission | "android.permission.SCHEDULE_EXACT_ALARM" | undefined { + if (Platform.OS === "ios") { + const nameWithoutSuffix = permissionName.replace("_IOS", "") as IOSPermissionName; + + return PERMISSIONS.IOS[nameWithoutSuffix] as Permission; + } + + const nameWithoutSuffix = permissionName.replace("_ANDROID", "") as ANDROIDPermissionName; + + return PERMISSIONS.ANDROID[nameWithoutSuffix] as Permission; +} + +async function checkScheduleAlarm(): Promise<"granted" | "blocked"> { + if (NativeModules && !NativeModules.ScheduleEA) { + return Promise.reject(new Error("ScheduleEA module is not available in your app")); + } + + if (Platform.OS !== "android") { + return Promise.resolve("granted"); + } + + const checkPermissionPromise = new Promise(resolve => { + NativeModules.ScheduleEA.checkPermission((isEnabled: boolean) => { + resolve(isEnabled); + }); + }); + + return checkPermissionPromise.then(result => { + return Promise.resolve(result ? "granted" : "blocked"); + }); +} + +// END EXTRA CODE + +/** + * @param {"NanoflowCommons.Enum_Permissions.APP_TRACKING_TRANSPARENCY_IOS"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_PERIPHERAL_IOS"|"NanoflowCommons.Enum_Permissions.CAMERA_IOS"|"NanoflowCommons.Enum_Permissions.CALENDARS_IOS"|"NanoflowCommons.Enum_Permissions.CONTACTS_IOS"|"NanoflowCommons.Enum_Permissions.FACE_ID_IOS"|"NanoflowCommons.Enum_Permissions.LOCATION_ALWAYS_IOS"|"NanoflowCommons.Enum_Permissions.LOCATION_WHEN_IN_USE_IOS"|"NanoflowCommons.Enum_Permissions.MEDIA_LIBRARY_IOS"|"NanoflowCommons.Enum_Permissions.MICROPHONE_IOS"|"NanoflowCommons.Enum_Permissions.MOTION_IOS"|"NanoflowCommons.Enum_Permissions.PHOTO_LIBRARY_IOS"|"NanoflowCommons.Enum_Permissions.PHOTO_LIBRARY_ADD_ONLY_IOS"|"NanoflowCommons.Enum_Permissions.REMINDERS_IOS"|"NanoflowCommons.Enum_Permissions.SIRI_IOS"|"NanoflowCommons.Enum_Permissions.SPEECH_RECOGNITION_IOS"|"NanoflowCommons.Enum_Permissions.STOREKIT_IOS"|"NanoflowCommons.Enum_Permissions.ACCEPT_HANDOVER_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_BACKGROUND_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_COARSE_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_FINE_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_MEDIA_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACTIVITY_RECOGNITION_ANDROID"|"NanoflowCommons.Enum_Permissions.ADD_VOICEMAIL_ANDROID"|"NanoflowCommons.Enum_Permissions.ANSWER_PHONE_CALLS_ANDROID"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_ADVERTISE_ANDROID"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_CONNECT_ANDROID"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_SCAN_ANDROID"|"NanoflowCommons.Enum_Permissions.BODY_SENSORS_ANDROID"|"NanoflowCommons.Enum_Permissions.CALL_PHONE_ANDROID"|"NanoflowCommons.Enum_Permissions.CAMERA_ANDROID"|"NanoflowCommons.Enum_Permissions.GET_ACCOUNTS_ANDROID"|"NanoflowCommons.Enum_Permissions.PROCESS_OUTGOING_CALLS_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_CALENDAR_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_CALL_LOG_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_CONTACTS_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_EXTERNAL_STORAGE_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_PHONE_NUMBERS_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_PHONE_STATE_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_SMS_ANDROID"|"NanoflowCommons.Enum_Permissions.RECEIVE_MMS_ANDROID"|"NanoflowCommons.Enum_Permissions.RECEIVE_SMS_ANDROID"|"NanoflowCommons.Enum_Permissions.RECEIVE_WAP_PUSH_ANDROID"|"NanoflowCommons.Enum_Permissions.RECORD_AUDIO_ANDROID"|"NanoflowCommons.Enum_Permissions.SEND_SMS_ANDROID"|"NanoflowCommons.Enum_Permissions.USE_SIP_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_CALENDAR_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_CALL_LOG_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_CONTACTS_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_EXTERNAL_STORAGE_ANDROID"|"NanoflowCommons.Enum_Permissions.SCHEDULE_EXACT_ALARM_ANDROID"} permission - This field is required. + * @returns {Promise.<"NanoflowCommons.Enum_PermissionStatus.unavailable"|"NanoflowCommons.Enum_PermissionStatus.denied"|"NanoflowCommons.Enum_PermissionStatus.limited"|"NanoflowCommons.Enum_PermissionStatus.granted"|"NanoflowCommons.Enum_PermissionStatus.blocked">} + */ +export async function CheckGenericPermission( + permission?: string +): Promise<"unavailable" | "blocked" | "denied" | "granted" | "limited"> { + // BEGIN USER CODE + if (!permission) { + return Promise.reject(new Error("Input parameter 'permission' is required")); + } + const mappedPermissionName = mapPermissionName(permission); + + if (!mappedPermissionName) { + console.error(`${permission} permission is not found`); + return Promise.resolve("unavailable"); + } + + return mappedPermissionName === PERMISSIONS.ANDROID.SCHEDULE_EXACT_ALARM + ? checkScheduleAlarm() + : check(mappedPermissionName as Permission); + // END USER CODE +} diff --git a/packages/jsActions/mobile-resources-native/src/permissions/RequestGenericPermission.ts b/packages/jsActions/mobile-resources-native/src/permissions/RequestGenericPermission.ts index bea9c683d..83b2513a2 100644 --- a/packages/jsActions/mobile-resources-native/src/permissions/RequestGenericPermission.ts +++ b/packages/jsActions/mobile-resources-native/src/permissions/RequestGenericPermission.ts @@ -5,35 +5,80 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import { Alert, Platform } from "react-native"; -import { check, request, RESULTS, openSettings, PERMISSIONS, Permission } from "react-native-permissions"; +import { Alert, Platform, NativeModules } from "react-native"; +import { + check, + request, + RESULTS, + openSettings, + Permission, + PERMISSIONS as RNPermissions +} from "react-native-permissions"; +import { getPermission } from "react-native-schedule-exact-alarm-permission"; import { ANDROIDPermissionName, IOSPermissionName } from "../../typings/RequestGenericPermission"; // BEGIN EXTRA CODE +const PERMISSIONS = { + ANDROID: { + ...RNPermissions.ANDROID, + SCHEDULE_EXACT_ALARM: "android.permission.SCHEDULE_EXACT_ALARM" + }, + IOS: RNPermissions.IOS +}; + function handleBlockedPermission(permission: string): void { const permissionName = permission.replace(/_IOS|_ANDROID/, ""); - Alert.alert("", `Please allow ${permissionName} access`, [ - { text: "go to settings", onPress: () => openSettings() }, - { text: "cancel" } - ]); + + if (permissionName === "SCHEDULE_EXACT_ALARM") { + Alert.alert("", "Please allow setting alarms and reminders", [ + { text: "Go to alarm settings", onPress: () => getPermission(), isPreferred: true }, + { text: "Cancel", style: "cancel" } + ]); + } else { + Alert.alert("", `Please allow ${permissionName} access`, [ + { text: "Go to settings", onPress: () => openSettings(), isPreferred: true }, + { text: "Cancel", style: "cancel" } + ]); + } } -function mapPermissionName(permissionName: string): Permission | undefined { +function mapPermissionName(permissionName: string): Permission | "android.permission.SCHEDULE_EXACT_ALARM" | undefined { if (Platform.OS === "ios") { const nameWithoutSuffix = permissionName.replace("_IOS", "") as IOSPermissionName; - return PERMISSIONS.IOS[nameWithoutSuffix]; - } else if (Platform.OS === "android") { - const nameWithoutSuffix = permissionName.replace("_ANDROID", "") as ANDROIDPermissionName; + return PERMISSIONS.IOS[nameWithoutSuffix] as Permission; + } + + const nameWithoutSuffix = permissionName.replace("_ANDROID", "") as ANDROIDPermissionName; + + return PERMISSIONS.ANDROID[nameWithoutSuffix] as Permission; +} + +async function checkScheduleAlarm(): Promise<"granted" | "blocked"> { + if (NativeModules && !NativeModules.ScheduleEA) { + return Promise.reject(new Error("ScheduleEA module is not available in your app")); + } - return PERMISSIONS.ANDROID[nameWithoutSuffix]; + if (Platform.OS !== "android") { + return Promise.resolve("granted"); } + + const checkPermissionPromise = new Promise(resolve => { + NativeModules.ScheduleEA.checkPermission((isEnabled: boolean) => { + resolve(isEnabled); + }); + }); + + return checkPermissionPromise.then(result => { + return Promise.resolve(result ? "granted" : "blocked"); + }); } + // END EXTRA CODE /** - * @param {"NanoflowCommons.Enum_Permissions.APP_TRACKING_TRANSPARENCY_IOS"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_PERIPHERAL_IOS"|"NanoflowCommons.Enum_Permissions.CAMERA_IOS"|"NanoflowCommons.Enum_Permissions.CALENDARS_IOS"|"NanoflowCommons.Enum_Permissions.CONTACTS_IOS"|"NanoflowCommons.Enum_Permissions.FACE_ID_IOS"|"NanoflowCommons.Enum_Permissions.LOCATION_ALWAYS_IOS"|"NanoflowCommons.Enum_Permissions.LOCATION_WHEN_IN_USE_IOS"|"NanoflowCommons.Enum_Permissions.MEDIA_LIBRARY_IOS"|"NanoflowCommons.Enum_Permissions.MICROPHONE_IOS"|"NanoflowCommons.Enum_Permissions.MOTION_IOS"|"NanoflowCommons.Enum_Permissions.PHOTO_LIBRARY_IOS"|"NanoflowCommons.Enum_Permissions.PHOTO_LIBRARY_ADD_ONLY_IOS"|"NanoflowCommons.Enum_Permissions.REMINDERS_IOS"|"NanoflowCommons.Enum_Permissions.SIRI_IOS"|"NanoflowCommons.Enum_Permissions.SPEECH_RECOGNITION_IOS"|"NanoflowCommons.Enum_Permissions.STOREKIT_IOS"|"NanoflowCommons.Enum_Permissions.ACCEPT_HANDOVER_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_BACKGROUND_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_COARSE_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_FINE_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_MEDIA_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACTIVITY_RECOGNITION_ANDROID"|"NanoflowCommons.Enum_Permissions.ADD_VOICEMAIL_ANDROID"|"NanoflowCommons.Enum_Permissions.ANSWER_PHONE_CALLS_ANDROID"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_ADVERTISE_ANDROID"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_CONNECT_ANDROID"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_SCAN_ANDROID"|"NanoflowCommons.Enum_Permissions.BODY_SENSORS_ANDROID"|"NanoflowCommons.Enum_Permissions.CALL_PHONE_ANDROID"|"NanoflowCommons.Enum_Permissions.CAMERA_ANDROID"|"NanoflowCommons.Enum_Permissions.GET_ACCOUNTS_ANDROID"|"NanoflowCommons.Enum_Permissions.PROCESS_OUTGOING_CALLS_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_CALENDAR_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_CALL_LOG_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_CONTACTS_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_EXTERNAL_STORAGE_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_PHONE_NUMBERS_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_PHONE_STATE_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_SMS_ANDROID"|"NanoflowCommons.Enum_Permissions.RECEIVE_MMS_ANDROID"|"NanoflowCommons.Enum_Permissions.RECEIVE_SMS_ANDROID"|"NanoflowCommons.Enum_Permissions.RECEIVE_WAP_PUSH_ANDROID"|"NanoflowCommons.Enum_Permissions.RECORD_AUDIO_ANDROID"|"NanoflowCommons.Enum_Permissions.SEND_SMS_ANDROID"|"NanoflowCommons.Enum_Permissions.USE_SIP_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_CALENDAR_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_CALL_LOG_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_CONTACTS_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_EXTERNAL_STORAGE_ANDROID"} permission - This field is required. + * @param {"NanoflowCommons.Enum_Permissions.APP_TRACKING_TRANSPARENCY_IOS"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_PERIPHERAL_IOS"|"NanoflowCommons.Enum_Permissions.CAMERA_IOS"|"NanoflowCommons.Enum_Permissions.CALENDARS_IOS"|"NanoflowCommons.Enum_Permissions.CONTACTS_IOS"|"NanoflowCommons.Enum_Permissions.FACE_ID_IOS"|"NanoflowCommons.Enum_Permissions.LOCATION_ALWAYS_IOS"|"NanoflowCommons.Enum_Permissions.LOCATION_WHEN_IN_USE_IOS"|"NanoflowCommons.Enum_Permissions.MEDIA_LIBRARY_IOS"|"NanoflowCommons.Enum_Permissions.MICROPHONE_IOS"|"NanoflowCommons.Enum_Permissions.MOTION_IOS"|"NanoflowCommons.Enum_Permissions.PHOTO_LIBRARY_IOS"|"NanoflowCommons.Enum_Permissions.PHOTO_LIBRARY_ADD_ONLY_IOS"|"NanoflowCommons.Enum_Permissions.REMINDERS_IOS"|"NanoflowCommons.Enum_Permissions.SIRI_IOS"|"NanoflowCommons.Enum_Permissions.SPEECH_RECOGNITION_IOS"|"NanoflowCommons.Enum_Permissions.STOREKIT_IOS"|"NanoflowCommons.Enum_Permissions.ACCEPT_HANDOVER_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_BACKGROUND_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_COARSE_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_FINE_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACCESS_MEDIA_LOCATION_ANDROID"|"NanoflowCommons.Enum_Permissions.ACTIVITY_RECOGNITION_ANDROID"|"NanoflowCommons.Enum_Permissions.ADD_VOICEMAIL_ANDROID"|"NanoflowCommons.Enum_Permissions.ANSWER_PHONE_CALLS_ANDROID"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_ADVERTISE_ANDROID"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_CONNECT_ANDROID"|"NanoflowCommons.Enum_Permissions.BLUETOOTH_SCAN_ANDROID"|"NanoflowCommons.Enum_Permissions.BODY_SENSORS_ANDROID"|"NanoflowCommons.Enum_Permissions.CALL_PHONE_ANDROID"|"NanoflowCommons.Enum_Permissions.CAMERA_ANDROID"|"NanoflowCommons.Enum_Permissions.GET_ACCOUNTS_ANDROID"|"NanoflowCommons.Enum_Permissions.PROCESS_OUTGOING_CALLS_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_CALENDAR_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_CALL_LOG_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_CONTACTS_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_EXTERNAL_STORAGE_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_PHONE_NUMBERS_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_PHONE_STATE_ANDROID"|"NanoflowCommons.Enum_Permissions.READ_SMS_ANDROID"|"NanoflowCommons.Enum_Permissions.RECEIVE_MMS_ANDROID"|"NanoflowCommons.Enum_Permissions.RECEIVE_SMS_ANDROID"|"NanoflowCommons.Enum_Permissions.RECEIVE_WAP_PUSH_ANDROID"|"NanoflowCommons.Enum_Permissions.RECORD_AUDIO_ANDROID"|"NanoflowCommons.Enum_Permissions.SEND_SMS_ANDROID"|"NanoflowCommons.Enum_Permissions.USE_SIP_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_CALENDAR_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_CALL_LOG_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_CONTACTS_ANDROID"|"NanoflowCommons.Enum_Permissions.WRITE_EXTERNAL_STORAGE_ANDROID"|"NanoflowCommons.Enum_Permissions.SCHEDULE_EXACT_ALARM_ANDROID"} permission - This field is required. * @returns {Promise.<"NanoflowCommons.Enum_PermissionStatus.unavailable"|"NanoflowCommons.Enum_PermissionStatus.denied"|"NanoflowCommons.Enum_PermissionStatus.limited"|"NanoflowCommons.Enum_PermissionStatus.granted"|"NanoflowCommons.Enum_PermissionStatus.blocked">} */ export async function RequestGenericPermission( @@ -44,11 +89,16 @@ export async function RequestGenericPermission( return Promise.reject(new Error("Input parameter 'permission' is required")); } const mappedPermissionName = mapPermissionName(permission); + if (!mappedPermissionName) { console.error(`${permission} permission is not found`); return Promise.resolve("unavailable"); } - const permissionStatus = await check(mappedPermissionName); + + const permissionStatus = + mappedPermissionName === PERMISSIONS.ANDROID.SCHEDULE_EXACT_ALARM + ? await checkScheduleAlarm() + : await check(mappedPermissionName as Permission); switch (permissionStatus) { case RESULTS.GRANTED: @@ -59,7 +109,7 @@ export async function RequestGenericPermission( handleBlockedPermission(permission); return RESULTS.BLOCKED; case RESULTS.DENIED: - return request(mappedPermissionName); + return request(mappedPermissionName as Permission); } // END USER CODE } diff --git a/packages/jsActions/mobile-resources-native/typings/RequestGenericPermission.d.ts b/packages/jsActions/mobile-resources-native/typings/RequestGenericPermission.d.ts index dc3c60744..f9dd3868e 100644 --- a/packages/jsActions/mobile-resources-native/typings/RequestGenericPermission.d.ts +++ b/packages/jsActions/mobile-resources-native/typings/RequestGenericPermission.d.ts @@ -50,4 +50,5 @@ export type ANDROIDPermissionName = | "WRITE_CALENDAR" | "WRITE_CALL_LOG" | "WRITE_CONTACTS" - | "WRITE_EXTERNAL_STORAGE"; + | "WRITE_EXTERNAL_STORAGE" + | "SCHEDULE_EXACT_ALARM"; diff --git a/yarn.lock b/yarn.lock index 27a2fb805..e41bc4db0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12683,6 +12683,7 @@ __metadata: react-native-localize: 1.4.2 react-native-permissions: 3.3.1 react-native-push-notification: 8.1.1 + react-native-schedule-exact-alarm-permission: ^0.1.3 react-native-sound: 0.11.0 react-native-touch-id: 4.4.1 rimraf: ^2.7.1 @@ -14951,6 +14952,16 @@ __metadata: languageName: node linkType: hard +"react-native-schedule-exact-alarm-permission@npm:^0.1.3": + version: 0.1.4 + resolution: "react-native-schedule-exact-alarm-permission@npm:0.1.4" + peerDependencies: + react: "*" + react-native: "*" + checksum: cadb1c6d17588beab4532cde73eeb943f4bf1ebb08e9e52d3cd291d3674a6d9b84ec8a590b6ff24e4fd8b671e342a12cf81b35ef4d46e927cf321442340480ad + languageName: node + linkType: hard + "react-native-segmented-control-tab@npm:^3.4.0": version: 3.4.1 resolution: "react-native-segmented-control-tab@npm:3.4.1"