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

Android intent to share VC data with ODK #279

Closed
wants to merge 16 commits into from
Closed
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
20 changes: 10 additions & 10 deletions .github/workflows/ui-automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-

- name: Install npm dependencies
run: |
npm ci
Expand All @@ -76,12 +76,12 @@ jobs:
RELEASE_KEYSTORE_ALIAS: 'androidreleasekey'
RELEASE_KEYSTORE_PASSWORD: "${{ secrets.INJI_ANDROID_RELEASE_STOREPASS }}"

- name: Configure AWS CLI
- name: Configure AWS CLI
run: |
aws configure set aws_access_key_id ${{ secrets.AWS_DEVICE_FARM_ACCESS_KEY }}
aws configure set aws_secret_access_key ${{ secrets.AWS_DEVICE_FARM_SECRET_KEY }}
aws configure set region us-west-2

- name: Android - Automation
id: android-run
run: |
Expand All @@ -92,17 +92,17 @@ jobs:
TEST_TYPE: ${{ github.event.inputs.testType }}

- name: Download Android Artifacts
run: |
run: |
cd injitest/scripts/ui_automation
./download_artifacts.sh "$RUN_ARN" "Android"

- name: Upload Artifact to Actions
uses: actions/[email protected]
with:
name: Android-Artifacts
path: injitest/scripts/ui_automation/artifacts/android_artifacts/
retention-days: 10

# - name: Update slack channel
# if: always()
# uses: 8398a7/action-slack@v3
Expand Down Expand Up @@ -130,7 +130,7 @@ jobs:
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-

- name: Install npm dependencies
run: |
npm ci
Expand All @@ -139,7 +139,7 @@ jobs:
run: |
cd ios
pod install && pod install
fastlane ios_ui_automation_build
fastlane ios_ui_automation_build
env:
MIMOTO_HOST: ${{ github.event.inputs.backendServiceUrl }}
ESIGNET_HOST: ${{ github.event.inputs.backendServiceUrl }}
Expand All @@ -154,7 +154,7 @@ jobs:
APPLE_KEY_CONTENT: '${{ secrets.APPLE_KEY_CONTENT }}'
MATCH_PASSWORD: '${{ secrets.INJI_IOS_MATCH_PASSWORD }}'

- name: Configure AWS CLI
- name: Configure AWS CLI
run: |
aws configure set aws_access_key_id ${{ secrets.AWS_DEVICE_FARM_ACCESS_KEY }}
aws configure set aws_secret_access_key ${{ secrets.AWS_DEVICE_FARM_SECRET_KEY }}
Expand All @@ -169,7 +169,7 @@ jobs:
TEST_TYPE: ${{ github.event.inputs.testType }}

- name: Download IOS Artifacts
run: |
run: |
cd injitest/scripts/ui_automation
./download_artifacts.sh "$RUN_ARN" "IOS"

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,4 @@ To learn more about React Native, take a look at the following resources:
- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**.
- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts.
- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native.

85 changes: 50 additions & 35 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,46 +1,61 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.mosip.residentapp" xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.mosip.residentapp"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<queries>
<intent>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
</queries>
<application tools:replace="usesCleartextTraffic" android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme" android:usesCleartextTraffic="false">
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="48.0.0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@anonymous/inji"/>
<activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|locale|layoutDirection" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:screenOrientation="portrait">
<application tools:replace="usesCleartextTraffic" android:name=".MainApplication"
android:label="@string/app_name" android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false"
android:theme="@style/AppTheme" android:usesCleartextTraffic="false">
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true" />
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="48.0.0" />
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH"
android:value="ALWAYS" />
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0" />
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL"
android:value="https://exp.host/@anonymous/inji" />
<activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|locale|layoutDirection"
android:launchMode="singleTask" android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.App.SplashScreen" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="io.mosip.residentapp"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="io.mosip.residentapp" />
</intent-filter>
<intent-filter>
<action android:name="io.mosip.residentapp.odk.REQUEST" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new ODKIntentPackage());
return packages;
}

Expand All @@ -53,7 +53,7 @@ protected boolean isNewArchEnabled() {
@Override
protected Boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED;
}
}
});

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.mosip.residentapp;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;

