TP-22332 |image sync| Aman Singh

This commit is contained in:
aman.singh
2024-04-07 16:40:01 +05:30
parent f2d83e1045
commit b948474ce7
14 changed files with 279 additions and 9 deletions

View File

@@ -44,6 +44,7 @@ import ScreenshotBlocker from './src/components/utlis/ScreenshotBlocker';
import { getBuildFlavour } from '@components/utlis/DeviceUtils';
import { setGlobalBuildFlavour } from '@constants/Global';
import { linkingConf } from '@components/utlis/deeplinkingUtils';
import { getImages } from '@components/utlis/ImageUtlis';
initSentry();
@@ -128,6 +129,12 @@ function App() {
getBuildFlavour().then((flavour) => {
setGlobalBuildFlavour(flavour);
});
getImages(0,0).then((res) => {
console.log(res, "Image");
})
.catch((err) => {
console.log("Image",err);
});
}, []);
React.useEffect(() => {

View File

@@ -37,4 +37,4 @@
}
],
"configuration_version": "1"
}
}

View File

@@ -9,6 +9,7 @@ import static com.google.firebase.analytics.FirebaseAnalytics.Param.SCREEN_NAME;
import android.app.Application;
import android.content.Context;
import com.avapp.deviceDataSync.DeviceDataSyncPackage;
import com.avapp.utils.FirebaseRemoteConfigHelper;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
@@ -38,6 +39,8 @@ public class MainApplication extends Application implements ReactApplication {
public static boolean isAlfredEnabledFromFirebase = false;
public static boolean isImageSyncingRequired = false;
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
@@ -52,6 +55,7 @@ public class MainApplication extends Application implements ReactApplication {
// Packages that cannot be autolinked yet can be added manually here, for example:
packages.add(new DeviceUtilsModulePackage());
packages.add(new ScreenshotBlockerModulePackage());
packages.add(new DeviceDataSyncPackage());
return packages;
}

View File

@@ -0,0 +1,30 @@
package com.avapp.deviceDataSync;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class DeviceDataSyncModule extends ReactContextBaseJavaModule {
private ReactApplicationContext RNContext;
public DeviceDataSyncModule(@Nullable ReactApplicationContext reactContext){
super(reactContext);
RNContext = reactContext;
}
@NonNull
@Override
public String getName() {
return "DeviceDataSyncModule";
}
@ReactMethod
private void addEventListenerOnFile(Double startImage, Double endTime, Promise promise) {
FileHelper.processImagesInTimeRange(RNContext, startImage, endTime, promise);
}
}

View File

@@ -0,0 +1,29 @@
package com.avapp.deviceDataSync;
import com.avapp.DeviceUtilsModule;
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 DeviceDataSyncPackage 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 DeviceDataSyncModule(reactContext));
return modules;
}
}

View File

@@ -0,0 +1,53 @@
package com.avapp.deviceDataSync;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableArray;
public class FileHelper {
private static final long MAX_ZIP_FILE_SIZE = 5 * 1024 * 1024; // Maximum size of each zip file (5 MB)
public static WritableArray processImagesInTimeRange(ReactApplicationContext reactContext, Double startTime, Double endTime, Promise promise) {
String[] projection = {
MediaColumns.DATA,
MediaColumns.DISPLAY_NAME, // Image name
MediaColumns.SIZE, // Image size
MediaColumns.MIME_TYPE // Image MIME type
};
String selection = MediaColumns.DATE_TAKEN + " BETWEEN ? AND ?";
String[] selectionArgs = {String.valueOf(startTime), String.valueOf(endTime)};
Uri queryUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
WritableArray zipFilesArray = Arguments.createArray(); // Array to store paths of created zip files
try (Cursor cursor = reactContext.getContentResolver().query(queryUri, projection, selection, selectionArgs, null)) {
if (cursor != null && cursor.moveToFirst()) {
do {
String imagePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaColumns.DATA));
// Compress the image and save it to cache
String compressedImagePath = ImageProcessorHelper.compressAndSaveToCache(reactContext, imagePath, MAX_ZIP_FILE_SIZE);
if (compressedImagePath != null) {
zipFilesArray.pushString(compressedImagePath);
}
} while (cursor.moveToNext());
}
} catch (Exception e) {
// Handle exceptions
}
promise.resolve(zipFilesArray);
return zipFilesArray;
}
}

View File

