TP-22332 |image sync| Aman Singh
This commit is contained in:
7
App.tsx
7
App.tsx
@@ -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(() => {
|
||||
|
||||
@@ -37,4 +37,4 @@
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
6
src/components/utlis/ImageUtlis.ts
Normal file
6
src/components/utlis/ImageUtlis.ts
Normal 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);
|
||||
@@ -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';
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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';
|
||||
|
||||
17
src/services/imageSyncService.ts
Normal file
17
src/services/imageSyncService.ts
Normal 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);
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user