|
|
@@ -3,6 +3,8 @@ package com.datarecovery.master.utils;
|
|
|
import static android.content.Context.POWER_SERVICE;
|
|
|
|
|
|
import android.content.Context;
|
|
|
+import android.database.Cursor;
|
|
|
+import android.database.sqlite.SQLiteDatabase;
|
|
|
import android.net.Uri;
|
|
|
import android.os.CancellationSignal;
|
|
|
import android.os.PowerManager;
|
|
|
@@ -50,6 +52,7 @@ public class ImageDeepDetector {
|
|
|
private static final int VIVO_GALLERY_CACHE = 6;
|
|
|
private static final int XIAOMI_GALLERY_CACHE = 7;
|
|
|
private static final int MEIZU_GALLERY_CACHE = 8;
|
|
|
+ private static final int HUAWEI_GALLERY_CACHE = 9;
|
|
|
|
|
|
public static Flowable<List<ImageFile>> detect(Context context) {
|
|
|
return Flowable.create((FlowableOnSubscribe<XFile>) emitter -> {
|
|
|
@@ -110,6 +113,8 @@ public class ImageDeepDetector {
|
|
|
return detectVivoGalleryCache(context, xFile);
|
|
|
case MEIZU_GALLERY_CACHE:
|
|
|
return detectMeizuGalleryCache(context, xFile);
|
|
|
+ case HUAWEI_GALLERY_CACHE:
|
|
|
+ return detectHuaweiGalleryCache(context, xFile);
|
|
|
default:
|
|
|
return Flowable.empty();
|
|
|
}
|
|
|
@@ -151,12 +156,13 @@ public class ImageDeepDetector {
|
|
|
if (path.contains("com.kuaishou.nebula") && (path.contains("live_gift_store_icon_directory") ||
|
|
|
path.contains("magic_finger_resource") || path.contains("theme_resource") ||
|
|
|
path.contains("magic_emoji_resource") || path.contains(".material_library_resource") ||
|
|
|
- path.contains("sticker_resource")
|
|
|
+ path.contains("sticker_resource") || path.contains("preload%2Ficon%2Fcommon") ||
|
|
|
+ path.contains("preload/icon/common") || path.contains(".emoji")
|
|
|
)) {
|
|
|
return true;
|
|
|
}
|
|
|
if ((path.contains("com.tencent.mobileqq") || path.contains("com.tencent.tim")) && (path.contains("qvideo_newvideo_tips") ||
|
|
|
- path.contains("Gameicon"))) {
|
|
|
+ path.contains("Gameicon") || path.contains("html5") || path.contains(".preloaduni"))) {
|
|
|
return true;
|
|
|
}
|
|
|
if ((path.contains("com.ss.android.article.video") || path.contains("com.ss.android.ugc.aweme")) && (path.contains("liveroom") ||
|
|
|
@@ -171,7 +177,8 @@ public class ImageDeepDetector {
|
|
|
if ((path.contains("com.baidu.BaiduMap")) && (path.contains("sticker"))) {
|
|
|
return true;
|
|
|
}
|
|
|
- if ((path.contains("com.eg.android.AlipayGphone")) && (path.contains("Sandbox"))) {
|
|
|
+ if ((path.contains("com.eg.android.AlipayGphone")) && (path.contains("Sandbox") ||
|
|
|
+ path.contains("emojiFiles"))) {
|
|
|
return true;
|
|
|
}
|
|
|
if ((path.contains("air.tv.douyu.android")) && (path.contains("skin_download_dir"))) {
|
|
|
@@ -186,11 +193,23 @@ public class ImageDeepDetector {
|
|
|
if (path.contains("bddownload/common") || path.contains("bddownload%2Fcommon")) {
|
|
|
return true;
|
|
|
}
|
|
|
+ if (path.contains("Pictures/.gs_fs") || path.contains("Pictures%2F.gs_fs")) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (path.contains("__MACOSX")) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
} catch (Exception ignore) {
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ private static Flowable<ImageFile> detectHuaweiGalleryCache(Context context, XFile xFile) {
|
|
|
+ return new HuaweiGalleryCacheDetector(context, xFile)
|
|
|
+ .subscribeOn(Schedulers.io())
|
|
|
+ .onErrorComplete();
|
|
|
+ }
|
|
|
+
|
|
|
private static Flowable<ImageFile> detectMeizuGalleryCache(Context context, XFile xFile) {
|
|
|
return new GenericImgCollectionDetector(context, xFile, ImageFile.CATEGORY_GALLERY)
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
@@ -270,6 +289,10 @@ public class ImageDeepDetector {
|
|
|
file.setTag(MEIZU_GALLERY_CACHE);
|
|
|
return true;
|
|
|
}
|
|
|
+ if (isHuaweiGalleryCacheFile(path)) {
|
|
|
+ file.setTag(HUAWEI_GALLERY_CACHE);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
} catch (Exception ignore) {
|
|
|
}
|
|
|
if (hasImgMagic(file)) {
|
|
|
@@ -372,6 +395,17 @@ public class ImageDeepDetector {
|
|
|
|| path.contains("uri_thumbnail_cache");
|
|
|
}
|
|
|
|
|
|
+ private static boolean isHuaweiGalleryCacheFile(String path) {
|
|
|
+ if (TextUtils.isEmpty(path)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!path.contains("com.huawei.photos%2Ffiles%2Fthumbdb") &&
|
|
|
+ !path.contains("com.huawei.photos/files/thumbdb")) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return path.endsWith("photoshare.db");
|
|
|
+ }
|
|
|
+
|
|
|
private static boolean isImageSuffix(String name) {
|
|
|
if (TextUtils.isEmpty(name)) {
|
|
|
return false;
|
|
|
@@ -599,7 +633,7 @@ public class ImageDeepDetector {
|
|
|
}
|
|
|
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");
|
|
|
+ File cache = new File(detectedCacheDir, UUID.randomUUID().toString());
|
|
|
if (cache.createNewFile() && bytes2File(imageBytes, cache)) {
|
|
|
subscriber.onNext(new ImageFile(new XPathFile(context, cache), ImageFile.CATEGORY_WECHAT));
|
|
|
}
|
|
|
@@ -613,7 +647,7 @@ public class ImageDeepDetector {
|
|
|
) {
|
|
|
imageBytes.remove(imageBytes.size() - 1);
|
|
|
imageBytes.remove(imageBytes.size() - 1);
|
|
|
- File cache = new File(detectedCacheDir, UUID.randomUUID() + ".jpg");
|
|
|
+ File cache = new File(detectedCacheDir, UUID.randomUUID().toString());
|
|
|
if (cache.createNewFile() && bytes2File(imageBytes, cache)) {
|
|
|
subscriber.onNext(new ImageFile(new XPathFile(context, cache), ImageFile.CATEGORY_WECHAT));
|
|
|
}
|
|
|
@@ -772,7 +806,7 @@ public class ImageDeepDetector {
|
|
|
if (cropData == null) {
|
|
|
continue;
|
|
|
}
|
|
|
- File cache = new File(detectedCacheDir, UUID.randomUUID() + ".jpg");
|
|
|
+ File cache = new File(detectedCacheDir, UUID.randomUUID().toString());
|
|
|
if (cache.createNewFile() && bytes2File(cropData, cache)) {
|
|
|
subscriber.onNext(new ImageFile(new XPathFile(context, cache), ImageFile.CATEGORY_GALLERY));
|
|
|
}
|
|
|
@@ -1118,7 +1152,7 @@ public class ImageDeepDetector {
|
|
|
}
|
|
|
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");
|
|
|
+ File cache = new File(detectedCacheDir, UUID.randomUUID().toString());
|
|
|
if (cache.createNewFile() && bytes2File(imageBytes, cache)) {
|
|
|
subscriber.onNext(new ImageFile(new XPathFile(context, cache), category));
|
|
|
}
|
|
|
@@ -1128,7 +1162,7 @@ public class ImageDeepDetector {
|
|
|
if (imageBytes.get(imageBytes.size() - 1) == (byte) 0xD9
|
|
|
&& imageBytes.get(imageBytes.size() - 2) == (byte) 0xFF
|
|
|
) {
|
|
|
- File cache = new File(detectedCacheDir, UUID.randomUUID() + ".jpg");
|
|
|
+ File cache = new File(detectedCacheDir, UUID.randomUUID().toString());
|
|
|
if (cache.createNewFile() && bytes2File(imageBytes, cache)) {
|
|
|
subscriber.onNext(new ImageFile(new XPathFile(context, cache), category));
|
|
|
}
|
|
|
@@ -1156,4 +1190,109 @@ public class ImageDeepDetector {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ private static class HuaweiGalleryCacheDetector extends Flowable<ImageFile> {
|
|
|
+
|
|
|
+ private static final String CACHE_DOMAIN = "huawei_gallery_cache_detector";
|
|
|
+ private final Context context;
|
|
|
+ private final XFile dbFile;
|
|
|
+
|
|
|
+ public HuaweiGalleryCacheDetector(Context context, XFile dbFile) {
|
|
|
+ this.context = context;
|
|
|
+ this.dbFile = dbFile;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void subscribeActual(@NonNull Subscriber<? super ImageFile> subscriber) {
|
|
|
+ long lastModified;
|
|
|
+ try {
|
|
|
+ lastModified = dbFile.lastModified();
|
|
|
+ } 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();
|
|
|
+ }
|
|
|
+
|
|
|
+ File dbTempFile;
|
|
|
+ try {
|
|
|
+ dbTempFile = createDbTempFile(detectedCacheDir);
|
|
|
+ } catch (Exception e) {
|
|
|
+ subscriber.onError(e);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try (SQLiteDatabase sqLiteDatabase = SQLiteDatabase.openDatabase(dbTempFile.getPath(), null, SQLiteDatabase.OPEN_READONLY);
|
|
|
+ Cursor cursor = sqLiteDatabase.rawQuery("select * from general_kv", null)
|
|
|
+ ) {
|
|
|
+ int vIndex = cursor.getColumnIndex("v");
|
|
|
+ if (vIndex == -1) {
|
|
|
+ subscriber.onComplete();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ while (cursor.moveToNext()) {
|
|
|
+ byte[] data = cursor.getBlob(vIndex);
|
|
|
+ if (data == null || data.length == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ File cache = new File(detectedCacheDir, UUID.randomUUID().toString());
|
|
|
+ if (cache.createNewFile() && bytes2File(data, cache)) {
|
|
|
+ subscriber.onNext(new ImageFile(new XPathFile(context, cache), ImageFile.CATEGORY_GALLERY));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ subscriber.onComplete();
|
|
|
+ } catch (Exception e) {
|
|
|
+ subscriber.onError(e);
|
|
|
+ } finally {
|
|
|
+ if (dbTempFile != null && dbTempFile.exists()) {
|
|
|
+ dbTempFile.delete();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private File createDbTempFile(File detectedCacheDir) throws Exception {
|
|
|
+ File dbTempFile = new File(detectedCacheDir, "huawei_gallery_cache_detector.db");
|
|
|
+ if (dbTempFile.exists()) {
|
|
|
+ dbTempFile.delete();
|
|
|
+ }
|
|
|
+ try (InputStream inputStream = dbFile.newInputStream();
|
|
|
+ OutputStream outputStream = new FileOutputStream(dbTempFile)
|
|
|
+ ) {
|
|
|
+ byte[] buffer = new byte[2048];
|
|
|
+ int read;
|
|
|
+ while ((read = inputStream.read(buffer)) != -1) {
|
|
|
+ outputStream.write(buffer, 0, read);
|
|
|
+ }
|
|
|
+ outputStream.flush();
|
|
|
+ return dbTempFile;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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) {
|
|
|
+ if (file.getName().endsWith(".db")) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ subscriber.onNext(new ImageFile(new XPathFile(this.context, file), ImageFile.CATEGORY_GALLERY));
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|