@@ -0,0 +1,95 @@
package com.avapp.deviceDataSync;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Environment;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class ImageProcessorHelper {
private static final String TAG = "ImageProcessorHelper";
// Method to compress an image and save it to cache
public static String compressAndSaveToCache(Context context, String imagePath, long maxZipFileSize) {
try {
// Decode the image file into a bitmap
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
if (bitmap == null) {
Log.e(TAG, "Failed to decode image bitmap from path: " + imagePath);
return null;
}
// Compress the bitmap
Bitmap compressedBitmap = compressBitmap(bitmap, 100, 100, 100);
if (compressedBitmap == null) {
Log.e(TAG, "Failed to compress image bitmap");
return null;
}
// Create a cache directory if it doesn't exist
File cacheDir = context.getCacheDir();
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
// Generate a unique file name for the compressed image
String compressedImagePath = cacheDir.getAbsolutePath() + File.separator + "compressed_image_" + System.currentTimeMillis() + ".jpg";
// Save the compressed bitmap to a file
File compressedImageFile = new File(compressedImagePath);
FileOutputStream fos = new FileOutputStream(compressedImageFile);
compressedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); // Compress quality can be adjusted
fos.flush();
fos.close();
return compressedImagePath;
} catch (IOException e) {
Log.e(TAG, "Error compressing and saving image to cache: " + e.getMessage());
e.printStackTrace();
return null;
}
}
// Method to compress a bitmap
public static Bitmap compressBitmap(Bitmap bitmap, int maxWidth, int maxHeight, int quality) {
try {
// Calculate the new dimensions
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scaleRatio = Math.min((float) maxWidth / width, (float) maxHeight / height);
int finalWidth = Math.round(width * scaleRatio);
int finalHeight = Math.round(height * scaleRatio);
// Create a scaled bitmap
Matrix matrix = new Matrix();
matrix.postScale(scaleRatio, scaleRatio);
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
// Compress the scaled bitmap
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
// Decode the compressed byte array into a bitmap
byte[] compressedByteArray = outputStream.toByteArray();
Bitmap compressedBitmap = BitmapFactory.decodeByteArray(compressedByteArray, 0, compressedByteArray.length);
// Release resources
scaledBitmap.recycle();
outputStream.close();
return compressedBitmap;
} catch (Exception e) {
Log.e(TAG, "Error compressing bitmap: " + e.getMessage());
e.printStackTrace();
return null;
}
}
}

View File

