Browse Source

[New]新增oppo相册缓存解析

zhipeng 1 year ago
parent
commit
3713aef9da

+ 119 - 1
app/src/main/java/com/datarecovery/master/utils/ImageDeepDetector.java

@@ -41,6 +41,7 @@ public class ImageDeepDetector {
     private static final int WECHAT_CACHE = 2;
     private static final int GALLERY_CACHE = 3;
     private static final int JPG_MAGIC = 4;
+    private static final int OPPO_GALLERY_CACHE = 5;
 
     public static Flowable<ImageFile> detect(Context context) {
         return Flowable.create((FlowableOnSubscribe<XFile>) emitter -> {
@@ -88,12 +89,20 @@ public class ImageDeepDetector {
                             return detectWechatCache(context, xFile);
                         case GALLERY_CACHE:
                             return detectGalleryCache(context, xFile);
+                        case OPPO_GALLERY_CACHE:
+                            return detectOppoGalleryCache(context, xFile);
                         default:
                             return Flowable.empty();
                     }
                 });
     }
 
+    private static Publisher<ImageFile> detectOppoGalleryCache(Context context, XFile xFile) {
+        return new GenericImgCollectionDetector(context, xFile)
+                .subscribeOn(Schedulers.io())
+                .onErrorComplete();
+    }
+
     private static Flowable<ImageFile> detectGalleryCache(Context context, XFile xFile) {
         return new GalleryCacheDetector(context, xFile)
                 .subscribeOn(Schedulers.io())
@@ -139,6 +148,10 @@ public class ImageDeepDetector {
                 file.setTag(WECHAT_CACHE);
                 return true;
             }
+            if (isOppoGalleryCacheFile(path)) {
+                file.setTag(OPPO_GALLERY_CACHE);
+                return true;
+            }
         } catch (Exception ignore) {
         }
         if (hasJpgMagic(file)) {
@@ -193,6 +206,18 @@ public class ImageDeepDetector {
                 name.contains("com.tencent.mm/cache/imgcache/cache.data");
     }
 
+    private static boolean isOppoGalleryCacheFile(String path) {
+        if (TextUtils.isEmpty(path)) {
+            return false;
+        }
+        if (!path.contains("com.coloros.gallery3d%2Fcache") &&
+                !path.contains("com.coloros.gallery3d/cache")) {
+            return false;
+        }
+        return path.contains("imgcache") || path.contains("screennailcache")
+                || path.contains("tilecache");
+    }
+
     private static boolean isImageSuffix(String name) {
         if (TextUtils.isEmpty(name)) {
             return false;
@@ -338,7 +363,7 @@ public class ImageDeepDetector {
 
             try (InputStream inputStream = xFile.newInputStream()) {
                 ArrayList<Byte> imageBytes = new ArrayList<>();
-                byte[] buffer = new byte[1024];
+                byte[] buffer = new byte[2048];
                 int read;
                 while ((read = inputStream.read(buffer)) != -1) {
                     for (int i = 0; i < read; i++) {
@@ -817,4 +842,97 @@ public class ImageDeepDetector {
             }
         }
     }
+
+    private static class GenericImgCollectionDetector extends Flowable<ImageFile> {
+
+        private String CACHE_DOMAIN = "generic_img_collection_detector";
+        private final Context context;
+        private final XFile xFile;
+
+        public GenericImgCollectionDetector(Context context, XFile xFile) {
+            this.context = context;
+            this.xFile = xFile;
+        }
+
+        @Override
+        protected void subscribeActual(@NonNull Subscriber<? super ImageFile> subscriber) {
+            long lastModified;
+            try {
+                lastModified = xFile.lastModified();
+                CACHE_DOMAIN += xFile.getName();
+            } catch (Exception e) {
+                subscriber.onError(e);
+                return;
+            }
+
+            if (checkDetectedCache(context, lastModified, subscriber)) {
+                subscriber.onComplete();
+                return;
+            } else {
+                clearDetectedCache(context, CACHE_DOMAIN);
+            }
+
+            File detectedCacheDir = getDetectedCacheDir(context, CACHE_DOMAIN);
+            detectedCacheDir = new File(detectedCacheDir, CryptoUtils.HASH.md5(String.valueOf(lastModified)));
+            if (!detectedCacheDir.exists()) {
+                detectedCacheDir.mkdirs();
+            }
+
+            try (InputStream inputStream = xFile.newInputStream()) {
+                ArrayList<Byte> imageBytes = new ArrayList<>();
+                byte[] buffer = new byte[2048];
+                int read;
+                while ((read = inputStream.read(buffer)) != -1) {
+                    for (int i = 0; i < read; i++) {
+                        byte b = buffer[i];
+                        imageBytes.add(b);
+                        if (imageBytes.size() < 2) {
+                            continue;
+                        }
+                        if (imageBytes.size() == 2) {
+                            if (imageBytes.get(0) != (byte) 0xFF || imageBytes.get(1) != (byte) 0xD8) {
+                                imageBytes.remove(0);
+                            }
+                            continue;
+                        }
+                        if (i == read - 1 && inputStream.available() == 0) {
+                            if (imageBytes.get(imageBytes.size() - 2) == (byte) 0xFF && imageBytes.get(imageBytes.size() - 1) == (byte) 0xD9) {
+                                File cache = new File(detectedCacheDir, UUID.randomUUID() + ".jpg");
+                                if (cache.createNewFile() && bytes2File(imageBytes, cache)) {
+                                    subscriber.onNext(new ImageFile(new XPathFile(context, cache)));
+                                }
+                            }
+                            imageBytes.clear();
+                        } else if (imageBytes.size() >= 4) {
+                            if (imageBytes.get(imageBytes.size() - 1) == (byte) 0xD9
+                                    && imageBytes.get(imageBytes.size() - 2) == (byte) 0xFF
+                            ) {
+                                File cache = new File(detectedCacheDir, UUID.randomUUID() + ".jpg");
+                                if (cache.createNewFile() && bytes2File(imageBytes, cache)) {
+                                    subscriber.onNext(new ImageFile(new XPathFile(context, cache)));
+                                }
+                                imageBytes.clear();
+                            }
+                        }
+                    }
+                }
+                subscriber.onComplete();
+            } catch (Exception e) {
+                subscriber.onError(e);
+            }
+        }
+
+        private boolean checkDetectedCache(Context context, long lastModified, Subscriber<? super ImageFile> subscriber) {
+            File detectedCacheDir = getDetectedCacheDir(context, CACHE_DOMAIN);
+            File targetCaches = new File(detectedCacheDir, CryptoUtils.HASH.md5(String.valueOf(lastModified)));
+            File[] files = targetCaches.exists() && targetCaches.isDirectory() ? targetCaches.listFiles() : null;
+            if (files != null && files.length > 0) {
+                for (File file : files) {
+                    subscriber.onNext(new ImageFile(new XPathFile(this.context, file)));
+                }
+                return true;
+            }
+            return false;
+        }
+    }
 }

+ 0 - 2
app/src/main/java/com/datarecovery/master/utils/xfile/XFileSearch.java

@@ -5,7 +5,6 @@ import android.net.Uri;
 import android.os.Build;
 import android.os.CancellationSignal;
 import android.os.storage.StorageVolume;
-import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
@@ -100,7 +99,6 @@ public class XFileSearch {
 
                 @Override
                 public void onEachFile(XFile file) {
-                    Log.d("lzplzp", "onEachFile: " + finalCurrentIndex);
                     if (callback != null) {
                         callback.onEachFile(file);
                     }