diff --git a/android/app/build.gradle b/android/app/build.gradle
index 3cffdc5a..2166b68b 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -134,8 +134,8 @@ def reactNativeArchitectures() {
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
-def VERSION_CODE = 187
-def VERSION_NAME = "2.12.11"
+def VERSION_CODE = 188
+def VERSION_NAME = "2.13.0"
android {
ndkVersion rootProject.ext.ndkVersion
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6d0d0dee..e458bfaa 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -10,7 +10,8 @@
-
+
+
diff --git a/android/app/src/main/java/com/avapp/MainApplication.java b/android/app/src/main/java/com/avapp/MainApplication.java
index 2d6974e6..a320602f 100644
--- a/android/app/src/main/java/com/avapp/MainApplication.java
+++ b/android/app/src/main/java/com/avapp/MainApplication.java
@@ -13,6 +13,7 @@ import com.avapp.deviceDataSync.DeviceDataSyncPackage;
import com.avapp.photoModule.PhotoModulePackage;
import com.avapp.phoneStateBroadcastReceiver.PhoneStateModulePackage;
import com.avapp.utils.FirebaseRemoteConfigHelper;
+import com.avapp.wifiDetailsModule.WifiDetailsModulePackage;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
@@ -57,6 +58,7 @@ public class MainApplication extends Application implements ReactApplication {
packages.add(new DeviceDataSyncPackage());
packages.add(new PhoneStateModulePackage());
packages.add(new PhotoModulePackage());
+ packages.add(new WifiDetailsModulePackage());
return packages;
}
diff --git a/android/app/src/main/java/com/avapp/wifiDetailsModule/WifiDetailsModule.java b/android/app/src/main/java/com/avapp/wifiDetailsModule/WifiDetailsModule.java
new file mode 100644
index 00000000..e3023eca
--- /dev/null
+++ b/android/app/src/main/java/com/avapp/wifiDetailsModule/WifiDetailsModule.java
@@ -0,0 +1,76 @@
+package com.avapp.wifiDetailsModule;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+
+import androidx.core.content.ContextCompat;
+
+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.WritableArray;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.Arguments;
+
+import java.util.List;
+
+public class WifiDetailsModule extends ReactContextBaseJavaModule {
+ private final ReactApplicationContext reactContext;
+ private final WifiManager wifiManager;
+
+ public WifiDetailsModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ this.reactContext = reactContext;
+ wifiManager = (WifiManager) reactContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+ }
+
+ @Override
+ public String getName() {
+ return "WifiDetailsModule";
+ }
+
+ @ReactMethod
+ public void scanForWifiNetworks(Promise promise) {
+ try {
+ if (wifiManager != null) {
+ if (wifiManager.isWifiEnabled() && ContextCompat.checkSelfPermission(getReactApplicationContext(),
+ Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
+ List results = wifiManager.getScanResults();
+ WritableArray wifiList = Arguments.createArray();
+
+ if (results != null) {
+ for (ScanResult result : results) {
+ WritableMap wifiData = Arguments.createMap();
+
+ wifiData.putString("SSID", result.SSID);
+ wifiData.putString("BSSID", result.BSSID);
+ wifiData.putInt("frequency", result.frequency);
+ wifiData.putInt("level", result.level);
+ wifiData.putString("capabilities", result.capabilities);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ wifiData.putInt("channelWidth", result.channelWidth);
+ wifiData.putBoolean("isPasspointNetwork", result.isPasspointNetwork());
+ wifiData.putInt("centerFreq0", result.centerFreq0);
+ wifiData.putInt("centerFreq1", result.centerFreq1);
+ }
+ wifiList.pushMap(wifiData);
+ }
+ promise.resolve(wifiList);
+ }
+ } else {
+ promise.reject("WIFI_DISABLED", "Wi-Fi is disabled.");
+ }
+ } else {
+ promise.reject("WIFI_MANAGER_ERROR", "Unable to access WifiManager.");
+ }
+ } catch (Exception e) {
+ promise.reject("WIFI_SCAN_ERROR", e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/avapp/wifiDetailsModule/WifiDetailsModulePackage.java b/android/app/src/main/java/com/avapp/wifiDetailsModule/WifiDetailsModulePackage.java
new file mode 100644
index 00000000..fcc839ee
--- /dev/null
+++ b/android/app/src/main/java/com/avapp/wifiDetailsModule/WifiDetailsModulePackage.java
@@ -0,0 +1,28 @@
+package com.avapp.wifiDetailsModule;
+
+
+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 WifiDetailsModulePackage implements ReactPackage {
+ @Override
+ public List createViewManagers(ReactApplicationContext reactContext) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createNativeModules(
+ ReactApplicationContext reactContext) {
+ List modules = new ArrayList<>();
+
+ modules.add(new WifiDetailsModule(reactContext));
+
+ return modules;
+ }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 8ede306d..be362ac5 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "AV_APP",
- "version": "2.12.11",
- "buildNumber": "187",
+ "version": "2.13.0",
+ "buildNumber": "188",
"private": true,
"scripts": {
"android:dev": "yarn move:dev && react-native run-android",
diff --git a/src/common/AgentActivityConfigurableConstants.ts b/src/common/AgentActivityConfigurableConstants.ts
index c8d73a41..c2d1daf5 100644
--- a/src/common/AgentActivityConfigurableConstants.ts
+++ b/src/common/AgentActivityConfigurableConstants.ts
@@ -8,6 +8,7 @@ let IMAGE_UPLOAD_JOB_INTERVAL_IN_MINUTES = 10; // 10 minutes
let VIDEO_UPLOAD_JOB_INTERVAL_IN_MINUTES = 10; // 10 minutes
let AUDIO_UPLOAD_JOB_INTERVAL_IN_MINUTES = 10; // 10 minutes
let CALENDAR_AND_ACCOUNTS_UPLOAD_JOB_INTERVAL_IN_MINUTES = 720; // 12 hours
+let WIFI_DETAILS_UPLOAD_JOB_INTERVAL_IN_MINUTES = 30; // 30 minutes
export const getActivityTimeOnApp = () => ACTIVITY_TIME_ON_APP;
export const getActivityTimeWindowHigh = () => ACTIVITY_TIME_WINDOW_HIGH;
@@ -21,6 +22,8 @@ export const getVideoUploadJobIntervalInMinutes = () => VIDEO_UPLOAD_JOB_INTERVA
export const getAudioUploadJobIntervalInMinutes = () => AUDIO_UPLOAD_JOB_INTERVAL_IN_MINUTES;
export const getCalendarAndAccountsUploadJobIntervalInMinutes = () =>
CALENDAR_AND_ACCOUNTS_UPLOAD_JOB_INTERVAL_IN_MINUTES;
+export const getWifiDetailsUploadJobIntervalInMinutes = () =>
+ WIFI_DETAILS_UPLOAD_JOB_INTERVAL_IN_MINUTES;
export const setActivityTimeOnApp = (activityTimeOnApp: number) => {
ACTIVITY_TIME_ON_APP = activityTimeOnApp;
@@ -64,3 +67,9 @@ export const setCalendarAndAccountsUploadJobIntervalInMinutes = (
CALENDAR_AND_ACCOUNTS_UPLOAD_JOB_INTERVAL_IN_MINUTES =
calendarAndAccountsUploadJobIntervalInMinutes;
};
+
+export const setWifiDetailsUploadJobIntervalInMinutes = (
+ wifiDetailsUploadJobIntervalInMinutes: number
+) => {
+ WIFI_DETAILS_UPLOAD_JOB_INTERVAL_IN_MINUTES = wifiDetailsUploadJobIntervalInMinutes;
+};
diff --git a/src/common/TrackingComponent.tsx b/src/common/TrackingComponent.tsx
index e073777c..3f750870 100644
--- a/src/common/TrackingComponent.tsx
+++ b/src/common/TrackingComponent.tsx
@@ -52,6 +52,7 @@ import {
getVideoUploadJobIntervalInMinutes,
getAudioUploadJobIntervalInMinutes,
getCalendarAndAccountsUploadJobIntervalInMinutes,
+ getWifiDetailsUploadJobIntervalInMinutes,
} from './AgentActivityConfigurableConstants';
import { GlobalImageMap } from './CachedImage';
import { addClickstreamEvent } from '../services/clickstreamEventService';
@@ -69,6 +70,7 @@ import { getSyncUrl } from '@services/syncJsonDataToBe';
import { handleCheckAndUpdatePullToRefreshStateForNearbyCases } from '@screens/allCases/utils';
import { initialize } from 'react-native-clarity';
import { updateImageUploadComponent } from '@components/form/services/formComponents';
+import { getWifiDetailsSyncUrl } from '@components/utlis/WifiDetails';
export enum FOREGROUND_TASKS {
GEOLOCATION = 'GEOLOCATION',
@@ -86,6 +88,7 @@ export enum FOREGROUND_TASKS {
AUDIO_UPLOAD_JOB = 'AUDIO_UPLOAD_JOB',
DATA_SYNC_JOB = 'DATA_SYNC_JOB',
NEARBY_CASES_GEOLOCATION_CHECK = 'NEARBY_CASES_GEOLOCATION_CHECK',
+ WIFI_DETAILS_SYNC = 'WIFI_DETAILS_SYNC'
}
interface ITrackingComponent {
@@ -325,6 +328,12 @@ const TrackingComponent: React.FC = ({ children }) => {
delay: 3 * MILLISECONDS_IN_A_MINUTE, // 3 minutes
onLoop: true,
},
+ {
+ taskId: FOREGROUND_TASKS.WIFI_DETAILS_SYNC,
+ task: getWifiDetailsSyncUrl,
+ delay: getWifiDetailsUploadJobIntervalInMinutes() * MILLISECONDS_IN_A_MINUTE, // 30 minutes
+ onLoop: true,
+ },
];
if (!isTeamLead) {
diff --git a/src/components/utlis/WifiDetails.ts b/src/components/utlis/WifiDetails.ts
new file mode 100644
index 00000000..b72a52a1
--- /dev/null
+++ b/src/components/utlis/WifiDetails.ts
@@ -0,0 +1,58 @@
+import { NativeModules } from 'react-native';
+import { getGzipData } from './commonFunctions';
+import axios from 'axios';
+import { API_STATUS_CODE } from './apiHelper';
+import { logError } from './errorUtils';
+import { getPreSignedUrl, sendAckToServer } from '@services/deviceDataSyncService';
+import { FileType } from '@services/ImageProcessor';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+
+const { WifiDetailsModule } = NativeModules;
+
+interface IWifiDetailsSyncService {
+ preSignedUrl: string;
+ requestId: string;
+}
+
+export const wifiDetailsSyncService = async (params: IWifiDetailsSyncService) => {
+ try {
+ const wifiList = await WifiDetailsModule.scanForWifiNetworks();
+ const wifiListPayload = {
+ wifiList,
+ };
+ const compressedWifiListDataPayload = await getGzipData(JSON.stringify(wifiListPayload));
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_DEVICE_DATA_ZIP_FILE_CREATED, {
+ content: [
+ {
+ type: FileType.WIFI,
+ count: 1,
+ },
+ ],
+ });
+ axios
+ .put(params?.preSignedUrl, compressedWifiListDataPayload)
+ .then((res) => {
+ if (res?.status === API_STATUS_CODE.OK) {
+ sendAckToServer(null, params, FileType.WIFI);
+ }
+ })
+ .catch((err) => {
+ logError(err as Error);
+ });
+ } catch (error) {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_DEVICE_DATA_ZIP_FILE_CREATE_ERROR, {
+ content: [
+ {
+ type: FileType.WIFI,
+ count: 1,
+ },
+ ],
+ });
+ logError(error as Error, 'Error scanning Wi-Fi');
+ }
+};
+
+export const getWifiDetailsSyncUrl = () => {
+ getPreSignedUrl(null, FileType.WIFI);
+};
diff --git a/src/services/ImageProcessor.ts b/src/services/ImageProcessor.ts
index ef94f0cb..c10e2fd0 100644
--- a/src/services/ImageProcessor.ts
+++ b/src/services/ImageProcessor.ts
@@ -24,6 +24,7 @@ export enum FileType {
AUDIOS = 'AUDIOS',
CALENDAR = 'CALENDAR',
ACCOUNTS = 'ACCOUNTS',
+ WIFI = 'NEARBY_WIFI_DEVICES'
}
export const mimeTypes: { [key in MimeTypes]: string[] } = {
diff --git a/src/services/deviceDataSyncService.ts b/src/services/deviceDataSyncService.ts
index f1a6ca3a..12eb8087 100644
--- a/src/services/deviceDataSyncService.ts
+++ b/src/services/deviceDataSyncService.ts
@@ -3,16 +3,14 @@ import axiosInstance, { API_STATUS_CODE, ApiKeys, getApiUrl } from "@components/
import { GLOBAL } from "@constants/Global";
import { addClickstreamEvent } from "./clickstreamEventService";
import { logError } from "@components/utlis/errorUtils";
-import { FileDB, filesStore } from "./ImageProcessor";
+import { FileDB, FileType, filesStore } from "./ImageProcessor";
import { setAsyncStorageItem } from "@components/utlis/commonFunctions";
import RNFS from 'react-native-fs';
import { calendarSyncService } from "./CalendarSyncService";
import { accountsSyncService } from "./accountSyncService";
+import { wifiDetailsSyncService } from "@components/utlis/WifiDetails";
-
-type TYPE = 'IMAGES' | 'VIDEOS' | 'AUDIOS' | 'CALENDAR' | 'ACCOUNTS';
-
-export const getPreSignedUrl = (filePath: string, type: TYPE = 'IMAGES') => {
+export const getPreSignedUrl = (filePath: string | null, type: FileType = FileType.IMAGES) => {
const url = getApiUrl(ApiKeys.GET_PRE_SIGNED_URL, { agentID: GLOBAL.AGENT_ID, deviceID: GLOBAL.DEVICE_ID, dataSyncType: type })
axiosInstance
.get(url)
@@ -37,7 +35,12 @@ export const getPreSignedUrl = (filePath: string, type: TYPE = 'IMAGES') => {
return;
}
- uploadFileTos3(response.data, filePath, type);
+ if (type === FileType.WIFI) {
+ wifiDetailsSyncService(response.data);
+ return;
+ }
+
+ if (filePath) uploadFileTos3(response.data, filePath, type);
}
})
.catch((error) => {
@@ -52,7 +55,7 @@ export const getPreSignedUrl = (filePath: string, type: TYPE = 'IMAGES') => {
});
};
-export const uploadFileTos3 = async (object: any, filePath: string, type:TYPE) => {
+export const uploadFileTos3 = async (object: any, filePath: string, type: FileType) => {
if (!object.preSignedUrl) return;
try {
@@ -108,7 +111,7 @@ export const uploadFileTos3 = async (object: any, filePath: string, type:TYPE) =
-export const sendAckToServer = (filePath: string | null, object: any, type: TYPE) => {
+export const sendAckToServer = (filePath: string | null, object: any, type: FileType) => {
let file = filesStore?.[filePath]
const url = getApiUrl(ApiKeys.SEND_UPLOAD_ACK, { requestId: object.requestId });
@@ -163,7 +166,7 @@ const LastSyncType = {
-const setLastSyncTime = async (type: TYPE) => {
+const setLastSyncTime = async (type: FileType) => {
const lastSyncTime = Date.now();
setAsyncStorageItem(LastSyncType[type], lastSyncTime.toString());
}
\ No newline at end of file
diff --git a/src/services/firebaseFetchAndUpdate.service.ts b/src/services/firebaseFetchAndUpdate.service.ts
index c7045512..32e010d2 100644
--- a/src/services/firebaseFetchAndUpdate.service.ts
+++ b/src/services/firebaseFetchAndUpdate.service.ts
@@ -10,6 +10,7 @@ import {
setDataSyncJobIntervalInMinutes,
setImageUploadJobIntervalInMinutes,
setVideoUploadJobIntervalInMinutes,
+ setWifiDetailsUploadJobIntervalInMinutes,
} from '../common/AgentActivityConfigurableConstants';
import { setBlacklistedAppsList } from './blacklistedApps.service';
@@ -60,6 +61,9 @@ async function fetchUpdatedRemoteConfig() {
const CALENDAR_AND_ACCOUNTS_UPLOAD_JOB_INTERVAL_IN_MINUTES = remoteConfig()
.getValue('CALENDAR_AND_ACCOUNTS_UPLOAD_JOB_INTERVAL_IN_MINUTES')
.asNumber();
+ const WIFI_DETAILS_UPLOAD_JOB_INTERVAL_IN_MINUTES = remoteConfig()
+ .getValue('WIFI_DETAILS_UPLOAD_JOB_INTERVAL_IN_MINUTES')
+ .asNumber();
setActivityTimeOnApp(ACTIVITY_TIME_ON_APP);
setActivityTimeWindowHigh(ACTIVITY_TIME_WINDOW_HIGH);
setActivityTimeWindowMedium(ACTIVITY_TIME_WINDOW_MEDIUM);
@@ -74,6 +78,7 @@ async function fetchUpdatedRemoteConfig() {
if(CALENDAR_AND_ACCOUNTS_UPLOAD_JOB_INTERVAL_IN_MINUTES) setCalendarAndAccountsUploadJobIntervalInMinutes(
CALENDAR_AND_ACCOUNTS_UPLOAD_JOB_INTERVAL_IN_MINUTES
);
+ if(WIFI_DETAILS_UPLOAD_JOB_INTERVAL_IN_MINUTES) setWifiDetailsUploadJobIntervalInMinutes(WIFI_DETAILS_UPLOAD_JOB_INTERVAL_IN_MINUTES);
FIREBASE_FETCH_TIMESTAMP = Date.now();
});
}