Definitive Fix for Android's bug of duplicating photo on gallery when using the internal camera

前端 未结 1 1394
轻奢々
轻奢々 2021-01-24 02:08

This is definitive fix for the Android\'s problem of duplicating a photo. Tested it on 2.3 (which has the bug), 4.x (which doesnt have the bug) and 5.x (which has the bug too).

相关标签:
1条回答
  • 2021-01-24 02:27

    The fix uses code that i found in some questions here in StackOverflow, and also an improvement of my own.

    First, you get the image with the URI you used to create the intent, get its added date, and delete it. Then, you get the last image added to the gallery, and compare with the added date of the original image. I delete it if difference is less than one second (its usually less than 10ms).

    This is the code used to take the photo:

    private static final int EXTCAMERA_RETURN = 1234324334;
    private String imageFN; // stored globally but could be a parameter
    ...
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, "tctemp.jpg");
    values.put (MediaStore.Images.Media.IS_PRIVATE, 1);
    capturedImageURI = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);  
    intent.putExtra(MediaStore.EXTRA_OUTPUT, capturedImageURI);  
    startActivityForResult(intent, EXTCAMERA_RETURN);
    

    And this is the one to grab the taken photo:

     String[] projection = {MediaStore.Images.Media.DATA, BaseColumns._ID, MediaStore.Images.Media.DATE_ADDED}; 
     Cursor cursor = managedQuery(capturedImageURI, projection, null, null, null); 
    
     cursor.moveToFirst();
     String capturedImageFilePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
     long date = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_ADDED));
     if (capturedImageFilePath == null || !AndroidUtils.copyFile(capturedImageFilePath,imageFN,cameraType == CAMERA_NATIVE_NOCOPY))
        resultCode = RESULT_OK+1; // error
     else
     {
        autoRotatePhoto(imageFN);
        getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, BaseColumns._ID + "=" + cursor.getString(cursor.getColumnIndexOrThrow(BaseColumns._ID)), null);
        try {new File(capturedImageFilePath).delete();} catch (Exception e) {} // on android 2.3 the code above does not work, so we just ensure that we delete the file
        removeLastImageFromGallery(date);
     }
    

    This code is used to remove the last photo of the gallery IF the difference is less than one second

     private void removeLastImageFromGallery(long orig)
     {
        try
        {
           final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATE_ADDED };
           final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
           Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy);
           if (imageCursor.moveToFirst())
           {
              long last = imageCursor.getLong(imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_ADDED));
              int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
              long dif = Math.abs(orig-last);
              if (dif < 1) // 1 second - usually is less than 10ms
                 getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media._ID + "=?", new String[]{ Long.toString(id) } );
           }
        }
        catch (Exception e)
        {
           AndroidUtils.handleException(e, false);
        }
    }
    

    Finally, the autorotate code is:

    public static void autoRotatePhoto(String imagePath)
    {
       try
       {
          File f = new File(imagePath);
          ExifInterface exif = new ExifInterface(f.getPath());
          int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
          AndroidUtils.debug(imagePath+" -> "+orientation);
    
          int angle = 0;
          switch (orientation)
          {
             case ExifInterface.ORIENTATION_ROTATE_90: angle  = 90;  break;
             case ExifInterface.ORIENTATION_ROTATE_180: angle = 180; break;
             case ExifInterface.ORIENTATION_ROTATE_270: angle = 270; break;
             default: return;
          }
    
          Matrix mat = new Matrix();
          mat.postRotate(angle);
          BitmapFactory.Options options = new BitmapFactory.Options();
          options.inSampleSize = 2;
    
          Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, options);
          Bitmap bitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mat, true);
          FileOutputStream out = new FileOutputStream(f);
          bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out);
          out.close();
          AndroidUtils.debug("auto-rotated "+imagePath);
       }
       catch (Exception e)
       {
          AndroidUtils.handleException(e, false);
       }
    }
    

    The AndroidUtils.debug and handleException are used to dump the Log and print the exception. The copyFile is shown here:

    public static boolean copyFile(String in, String out, boolean deleteOriginal)
    {
       try
       {
          byte[] buf = new byte[4096];
          FileInputStream fin = new FileInputStream(in);
          FileOutputStream fout = new FileOutputStream(out);
          int r;
          while ((r=fin.read(buf,0,buf.length)) > 0)
             fout.write(buf,0,r);
          fin.close();
          fout.close();
          if (deleteOriginal)
             new File(in).delete();
          return true;
       }
       catch (Exception e)
       {
          handleException(e,false);
          return false;
       }
    }
    
    0 讨论(0)
提交回复
热议问题