TP-0 | Merge branch 'master' of github.com:navi-medici/address-verification-app into feat/TP-42454

This commit is contained in:
Aman Chaturvedi
2023-10-25 22:58:42 +05:30
15 changed files with 332 additions and 19 deletions

View File

@@ -15,7 +15,7 @@ import * as Sentry from '@sentry/react-native';
import codePush from 'react-native-code-push';
import AsyncStorage from '@react-native-async-storage/async-storage';
import CodePush from 'react-native-code-push';
import store, { persistor } from './src/store/store';
import store, { persistor, RootState } from './src/store/store';
import { navigationRef } from './src/components/utlis/navigationUtlis';
import FullScreenLoader from './RN-UI-LIB/src/components/FullScreenLoader';
@@ -42,7 +42,7 @@ import { StorageKeys } from './src/types/storageKeys';
import dayJs from 'dayjs';
import { GlobalImageMap, hydrateGlobalImageMap } from './src/common/CachedImage';
import analytics from '@react-native-firebase/analytics';
import handleUpdatedConfigureValuesFromFirebase from './src/services/firebaseFetchAndUpdate.service';
import fetchUpdatedRemoteConfig from './src/services/firebaseFetchAndUpdate.service';
import { addClickstreamEvent } from './src/services/clickstreamEventService';
import ScreenshotBlocker from './src/components/utlis/ScreenshotBlocker';
@@ -130,6 +130,7 @@ function App() {
}, []);
React.useEffect(() => {
fetchUpdatedRemoteConfig();
askForPermissions();
const appStateChange = AppState.addEventListener('change', async (change) => {
handleAppStateChange(change);
@@ -144,7 +145,6 @@ function App() {
setIsGlobalDocumentMapLoaded(true);
})();
checkCodePushAndSync();
handleUpdatedConfigureValuesFromFirebase();
setForegroundTimeStampAndClickstream();
return () => {

View File

@@ -131,8 +131,8 @@ def reactNativeArchitectures() {
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
def VERSION_CODE = 94
def VERSION_NAME = "2.4.10"
def VERSION_CODE = 95
def VERSION_NAME = "2.5.0"
android {
ndkVersion rootProject.ext.ndkVersion

View File

@@ -100,6 +100,20 @@ public class DeviceUtilsModule extends ReactContextBaseJavaModule {
}
}
public String getAppIcon(String packageName) {
try {
Context context = RNContext.getApplicationContext();
PackageManager pm = context.getPackageManager();
ApplicationInfo appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
Uri imageUri = Uri.parse("android.resource://" + appInfo.packageName + "/drawable/" + appInfo.icon);
return imageUri.toString();
} catch (Exception e) {
return null;
}
}
@ReactMethod
public void getAllInstalledApp(Promise promise) {
try {
@@ -108,13 +122,26 @@ public class DeviceUtilsModule extends ReactContextBaseJavaModule {
List<ApplicationInfo> packages = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
JSONArray jsonArray = new JSONArray();
for (PackageInfo packageInfo : installedPackages) {
final PackageManager pm = RNContext.getApplicationContext().getPackageManager();
ApplicationInfo appsInstalled;
try {
appsInstalled = pm.getApplicationInfo( packageInfo.packageName, 0);
} catch (final PackageManager.NameNotFoundException e) {
appsInstalled = null;
}
final String applicationName = (String) (appsInstalled != null ? pm.getApplicationLabel(appsInstalled) : "(unknown)");
JSONObject mainObject = new JSONObject();
JSONObject appObject = new JSONObject();
appObject.put("appName", packageInfo.applicationInfo.processName);
appObject.put("firstInstallTime", packageInfo.firstInstallTime);
appObject.put("lastUpdateTime", packageInfo.lastUpdateTime);
mainObject.put("packageName", packageInfo.packageName);
mainObject.put("appDetails", appObject);
JSONObject appDetails = new JSONObject();
appDetails.put("appName",packageInfo.applicationInfo.processName);
appDetails.put("firstInstallTime", packageInfo.firstInstallTime);
appDetails.put("lastUpdateTime", packageInfo.lastUpdateTime);
appDetails.put("applicationName", applicationName);
appDetails.put("applicationIcon",getAppIcon(packageInfo.packageName));
mainObject.put("packageName", packageInfo.packageName);
mainObject.put("appDetails", appDetails);
jsonArray.put(mainObject);
}
promise.resolve(jsonArray.toString());
@@ -292,5 +319,4 @@ public class DeviceUtilsModule extends ReactContextBaseJavaModule {
}

View File

@@ -1,6 +1,6 @@
{
"name": "AV_APP",
"version": "2.4.10",
"version": "2.5.0",
"private": true,
"scripts": {
"android:dev": "yarn move:dev && react-native run-android",

View File

@@ -1,15 +1,22 @@
import React, { ReactNode, useCallback, useState } from 'react';
import { Linking } from 'react-native';
import { AppState, Linking } from 'react-native';
import { useSelector } from 'react-redux';
import { RootState } from '../store/store';
import { UninstallInformation } from '../reducer/metadataSlice';
import { getAppVersion } from '../components/utlis/commonFunctions';
import BlockerInstructions from './BlockerInstructions';
import { BLOCKER_SCREEN_DATA } from './Constants';
import { BLOCKER_SCREEN_DATA, CLICKSTREAM_EVENT_NAMES } from './Constants';
import { useAppDispatch, useAppSelector } from '../hooks';
import { setIsDeviceLocationEnabled } from '../reducer/foregroundServiceSlice';
import { toast } from '../../RN-UI-LIB/src/components/toast';
import { locationEnabled } from '../components/utlis/DeviceUtils';
import BlockerScreenApps from '@screens/permissions/BlockerScreenApps';
import handleBlacklistedAppsForBlockingCosmos, {
Apps,
BLACKLISTED_APPS_LIST,
} from '@services/blacklistedApps.service';
import { addClickstreamEvent } from '@services/clickstreamEventService';
import { setBlacklistedAppsInstalledData } from '@reducers/blacklistedAppsInstalledSlice';
interface IBlockerScreen {
children?: ReactNode;
@@ -32,6 +39,10 @@ const BlockerScreen = (props: IBlockerScreen) => {
return state.metadata?.forceUninstall;
});
const blacklistedAppsInstalled: Apps[] = useSelector((state: RootState) => {
return state?.blacklistAppsInstalled?.blacklistedAppsInstalled || [];
});
function compareSemverVersions(a: string, b: string) {
return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });
}
@@ -54,6 +65,22 @@ const BlockerScreen = (props: IBlockerScreen) => {
setForceReinstallData(undefined);
}, [JSON.stringify(forceUninstallData || {})]);
React.useEffect(() => {
handleBlacklistedAppsForBlockingCosmos().then((blacklistedAppsInstalled) =>
dispatch(
setBlacklistedAppsInstalledData({ blacklistedAppsInstalled: blacklistedAppsInstalled })
)
);
const appStateChange = AppState.addEventListener('change', async (change) => {
handleBlacklistedAppsForBlockingCosmos().then((blacklistedAppsInstalled) =>
dispatch(
setBlacklistedAppsInstalledData({ blacklistedAppsInstalled: blacklistedAppsInstalled })
)
);
});
return () => appStateChange.remove();
}, [BLACKLISTED_APPS_LIST]);
const handleDownloadNewApp = () => {
if (forceReinstallData?.reinstall_endpoint) {
openApkDownloadLink(forceReinstallData?.reinstall_endpoint);
@@ -126,6 +153,11 @@ const BlockerScreen = (props: IBlockerScreen) => {
);
}
if (blacklistedAppsInstalled?.length > 0) {
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_BLOCKER_SCREEN_LOADED_FOR_BLACKLISTED_APPS);
return <BlockerScreenApps blacklistedAppsInstalled={blacklistedAppsInstalled} />;
}
return <>{props.children}</>;
};

View File

@@ -638,6 +638,13 @@ export const CLICKSTREAM_EVENT_NAMES = {
name: 'FA_PERFORMANCE_DASHBOARD_BROKEN_PTP_CASES_LOAD',
description: 'Performance Dashboard Broken PTP Cases Load',
},
//Blocker Screen for blacklisted Apps
FA_BLOCKER_SCREEN_LOADED_FOR_BLACKLISTED_APPS: {
name: 'FA_BLOCKER_SCREEN_LOADED_FOR_BLACKLISTED_APPS',
description: 'Blocker screen loaded for blacklisted apps',
},
// Nearby Cases
FA_NEARBY_CASES_BUTTON_CLICKED: {
name: 'FA_NEARBY_CASES_BUTTON_CLICKED',

View File

@@ -45,6 +45,11 @@ import { GlobalImageMap } from './CachedImage';
import { get } from 'react-hook-form';
import { addClickstreamEvent } from '../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from './Constants';
import { setBlacklistedAppsInstalledData } from '@reducers/blacklistedAppsInstalledSlice';
import handleBlacklistedAppsForBlockingCosmos, { Apps } from '@services/blacklistedApps.service';
import fetchUpdatedRemoteConfig, {
FIREBASE_FETCH_TIMESTAMP,
} from '@services/firebaseFetchAndUpdate.service';
export enum FOREGROUND_TASKS {
GEOLOCATION = 'GEOLOCATION',
@@ -54,6 +59,7 @@ export enum FOREGROUND_TASKS {
UPDATE_AGENT_ACTIVENESS = 'UPDATE_AGENT_ACTIVENESS',
UPDATE_AGENT_ACTIVITY = 'UPDATE_AGENT_ACTIVITY',
DELETE_CACHE = 'DELETE_CACHE',
FETCH_DATA_FROM_FIREBASE = 'FETCH_DATA_FROM_FIREBASE',
}
interface ITrackingComponent {
@@ -106,6 +112,14 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
const userActivityonApp: string =
(await getItem(StorageKeys.USER_ACTIVITY_ON_APP)) || AgentActivity.LOW;
let blacklistedAppsInstalledOnDevice: Apps[] = [];
await handleBlacklistedAppsForBlockingCosmos().then((blacklistedAppsInstalled) => {
if (blacklistedAppsInstalled.length > 0) {
blacklistedAppsInstalledOnDevice = blacklistedAppsInstalled;
}
});
const geolocation: IGeolocationPayload = {
latitude: location.latitude,
longitude: location.longitude,
@@ -113,6 +127,7 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
timestamp: Date.now(),
isActiveOnApp: Boolean(isActiveOnApp),
userActivityOnApp: String(userActivityonApp),
blacklistedAppsInstalled: blacklistedAppsInstalledOnDevice,
};
dispatch(setDeviceGeolocationsBuffer(geolocation));
dispatch(sendLocationAndActivenessToServer([geolocation]));
@@ -289,6 +304,16 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
});
};
const handleFetchUpdatedDataFromFirebase = async () => {
const currentTimestamp: number = Date.now();
if (
FIREBASE_FETCH_TIMESTAMP &&
currentTimestamp - FIREBASE_FETCH_TIMESTAMP > 15 * MILLISECONDS_IN_A_MINUTE
) {
fetchUpdatedRemoteConfig();
}
};
const tasks: IForegroundTask[] = [
{
taskId: FOREGROUND_TASKS.TIME_SYNC,
@@ -320,6 +345,12 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
delay: DATA_SYNC_TIME_INTERVAL,
onLoop: true,
},
{
taskId: FOREGROUND_TASKS.FETCH_DATA_FROM_FIREBASE,
task: handleFetchUpdatedDataFromFirebase,
delay: 15 * MILLISECONDS_IN_A_MINUTE, // 15 minutes
onLoop: true,
},
];
if (!isTeamLead) {
@@ -374,6 +405,11 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_APP_FOREGROUND, { now });
handleGetCaseSyncStatus();
dispatch(getConfigData());
handleBlacklistedAppsForBlockingCosmos().then((blacklistedAppsInstalled) =>
dispatch(
setBlacklistedAppsInstalledData({ blacklistedAppsInstalled: blacklistedAppsInstalled })
)
);
CosmosForegroundService.start(tasks);
}
if (nextAppState === AppStates.BACKGROUND) {
@@ -392,6 +428,11 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
}
await handleGetCaseSyncStatus();
dispatch(getConfigData());
handleBlacklistedAppsForBlockingCosmos().then((blacklistedAppsInstalled) =>
dispatch(
setBlacklistedAppsInstalledData({ blacklistedAppsInstalled: blacklistedAppsInstalled })
)
);
if (!isTeamLead && LAST_SYNC_STATUS !== SyncStatus.FETCH_CASES) {
const updatedDetails: ISyncedCases = await fetchCasesToSync(referenceId);
if (updatedDetails?.cases?.length) {

View File

@@ -6,6 +6,7 @@ import {
} from '../reducer/foregroundServiceSlice';
import { logError } from '../components/utlis/errorUtils';
import { toast } from '../../RN-UI-LIB/src/components/toast';
import { Apps } from '@services/blacklistedApps.service';
export interface IGeolocationPayload {
latitude: number;
@@ -14,6 +15,7 @@ export interface IGeolocationPayload {
timestamp: number;
isActiveOnApp: boolean;
userActivityOnApp: string;
blacklistedAppsInstalled: Apps[];
}
export const sendLocationAndActivenessToServer =

View File

@@ -0,0 +1,21 @@
import { createSlice } from '@reduxjs/toolkit';
import handleBlacklistedAppsForBlockingCosmos, { Apps } from '@services/blacklistedApps.service';
const initialState = {
blacklistedAppsInstalled: [] as Apps[],
};
export const blacklistedAppsInstalledSlice = createSlice({
name: 'blacklistedAppsInstalled',
initialState,
reducers: {
setBlacklistedAppsInstalledData: (state, action) => {
const { blacklistedAppsInstalled } = action.payload;
state.blacklistedAppsInstalled = blacklistedAppsInstalled;
},
},
});
export const { setBlacklistedAppsInstalledData } = blacklistedAppsInstalledSlice.actions;
export default blacklistedAppsInstalledSlice.reducer;

View File

@@ -108,7 +108,9 @@ const AuthRouter = () => {
</BlockerScreen>
</TrackingComponent>
) : (
<UnProtectedRouter />
<BlockerScreen>
<UnProtectedRouter />
</BlockerScreen>
);
};

View File

@@ -0,0 +1,107 @@
import * as React from 'react';
import { View, StyleSheet, ScrollView, Image } from 'react-native';
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
import { COLORS } from '@rn-ui-lib/colors';
import PermissionImage from '@assets/images/PermissionImage';
import { Apps } from '@services/blacklistedApps.service';
import Text from '@rn-ui-lib/components/Text';
const BlockerScreenApps: React.FC<{ blacklistedAppsInstalled: Apps[] }> = ({
blacklistedAppsInstalled,
}) => {
return (
<View style={[GenericStyles.ph16, GenericStyles.pb4, styles.container]}>
<View style={[styles.imageContainer]}>
<PermissionImage />
</View>
<View>
<Text style={[GenericStyles.fontSize14, GenericStyles.mb4, styles.textDark]}>
Some installed apps are banned by Navi
</Text>
</View>
<View>
<Text style={[GenericStyles.fontSize12, styles.textLight]}>
Uninstall these apps for uninterrupted usage
</Text>
</View>
<ScrollView>
<View style={[styles.appsContainer]}>
{blacklistedAppsInstalled.map((app: Apps, index: number) => (
<View key={index}>
<View style={styles.appsListItem}>
<Image source={{ uri: app.applicationIcon }} style={styles.appIcon} />
<Text style={[styles.textDark, styles.appNameText]}>{app.applicationName}</Text>
</View>
{index < blacklistedAppsInstalled.length - 1 && (
<View style={[styles.horizontalLine]} />
)}
</View>
))}
</View>
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: 'column',
flex: 1,
backgroundColor: COLORS.BACKGROUND.PRIMARY,
},
imageContainer: {
marginLeft: 97,
marginTop: 40,
marginBottom: 37,
},
textDark: {
color: COLORS.TEXT.DARK,
fontWeight: '500',
},
textLight: {
color: COLORS.TEXT.LIGHT,
fontWeight: '400',
marginBottom: 14,
},
appsContainer: {
paddingHorizontal: 16,
paddingTop: 4,
borderRadius: 4,
marginBottom: 16,
backgroundColor: COLORS.BACKGROUND.SILVER_LIGHT,
},
appsListItem: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 8,
paddingVertical: 12,
},
appNameText: {
marginLeft: 8,
fontSize: 12,
},
appIcon: {
width: 35,
height: 35,
backgroundColor: COLORS.BACKGROUND.PRIMARY,
borderRadius: 20,
},
horizontalLine: {
backgroundColor: COLORS.BACKGROUND.SILVER_LIGHT_2,
width: '100%',
height: 1,
},
});
export default BlockerScreenApps;

View File

@@ -0,0 +1,68 @@
import { GenericType } from '@common/GenericTypes';
import { getAllInstalledApp } from '@components/utlis/DeviceUtils';
import { logError } from '@components/utlis/errorUtils';
export type Apps = {
packageName: string;
applicationName: string;
applicationIcon: string;
};
type deviceApps = {
packageName: string;
appDetails: deviceAppDetails;
};
type deviceAppDetails = {
applicationName: string;
applicationIcon: string;
};
export let BLACKLISTED_APPS_LIST: string[] = [];
let installedBlacklistedApps: Apps[] = [];
export const getBlacklistedAppsList = () => BLACKLISTED_APPS_LIST;
export const setBlacklistedAppsList = (blacklistedAppsString: string) => {
BLACKLISTED_APPS_LIST = blacklistedAppsString.split(',');
};
function getBlacklistAppsPresent(installedApps: Apps[], blacklistedApps: string[]) {
installedBlacklistedApps = [];
const blacklistedAppsSet = new Set(blacklistedApps);
for (const app of installedApps) {
if (blacklistedAppsSet.has(app.packageName)) {
installedBlacklistedApps.push({
packageName: app.packageName,
applicationName: app.applicationName,
applicationIcon: app.applicationIcon,
});
}
}
}
const handleBlacklistedAppsForBlockingCosmos = async () => {
const blacklistedApps = getBlacklistedAppsList();
return getAllInstalledApp()
.then((apps) => {
try {
const appsArray = JSON.parse(apps);
const installedApps = appsArray.map((app: deviceApps) => ({
packageName: app.packageName,
applicationName: app.appDetails.applicationName,
applicationIcon: app.appDetails.applicationIcon,
}));
getBlacklistAppsPresent(installedApps, blacklistedApps);
return installedBlacklistedApps;
} catch (error: GenericType) {
logError(error);
return [];
}
})
.catch((error) => {
logError(error);
return [];
});
};
export default handleBlacklistedAppsForBlockingCosmos;

View File

@@ -4,9 +4,11 @@ import {
setActivityTimeWindowHigh,
setActivityTimeWindowMedium,
} from '../common/AgentActivityConfigurableConstants';
import { setBlacklistedAppsList } from './blacklistedApps.service';
const FIREBASE_FETCH_TIME = 15 * 60;
async function handleUpdatedConfigureValuesFromFirebase() {
export let FIREBASE_FETCH_TIMESTAMP: number;
async function fetchUpdatedRemoteConfig() {
await remoteConfig().fetch(FIREBASE_FETCH_TIME); //15 minutes
remoteConfig()
.activate()
@@ -28,10 +30,13 @@ async function handleUpdatedConfigureValuesFromFirebase() {
const ACTIVITY_TIME_WINDOW_MEDIUM = remoteConfig()
.getValue('ACTIVITY_TIME_WINDOW_MEDIUM')
.asNumber();
const BLACKLISTED_APPS = remoteConfig().getValue('BLACKLISTED_APPS').asString();
setActivityTimeOnApp(ACTIVITY_TIME_ON_APP);
setActivityTimeWindowHigh(ACTIVITY_TIME_WINDOW_HIGH);
setActivityTimeWindowMedium(ACTIVITY_TIME_WINDOW_MEDIUM);
setBlacklistedAppsList(BLACKLISTED_APPS);
FIREBASE_FETCH_TIMESTAMP = Date.now();
});
}
export default handleUpdatedConfigureValuesFromFirebase;
export default fetchUpdatedRemoteConfig;

View File

@@ -31,6 +31,7 @@ import feedbackImagesSlice from '../reducer/feedbackImagesSlice';
import configSlice from '../reducer/configSlice';
import profileSlice from '../reducer/profileSlice';
import reporteesSlice from '../reducer/reporteesSlice';
import blacklistedAppsInstalledSlice from '@reducers/blacklistedAppsInstalledSlice';
import feedbackFiltersSlice from '@reducers/feedbackFiltersSlice';
import agentPerformanceSlice from '../reducer/agentPerformanceSlice';
@@ -54,6 +55,7 @@ const rootReducer = combineReducers({
config: configSlice,
profile: profileSlice,
reportees: reporteesSlice,
blacklistAppsInstalled: blacklistedAppsInstalledSlice,
feedbackFilters: feedbackFiltersSlice,
agentPerformance: agentPerformanceSlice,
});