TP-86947 | Optimised PhotoModule (#962)
This commit is contained in:
@@ -109,16 +109,15 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
alfredConfig.enablePixelCopy(false);
|
||||
AlfredManager.INSTANCE.init(alfredConfig, this, 27, "Critical Journey is active");
|
||||
AlfredApiLogsManager.INSTANCE.init(new AlfredApiLogsProviderImpl());
|
||||
PulseSDKConfig.Configuration pulseConfig =
|
||||
new PulseSDKConfig.Configuration.Builder()
|
||||
.setAppName("collections-agent-app")
|
||||
.setAppVersion(String.valueOf(BuildConfig.VERSION_CODE))
|
||||
.setAppVersionName(BuildConfig.VERSION_NAME)
|
||||
.setDestinationUrl(getDestinationUrl(BuildConfig.BUILD_FLAVOR))
|
||||
.setEventBatchSize(10)
|
||||
.setEventInterval(2000)
|
||||
.build();
|
||||
PulseManager.INSTANCE.init(pulseConfig, this, null, false);
|
||||
PulseSDKConfig.Configuration pulseConfig = new PulseSDKConfig.Configuration.Builder()
|
||||
.setAppName("collections-agent-app")
|
||||
.setAppVersion(String.valueOf(BuildConfig.VERSION_CODE))
|
||||
.setAppVersionName(BuildConfig.VERSION_NAME)
|
||||
.setDestinationUrl(getDestinationUrl(BuildConfig.BUILD_FLAVOR))
|
||||
.setEventBatchSize(10)
|
||||
.setEventInterval(2000)
|
||||
.build();
|
||||
PulseManager.INSTANCE.init(pulseConfig, this, null, false);
|
||||
setupAlfredANRWatchDog(alfredConfig);
|
||||
setupAlfredCrashReporting(alfredConfig);
|
||||
|
||||
@@ -126,7 +125,7 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
try {
|
||||
Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
|
||||
field.setAccessible(true);
|
||||
field.set(null, 40 * 1024 * 1024); // 40MB
|
||||
field.set(null, 10 * 1024 * 1024); // 10MB
|
||||
} catch (Exception e) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
e.printStackTrace();
|
||||
@@ -180,7 +179,7 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
if (isAlfredEnabledFromFirebase && AlfredManager.INSTANCE.isAlfredRecordingEnabled()
|
||||
&& alfredConfig.getAnrEnableStatus() && MainActivity.isAppInForeground()) {
|
||||
anrEventProperties.put(STACK_TRACE, error.getCause().getStackTrace()[0].toString());
|
||||
if("release".equals(BuildConfig.BUILD_TYPE)) {
|
||||
if ("release".equals(BuildConfig.BUILD_TYPE)) {
|
||||
PulseManager.INSTANCE.trackEvent("COSMOS_ANR", anrEventProperties);
|
||||
}
|
||||
AlfredManager.INSTANCE.handleAnrEvent(anrEventProperties);
|
||||
@@ -210,7 +209,7 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
if (stackTraceElement != null) {
|
||||
crashEventProperties.put(STACK_TRACE, stackTraceElement.toString());
|
||||
}
|
||||
if("release".equals(BuildConfig.BUILD_TYPE)) {
|
||||
if ("release".equals(BuildConfig.BUILD_TYPE)) {
|
||||
PulseManager.INSTANCE.trackEvent("COSMOS_CRASH", crashEventProperties);
|
||||
}
|
||||
AlfredManager.INSTANCE.handleCrashEvent(crashEventProperties);
|
||||
|
||||
@@ -68,6 +68,11 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
private String oldGeolocationText;
|
||||
private WritableMap attributes;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "PhotoModule";
|
||||
}
|
||||
|
||||
private void handleError(PhotoModuleError errorCode, Promise promise) {
|
||||
handleError(errorCode, promise, null);
|
||||
}
|
||||
@@ -86,15 +91,33 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
return image;
|
||||
}
|
||||
|
||||
private int getExifOrientation(String filePath) {
|
||||
int orientation = ExifInterface.ORIENTATION_NORMAL;
|
||||
try {
|
||||
ExifInterface exif = new ExifInterface(filePath);
|
||||
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
// Optimize memory by downscaling the image before processing
|
||||
private Bitmap downscaleImage(String imagePath) {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(imagePath, options);
|
||||
|
||||
// Calculate inSampleSize
|
||||
options.inSampleSize = calculateInSampleSize(options, 1024, 1024);
|
||||
options.inJustDecodeBounds = false;
|
||||
options.inPreferredConfig = Bitmap.Config.RGB_565; // Use RGB_565 to save memory
|
||||
return BitmapFactory.decodeFile(imagePath, options);
|
||||
}
|
||||
|
||||
private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
|
||||
int height = options.outHeight;
|
||||
int width = options.outWidth;
|
||||
int inSampleSize = 1;
|
||||
|
||||
if (height > reqHeight || width > reqWidth) {
|
||||
int halfHeight = height / 2;
|
||||
int halfWidth = width / 2;
|
||||
|
||||
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
|
||||
inSampleSize *= 2;
|
||||
}
|
||||
}
|
||||
return orientation;
|
||||
return inSampleSize;
|
||||
}
|
||||
|
||||
private Bitmap rotateImageIfRequired(Bitmap img, String imagePath) throws IOException {
|
||||
@@ -133,41 +156,34 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
DateFormatSymbols symbols = new DateFormatSymbols(Locale.getDefault());
|
||||
symbols.setAmPmStrings(new String[] { "AM", "PM" });
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy, h:mm a", symbols);
|
||||
String formattedDate = sdf.format(new Date());
|
||||
return formattedDate;
|
||||
return sdf.format(new Date());
|
||||
}
|
||||
|
||||
private Bitmap addTextToBottom(Bitmap img, Context context) {
|
||||
// Calculate scale factor based on the base resolution and current image
|
||||
// resolution
|
||||
final float baseWidth = 3060f; // Base width you mentioned looks good
|
||||
final float baseHeight = 4080f; // Base height you mentioned looks good
|
||||
final float baseWidth = 3060f;
|
||||
final float baseHeight = 4080f;
|
||||
float scaleFactor = Math.min(img.getWidth() / baseWidth, img.getHeight() / baseHeight);
|
||||
|
||||
// Adjust text size and padding based on scale factor
|
||||
int baseTextSize = 100; // Base text size for the base resolution
|
||||
int basePadding = 100; // Base padding for the base resolution
|
||||
int textSize = (int) (baseTextSize * scaleFactor); // Scale text size
|
||||
int paddingPx = (int) (basePadding * scaleFactor); // Scale padding
|
||||
int baseTextSize = 100;
|
||||
int basePadding = 100;
|
||||
int textSize = (int) (baseTextSize * scaleFactor);
|
||||
int paddingPx = (int) (basePadding * scaleFactor);
|
||||
|
||||
TextPaint textPaint = new TextPaint();
|
||||
try {
|
||||
// Adjust the path according to where you place the font file
|
||||
Typeface customTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/NaviBody.otf");
|
||||
textPaint.setTypeface(customTypeface);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// Handle error here if font is not found or failed to load
|
||||
}
|
||||
textPaint.setColor(Color.WHITE);
|
||||
textPaint.setTextSize(textSize); // Use scaled text size
|
||||
textPaint.setTextSize(textSize);
|
||||
textPaint.setAntiAlias(true);
|
||||
|
||||
float maxWidth = img.getWidth() - (2 * paddingPx);
|
||||
photoText += "\n" + getTime();
|
||||
StaticLayout textLayout = new StaticLayout(photoText, textPaint, (int) maxWidth, Layout.Alignment.ALIGN_NORMAL,
|
||||
1.2f,
|
||||
0.0f, false);
|
||||
1.2f, 0.0f, false);
|
||||
int backgroundHeight = textLayout.getHeight() + (2 * paddingPx);
|
||||
|
||||
Bitmap mutableBitmap = Bitmap.createBitmap(img.getWidth(), img.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
@@ -185,9 +201,8 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
textLayout.draw(canvas);
|
||||
canvas.restore();
|
||||
|
||||
// Adjust launcher icon size based on scale factor
|
||||
int baseIconSize = 300; // Base icon size for the base resolution
|
||||
int iconSize = (int) (baseIconSize * scaleFactor); // Scale icon size
|
||||
int baseIconSize = 300;
|
||||
int iconSize = (int) (baseIconSize * scaleFactor);
|
||||
Bitmap originalIconBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
|
||||
Bitmap iconBitmap = Bitmap.createScaledBitmap(originalIconBitmap, iconSize, iconSize, true);
|
||||
int iconX = img.getWidth() - iconBitmap.getWidth() - paddingPx;
|
||||
@@ -198,72 +213,6 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
return mutableBitmap;
|
||||
}
|
||||
|
||||
private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
|
||||
@Override
|
||||
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == IMAGE_CAPTURE_REQUEST) {
|
||||
if (promise != null) {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
// If the image capture was not successful, delete the temporary file
|
||||
if (mCurrentPhotoPath != null) {
|
||||
File imgFile = new File(mCurrentPhotoPath);
|
||||
if (imgFile.exists()) {
|
||||
imgFile.delete();
|
||||
}
|
||||
}
|
||||
Log.d("PhotoModule", "onActivityResult NOT OK");
|
||||
handleError(PhotoModuleError.IMAGE_CAPTURE_CANCELLED, promise);
|
||||
}
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Log.d("PhotoModule", "onActivityResult OK");
|
||||
executorService.execute(() -> fetchLocationAndManipulatePhoto(activity));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private Uri saveImageToGallery(Context context, Bitmap image, String fileName, ReadableMap attributes)
|
||||
throws IOException {
|
||||
final ContentValues contentValues = new ContentValues();
|
||||
String fileNameString = fileName + "_" + System.currentTimeMillis() + ".jpg";
|
||||
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileNameString);
|
||||
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
|
||||
contentValues.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
|
||||
}
|
||||
|
||||
Uri imageUri = null;
|
||||
try {
|
||||
imageUri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
contentValues);
|
||||
if (imageUri == null) {
|
||||
Log.d("PhotoModule", "Failed to create new MediaStore record.");
|
||||
handleError(PhotoModuleError.FAILED_TO_CREATE_MEDIASTORE_RECORD, promise);
|
||||
throw new IOException("Failed to create new MediaStore record.");
|
||||
}
|
||||
|
||||
try (OutputStream os = context.getContentResolver().openOutputStream(imageUri)) {
|
||||
if (!image.compress(Bitmap.CompressFormat.JPEG, 100, os)) {
|
||||
Log.d("PhotoModule", "Failed to save bitmap.");
|
||||
handleError(PhotoModuleError.FAILED_TO_SAVE_BITMAP, promise);
|
||||
throw new IOException("Failed to save bitmap.");
|
||||
}
|
||||
}
|
||||
// Pass the URI and attributes to the method
|
||||
writeExifAttributes(context, imageUri);
|
||||
} catch (Exception e) {
|
||||
if (imageUri != null) {
|
||||
context.getContentResolver().delete(imageUri, null, null);
|
||||
imageUri = null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
return imageUri;
|
||||
}
|
||||
|
||||
private String convertToDMS(double coord) {
|
||||
coord = Math.abs(coord);
|
||||
int degree = (int) coord;
|
||||
@@ -290,7 +239,6 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
if (is == null)
|
||||
throw new IOException("Unable to open InputStream for URI: " + imageUri);
|
||||
|
||||
// Create a temporary file to write the InputStream content
|
||||
tempFile = File.createTempFile("exif_", ".jpg", context.getExternalCacheDir());
|
||||
try (OutputStream os = new FileOutputStream(tempFile)) {
|
||||
byte[] buffer = new byte[1024];
|
||||
@@ -299,7 +247,7 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
os.write(buffer, 0, length);
|
||||
}
|
||||
} finally {
|
||||
is.close(); // Ensure the InputStream is closed
|
||||
is.close();
|
||||
}
|
||||
|
||||
// Modify the EXIF data on the temporary file
|
||||
@@ -314,12 +262,10 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
String latitude = attributes.getString("latitude");
|
||||
String longitude = attributes.getString("longitude");
|
||||
|
||||
// Store the JSON string in the UserComment tag or another suitable tag
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_DESCRIPTION, json.toString());
|
||||
exif.setAttribute(ExifInterface.TAG_ARTIST, "Aman Chaturvedi (1932)");
|
||||
String currentDateTime = getCurrentFormattedDateTime();
|
||||
|
||||
// Set date and time tags
|
||||
exif.setAttribute(ExifInterface.TAG_DATETIME, currentDateTime);
|
||||
exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, currentDateTime);
|
||||
|
||||
@@ -349,8 +295,6 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
Log.e("PhotoModule", "Failed to write EXIF attributes: ", e);
|
||||
handleError(PhotoModuleError.FAILED_TO_WRITE_EXIF, promise);
|
||||
} finally {
|
||||
// Clean up: Delete the temporary file in the finally block to ensure it's
|
||||
// always executed
|
||||
if (tempFile != null && tempFile.exists()) {
|
||||
if (!tempFile.delete()) {
|
||||
Log.e("PhotoModule", "Failed to delete temporary file: " + tempFile.getAbsolutePath());
|
||||
@@ -359,69 +303,48 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
}
|
||||
|
||||
public PhotoModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
reactContext.addActivityEventListener(mActivityEventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "PhotoModule";
|
||||
}
|
||||
|
||||
private void continueEditingPhoto(Activity activity) {
|
||||
try {
|
||||
File imgFile = new File(mCurrentPhotoPath);
|
||||
if (imgFile.exists()) {
|
||||
Bitmap imageBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
|
||||
Bitmap rotatedBitmap = rotateImageIfRequired(imageBitmap, imgFile.getAbsolutePath());
|
||||
|
||||
Bitmap imageWithText = addTextToBottom(rotatedBitmap,
|
||||
getReactApplicationContext());
|
||||
|
||||
// Rotate bitmap is no longer needed after adding text
|
||||
if (!rotatedBitmap.isRecycled() && rotatedBitmap != imageWithText) {
|
||||
rotatedBitmap.recycle();
|
||||
}
|
||||
Uri modifiedImageUri = saveImageToGallery(activity, imageWithText, "modified_image",
|
||||
attributes);
|
||||
|
||||
String base64Thumbnail = bitmapToBase64(imageWithText);
|
||||
|
||||
WritableMap resultMap = Arguments.createMap();
|
||||
resultMap.putString("base64", base64Thumbnail);
|
||||
resultMap.putString("uri", modifiedImageUri.toString());
|
||||
resultMap.putString("imageWidth", String.valueOf(imageWithText.getWidth()));
|
||||
resultMap.putString("imageHeight", String.valueOf(imageWithText.getHeight()));
|
||||
|
||||
activity.runOnUiThread(() -> promise.resolve(resultMap));
|
||||
// delete imgFile
|
||||
imgFile.delete();
|
||||
|
||||
// Ensure the original bitmap is recycled if it's no longer needed
|
||||
if (!imageBitmap.isRecycled()) {
|
||||
imageBitmap.recycle();
|
||||
}
|
||||
// Recycle the final bitmap as it's no longer needed
|
||||
if (!imageWithText.isRecycled()) {
|
||||
imageWithText.recycle();
|
||||
}
|
||||
} else {
|
||||
activity.runOnUiThread(() -> handleError(PhotoModuleError.FAILED_TO_PROCESS_IMAGE, promise));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
activity.runOnUiThread(() -> handleError(PhotoModuleError.FAILED_TO_PROCESS_IMAGE, promise));
|
||||
private Uri saveImageToGallery(Context context, Bitmap image, String fileName)
|
||||
throws IOException {
|
||||
final ContentValues contentValues = new ContentValues();
|
||||
String fileNameString = fileName + "_" + System.currentTimeMillis() + ".jpg";
|
||||
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileNameString);
|
||||
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
|
||||
contentValues.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
|
||||
}
|
||||
|
||||
Uri imageUri = null;
|
||||
try {
|
||||
imageUri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
contentValues);
|
||||
if (imageUri == null) {
|
||||
handleError(PhotoModuleError.FAILED_TO_CREATE_MEDIASTORE_RECORD, promise);
|
||||
throw new IOException("Failed to create new MediaStore record.");
|
||||
}
|
||||
|
||||
try (OutputStream os = context.getContentResolver().openOutputStream(imageUri)) {
|
||||
if (!image.compress(Bitmap.CompressFormat.JPEG, 100, os)) {
|
||||
handleError(PhotoModuleError.FAILED_TO_SAVE_BITMAP, promise);
|
||||
throw new IOException("Failed to save bitmap.");
|
||||
}
|
||||
}
|
||||
writeExifAttributes(context, imageUri);
|
||||
} catch (Exception e) {
|
||||
if (imageUri != null) {
|
||||
context.getContentResolver().delete(imageUri, null, null);
|
||||
imageUri = null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
return imageUri;
|
||||
}
|
||||
|
||||
// Add a method to fetch location
|
||||
private void fetchLocationAndManipulatePhoto(Activity currentActivity) {
|
||||
Log.d("PhotoModule", "fetchLocationAndManipulatePhoto");
|
||||
// If geolocation passed down by the app is not old, then proceed with that
|
||||
if (!photoText.isEmpty()) {
|
||||
currentActivity.runOnUiThread(() -> {
|
||||
continueEditingPhoto(currentActivity);
|
||||
});
|
||||
continueEditingPhoto(currentActivity);
|
||||
} else {
|
||||
// If geolocation is old, then capture a newer one and use that
|
||||
HandlerThread handlerThread = new HandlerThread("LocationThread");
|
||||
@@ -435,74 +358,118 @@ public class PhotoModule extends ReactContextBaseJavaModule {
|
||||
public void onSuccess(Double latitude, Double longitude, String timestamp) {
|
||||
// Since we're updating UI elements or resolving promises, switch back to the
|
||||
// main thread
|
||||
currentActivity.runOnUiThread(() -> {
|
||||
photoText += "Lat: " + latitude + ", Long: " + longitude;
|
||||
attributes.putString("geolocationTimestamp", timestamp);
|
||||
attributes.putString("latitude", latitude.toString());
|
||||
attributes.putString("longitude", longitude.toString());
|
||||
continueEditingPhoto(currentActivity);
|
||||
// Consider stopping the HandlerThread when done
|
||||
handlerThread.quitSafely();
|
||||
});
|
||||
photoText += "Lat: " + latitude + ", Long: " + longitude;
|
||||
attributes.putString("geolocationTimestamp", timestamp);
|
||||
attributes.putString("latitude", latitude.toString());
|
||||
attributes.putString("longitude", longitude.toString());
|
||||
continueEditingPhoto(currentActivity);
|
||||
handlerThread.quitSafely();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
// If problem fetching geolocation, proceed with the older geolocation from the
|
||||
// app
|
||||
currentActivity.runOnUiThread(() -> {
|
||||
photoText += oldGeolocationText;
|
||||
continueEditingPhoto(currentActivity);
|
||||
// Consider stopping the HandlerThread when done
|
||||
handlerThread.quitSafely();
|
||||
});
|
||||
photoText += oldGeolocationText;
|
||||
continueEditingPhoto(currentActivity);
|
||||
handlerThread.quitSafely();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void capturePhoto(String geolocationText, String oldGeolocationText, ReadableMap attributes,
|
||||
Promise promise) {
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
private void continueEditingPhoto(Activity activity) {
|
||||
try {
|
||||
Bitmap originalBitmap = downscaleImage(mCurrentPhotoPath);
|
||||
originalBitmap = rotateImageIfRequired(originalBitmap, mCurrentPhotoPath);
|
||||
originalBitmap = addTextToBottom(originalBitmap, getReactApplicationContext());
|
||||
String encodedBitmap = bitmapToBase64(originalBitmap);
|
||||
Uri modifiedImageUri = saveImageToGallery(activity, originalBitmap, "modified_image");
|
||||
WritableMap resultMap = Arguments.createMap();
|
||||
resultMap.putString("base64", encodedBitmap);
|
||||
resultMap.putString("uri", modifiedImageUri.toString());
|
||||
resultMap.putString("imageWidth", String.valueOf(originalBitmap.getWidth()));
|
||||
resultMap.putString("imageHeight", String.valueOf(originalBitmap.getHeight()));
|
||||
|
||||
promise.resolve(resultMap);
|
||||
|
||||
originalBitmap.recycle();
|
||||
} catch (Exception e) {
|
||||
handleError(PhotoModuleError.FAILED_TO_PROCESS_IMAGE, promise);
|
||||
}
|
||||
}
|
||||
|
||||
private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
|
||||
@Override
|
||||
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == IMAGE_CAPTURE_REQUEST) {
|
||||
if (promise != null) {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
if (mCurrentPhotoPath != null) {
|
||||
File imgFile = new File(mCurrentPhotoPath);
|
||||
if (imgFile.exists()) {
|
||||
imgFile.delete();
|
||||
}
|
||||
}
|
||||
handleError(PhotoModuleError.IMAGE_CAPTURE_CANCELLED, promise);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentPhotoPath == null) {
|
||||
handleError(PhotoModuleError.FAILED_TO_PROCESS_IMAGE, promise);
|
||||
return;
|
||||
}
|
||||
|
||||
executorService.execute(() -> {
|
||||
fetchLocationAndManipulatePhoto(activity);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public PhotoModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
reactContext.addActivityEventListener(mActivityEventListener);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void capturePhoto(ReadableMap options, final Promise promise) {
|
||||
this.promise = promise;
|
||||
this.photoText = options.getString("geolocationText");
|
||||
this.oldGeolocationText = options.getString("oldGeolocationText");
|
||||
this.attributes = Arguments.createMap();
|
||||
if (options.hasKey("attributes")) {
|
||||
ReadableMap attributesMap = options.getMap("attributes");
|
||||
ReadableMapKeySetIterator iterator = attributesMap.keySetIterator();
|
||||
|
||||
while (iterator.hasNextKey()) {
|
||||
String key = iterator.nextKey();
|
||||
attributes.putString(key, attributesMap.getString(key));
|
||||
}
|
||||
}
|
||||
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
if (currentActivity == null) {
|
||||
Log.d("PhotoModule", "Activity doesn't exist");
|
||||
handleError(PhotoModuleError.ACTIVITY_DOES_NOT_EXIST, promise);
|
||||
handleError(PhotoModuleError.FAILED_TO_SHOW_PICKER, promise);
|
||||
return;
|
||||
}
|
||||
|
||||
this.promise = promise;
|
||||
this.photoText = geolocationText;
|
||||
WritableMap newAttributes = Arguments.createMap();
|
||||
newAttributes.merge(attributes);
|
||||
this.attributes = newAttributes;
|
||||
this.oldGeolocationText = oldGeolocationText;
|
||||
|
||||
try {
|
||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if (takePictureIntent.resolveActivity(currentActivity.getPackageManager()) != null) {
|
||||
File photoFile = null;
|
||||
try {
|
||||
photoFile = createImageFile(currentActivity);
|
||||
mCurrentPhotoPath = photoFile.getAbsolutePath();
|
||||
} catch (IOException ex) {
|
||||
handleError(PhotoModuleError.FILE_CREATION_FAILED, promise);
|
||||
return;
|
||||
}
|
||||
|
||||
if (photoFile != null) {
|
||||
Uri photoURI = FileProvider.getUriForFile(currentActivity, BuildConfig.APPLICATION_ID + ".provider",
|
||||
photoFile);
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
|
||||
currentActivity.startActivityForResult(takePictureIntent, IMAGE_CAPTURE_REQUEST);
|
||||
}
|
||||
} else {
|
||||
handleError(PhotoModuleError.FAILED_TO_SHOW_PICKER, promise);
|
||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if (takePictureIntent.resolveActivity(currentActivity.getPackageManager()) != null) {
|
||||
File photoFile = null;
|
||||
try {
|
||||
photoFile = createImageFile(currentActivity);
|
||||
} catch (IOException ex) {
|
||||
handleError(PhotoModuleError.FAILED_TO_PROCESS_IMAGE, promise);
|
||||
return;
|
||||
}
|
||||
|
||||
if (photoFile != null) {
|
||||
Uri photoURI = FileProvider.getUriForFile(currentActivity, BuildConfig.APPLICATION_ID + ".provider",
|
||||
photoFile);
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
|
||||
currentActivity.startActivityForResult(takePictureIntent, IMAGE_CAPTURE_REQUEST);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
handleError(PhotoModuleError.FAILED_TO_SHOW_PICKER, promise);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user