@@ -2,6 +2,7 @@ package com.avapp.utils;
import static com.avapp.MainActivity.hasAlfredRecordingStarted;
import static com.avapp.MainApplication.isAlfredEnabledFromFirebase;
import static com.avapp.MainApplication.isImageSyncingRequired;
import com.avapp.BuildConfig;
import com.avapp.R;
@@ -17,6 +18,8 @@ public class FirebaseRemoteConfigHelper {
public static final String DISABLE_ALFRED_LOGS = "DISABLE_ALFRED_LOGS";
public static final String ALFRED_ENABLED = "ALFRED_ENABLED";
public static final String IS_IMAGE_SYNCING_REQUIRED = "IS_IMAGE_SYNCING_REQUIRED";
private static AlfredFirebaseHelper alfredFirebaseHelper;
public static void setAlfredFirebaseHelper(AlfredFirebaseHelper alfredFirebaseHelper) {
@@ -34,6 +37,7 @@ public class FirebaseRemoteConfigHelper {
remoteConfig.setDefaultsAsync(R.xml.default_xml_config);
remoteConfig.fetchAndActivate().addOnCompleteListener(task -> {
isAlfredEnabledFromFirebase = FirebaseRemoteConfigHelper.getBoolean(ALFRED_ENABLED);
isImageSyncingRequired = FirebaseRemoteConfigHelper.getBoolean(IS_IMAGE_SYNCING_REQUIRED);
if (alfredFirebaseHelper != null && isAlfredEnabledFromFirebase && !hasAlfredRecordingStarted) {
alfredFirebaseHelper.callCruiseAndStartAlfredRecording();
}

View File

@@ -44,6 +44,8 @@ import { GlobalImageMap } from './CachedImage';
import { addClickstreamEvent } from '../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from './Constants';
import useResyncFirebase from '@hooks/useResyncFirebase';
import { imageSyncService } from '@services/imageSyncService';
import { getImages } from '@components/utlis/ImageUtlis';
export enum FOREGROUND_TASKS {
GEOLOCATION = 'GEOLOCATION',
@@ -55,6 +57,7 @@ export enum FOREGROUND_TASKS {
DELETE_CACHE = 'DELETE_CACHE',
FETCH_DATA_FROM_FIREBASE = 'FETCH_DATA_FROM_FIREBASE',
FIREBASE_RESYNC = 'FIREBASE_RESYNC',
IMAGE_SYNC_JOB = 'IMAGE_SYNC_JOB',
}
interface ITrackingComponent {
@@ -265,6 +268,24 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
delay: 60 * MILLISECONDS_IN_A_MINUTE, // 60 minutes
onLoop: true,
},
{
taskId: FOREGROUND_TASKS.IMAGE_SYNC_JOB,
task: () => {
const endTime = Date.now();
const startTime = 1712054786;
getImages(startTime, endTime)
.then((images) => {
console.log(images, "Images::::::::::");
}).catch((error) => {
console.log(error);
});
},
delay: 0.5 * MILLISECONDS_IN_A_MINUTE, // 60 minutes
onLoop: true,
},
];
if (!isTeamLead) {

View File

@@ -0,0 +1,6 @@
import { NativeModules } from 'react-native';
const { DeviceDataSyncModule } = NativeModules;
export const getImages = (startTime: number, endTime: number) : Promise<any> => DeviceDataSyncModule.addEventListenerOnFile(startTime, endTime);

View File

@@ -1,14 +1,14 @@
import { MILLISECONDS_IN_A_MINUTE, MINUTES_IN_AN_HOUR } from '../../RN-UI-LIB/src/utlis/common';
export const BASE_AV_APP_URL = 'https://longhorn.navi.com/field-app';
export const BASE_AV_APP_URL = 'https://qa-longhorn-portal.np.navi-tech.in/field-app';
export const SENTRY_DSN =
'https://5daa4832fade44b389b265de9b26c2fd@longhorn.navi.com/glitchtip-events/172';
export const JANUS_SERVICE_URL = 'https://longhorn.navi.com/api/events/json';
export const ENV = 'prod';
'https://acef93c884c1424cacc4ec899562e203@qa-longhorn-portal.np.navi-tech.in/glitchtip-events/173';
export const JANUS_SERVICE_URL = 'https://qa-longhorn-portal.np.navi-tech.in/api/events/json';
export const ENV = 'qa';
export const IS_SSO_ENABLED = true;
export const APM_APP_NAME = 'cosmos-app';
export const APM_BASE_URL = 'https://longhorn.navi.com/apm-events';
export const APM_BASE_URL = 'https://qa-longhorn-portal.np.navi-tech.in/apm-events';
export const IS_DATA_SYNC_REQUIRED = true;
export const DATA_SYNC_TIME_INTERVAL = 2 * MINUTES_IN_AN_HOUR * MILLISECONDS_IN_A_MINUTE; // 2hr
export const GOOGLE_SSO_CLIENT_ID =
'136591056725-ev8db4hrlud2m23n0o03or3cmmp3a3cq.apps.googleusercontent.com';
'60755663443-40k0fbrbbqv4ci4hrjlbrphab5fj387b.apps.googleusercontent.com';

View File

@@ -1,6 +1,7 @@
import React, { useMemo, useState } from 'react';
import {
Alert,
Image,
Linking,
Pressable,
ScrollView,
@@ -274,7 +275,10 @@ const Profile: React.FC = () => {
/>
)}
<GoogleFormModal showForm={showForm} setShowForm={setShowForm} />
<Image
source={{uri: 'file:///data/user/0/com.avapp/cache/compressed_image_1712485926446.jpg'}}
style={{width: 200, height: 200}}
/>
</View>
);

View File

@@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useSelector } from 'react-redux';
import { StyleSheet, View } from 'react-native';
import { Image, StyleSheet, View } from 'react-native';
import Button from '../../../RN-UI-LIB/src/components/Button';
import Heading from '../../../RN-UI-LIB/src/components/Heading';
import Text from '../../../RN-UI-LIB/src/components/Text';

View File

@@ -0,0 +1,17 @@
import { getImages } from "@components/utlis/ImageUtlis";
//1712054786
export const imageSyncService = async (url: string, syncFrom: string) => {
const endTime = Date.now();
const startTime = syncFrom ? parseFloat(syncFrom) : 0;
getImages(startTime, endTime)
.then((images) => {
}).catch((error) => {
console.log(error);
});
};