public class ODKIntentModule extends ReactContextBaseJavaModule {

@Override
public String getName() {
return "ODKIntentModule";
}

ODKIntentModule(ReactApplicationContext context) {
super(context);
}

@ReactMethod
public void isRequestIntent(Promise promise) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's return type should be Promise ?

Activity activity = getCurrentActivity();
Intent intent = activity.getIntent();

String action = intent.getAction();
if (action == "io.mosip.residentapp.odk.REQUEST") {
promise.resolve(true);
} else {
promise.resolve(false);
}
}

@ReactMethod
public void sendBundleResult(ReadableMap vcData) {
Activity activity = getCurrentActivity();

Intent result = new Intent();
Bundle vcBundle = new Bundle(Arguments.toBundle(vcData));
for (String key : vcBundle.keySet()) {
result.putExtra(key, vcBundle.getString(key));
}

activity.setResult(Activity.RESULT_OK, result);
activity.finish();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.mosip.residentapp;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ODKIntentPackage implements ReactPackage {

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}

@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();

modules.add(new ODKIntentModule(reactContext));

return modules;
}
}
22 changes: 22 additions & 0 deletions lib/react-native-odk-intent/ODKIntentModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { NativeModules } from 'react-native';
const { ODKIntentModule } = NativeModules;

export enum ODKIntentVcField {
UIN = 'uin',
FullName = 'full_name',
DateOfBirth = 'date_of_birth',
Email = 'email',
Phone = 'phone',
Biometrics = 'biometrics',
Issuer = 'issuer',
IssuanceDate = 'issuance_date',
}

export type ODKIntentVcData = Record<ODKIntentVcField, string>;

interface ODKIntentInterface {
isRequestIntent: () => Promise<boolean>;
sendBundleResult: (vcData: ODKIntentVcData) => void;
}

export default ODKIntentModule as ODKIntentInterface;
32 changes: 30 additions & 2 deletions machines/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,16 @@ import {
createBackupRestoreMachine,
} from './backupRestore';

import ODKIntentModule from '../lib/react-native-odk-intent/ODKIntentModule';

const model = createModel(
{
info: {} as AppInfo,
serviceRefs: {} as AppServices,
isReadError: false,
isDecryptError: false,
isKeyInvalidateError: false,
isRequestIntent: false,
},
{
events: {
Expand Down Expand Up @@ -69,6 +72,9 @@ export const appMachine = model.createMachine(
schema: {
context: model.initialContext,
events: {} as EventFrom<typeof model>,
services: {} as {
checkIntent: {data: boolean};
},
},
id: 'app',
initial: 'init',
Expand All @@ -90,8 +96,17 @@ export const appMachine = model.createMachine(
},
states: {
init: {
initial: 'store',
initial: 'intent',
states: {
intent: {
invoke: {
src: 'checkIntent',
onDone: {
target: 'store',
actions: 'setIntent',
},
},
},
store: {
entry: ['spawnStoreActor', 'logStoreEvents'],
on: {
Expand Down Expand Up @@ -196,6 +211,10 @@ export const appMachine = model.createMachine(
},
{
actions: {
setIntent: assign({
isRequestIntent: (_context, event) => event.data,
}),

forwardToServices: pure((context, event) =>
Object.values(context.serviceRefs).map(serviceRef =>
send({...event, type: `APP_${event.type}`}, {to: serviceRef}),
Expand Down Expand Up @@ -287,7 +306,7 @@ export const appMachine = model.createMachine(

if (isAndroid()) {
serviceRefs.request = spawn(
createRequestMachine(serviceRefs),
createRequestMachine(serviceRefs, context.isRequestIntent),
requestMachine.id,
);
}
Expand Down Expand Up @@ -352,6 +371,10 @@ export const appMachine = model.createMachine(
},

services: {
checkIntent: () => {
return ODKIntentModule.isRequestIntent();
},

getAppInfo: () => async callback => {
const appInfo = {
deviceId: getDeviceId(),
Expand Down Expand Up @@ -416,6 +439,11 @@ type State = StateFrom<typeof appMachine>;
export function selectAppInfo(state: State) {
return state.context.info;
}

export function selectIsRequestIntent(state: State) {
return state.context.isRequestIntent; // TODO: change to state 'ready.intent.request'
}

export function selectIsReady(state: State) {
return state.matches('ready');
}
Expand Down
Loading
Loading