ImageRecoverViewModel.java 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. package com.datarecovery.master.module.imgrecover;
  2. import android.content.ContentResolver;
  3. import android.content.ContentUris;
  4. import android.content.Context;
  5. import android.database.Cursor;
  6. import android.net.Uri;
  7. import android.os.Build;
  8. import android.provider.MediaStore;
  9. import android.text.TextUtils;
  10. import android.util.Pair;
  11. import androidx.lifecycle.LiveData;
  12. import androidx.lifecycle.MutableLiveData;
  13. import androidx.lifecycle.Transformations;
  14. import com.atmob.app.lib.base.BaseViewModel;
  15. import com.atmob.app.lib.livedata.SingleLiveEvent;
  16. import com.atmob.common.logging.AtmobLog;
  17. import com.atmob.common.runtime.ActivityUtil;
  18. import com.atmob.common.runtime.ContextUtil;
  19. import com.datarecovery.master.R;
  20. import com.datarecovery.master.data.consts.AdFuncId;
  21. import com.datarecovery.master.module.member.MemberActivity;
  22. import com.datarecovery.master.module.member.MemberType;
  23. import com.datarecovery.master.sdk.ad.AtmobAdHelper;
  24. import com.datarecovery.master.sdk.bugly.BuglyHelper;
  25. import com.datarecovery.master.utils.BoxingUtil;
  26. import com.datarecovery.master.utils.FileUtil;
  27. import com.datarecovery.master.utils.ImageDeepDetector;
  28. import com.datarecovery.master.utils.MediaStoreHelper;
  29. import com.datarecovery.master.utils.ReverseArrayList;
  30. import com.datarecovery.master.utils.ToastUtil;
  31. import org.reactivestreams.Subscription;
  32. import java.io.File;
  33. import java.util.ArrayList;
  34. import java.util.Iterator;
  35. import java.util.List;
  36. import java.util.Objects;
  37. import java.util.concurrent.TimeUnit;
  38. import javax.inject.Inject;
  39. import atmob.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
  40. import atmob.reactivex.rxjava3.annotations.NonNull;
  41. import atmob.reactivex.rxjava3.core.FlowableSubscriber;
  42. import atmob.reactivex.rxjava3.core.Single;
  43. import atmob.reactivex.rxjava3.core.SingleObserver;
  44. import atmob.reactivex.rxjava3.core.SingleOnSubscribe;
  45. import atmob.reactivex.rxjava3.core.SingleSource;
  46. import atmob.reactivex.rxjava3.disposables.Disposable;
  47. import atmob.reactivex.rxjava3.schedulers.Schedulers;
  48. import atmob.rxjava.utils.RxJavaUtil;
  49. import dagger.hilt.android.lifecycle.HiltViewModel;
  50. @HiltViewModel
  51. public class ImageRecoverViewModel extends BaseViewModel {
  52. private final long SCANNING_COUNTDOWN = 1000 * 60 * 8;
  53. private final long SCANNING_IS_TRIAL_COUNTDOWN = 1000 * 5;
  54. private final List<ImageDeepDetector.ImageFile> detectedPhotoList = new ReverseArrayList<>();
  55. private final List<ImageDeepDetector.ImageFile> detectedWxList = new ReverseArrayList<>();
  56. private final List<ImageDeepDetector.ImageFile> detectedQQList = new ReverseArrayList<>();
  57. private final List<ImageDeepDetector.ImageFile> detectedOtherList = new ReverseArrayList<>();
  58. private final List<ImageDeepDetector.ImageFile> selectList = new ReverseArrayList<>();
  59. private final MutableLiveData<List<ImageDeepDetector.ImageFile>> detectedPhotoImg = new MutableLiveData<>(detectedPhotoList);
  60. private final MutableLiveData<List<ImageDeepDetector.ImageFile>> detectedWxImg = new MutableLiveData<>(detectedWxList);
  61. private final MutableLiveData<List<ImageDeepDetector.ImageFile>> detectedQQImg = new MutableLiveData<>(detectedQQList);
  62. private final MutableLiveData<List<ImageDeepDetector.ImageFile>> detectedOtherImg = new MutableLiveData<>(detectedOtherList);
  63. private final MutableLiveData<List<ImageDeepDetector.ImageFile>> selectedList = new MutableLiveData<>(selectList);
  64. private final SingleLiveEvent<List<Uri>> deleteUriListSdk11 = new SingleLiveEvent<>();
  65. private final SingleLiveEvent<?> showTrialFinishDialog = new SingleLiveEvent<>();
  66. private final SingleLiveEvent<?> showTrialExportFailDialog = new SingleLiveEvent<>();
  67. private final SingleLiveEvent<ImageDeepDetector.ImageFile> failScrollPosition = new SingleLiveEvent<>();
  68. private final MutableLiveData<Boolean> showTrialView = new MutableLiveData<>();
  69. private final SingleLiveEvent<Pair<List<ImageDeepDetector.ImageFile>, Integer>> previewEvent = new SingleLiveEvent<>();
  70. private final SingleLiveEvent<Boolean> showScanDialogEvent = new SingleLiveEvent<>();
  71. private final SingleLiveEvent<Boolean> showLoadingEvent = new SingleLiveEvent<>();
  72. private final SingleLiveEvent<?> scrollTop = new SingleLiveEvent<>();
  73. private final SingleLiveEvent<?> notifyList = new SingleLiveEvent<>();
  74. private final MutableLiveData<String> barTitle = new MutableLiveData<>();
  75. private final MutableLiveData<Boolean> checkAll = new MutableLiveData<>(false);
  76. private final MutableLiveData<String> detectedLastFileName = new MutableLiveData<>();
  77. private final SingleLiveEvent<?> onExportClickEvent = new SingleLiveEvent<>();
  78. private LiveData<String> detectedPhotoTitle;
  79. private LiveData<String> detectedWxTitle;
  80. private LiveData<String> detectedQQTitle;
  81. private LiveData<String> detectedOtherTitle;
  82. private LiveData<String> selectedCountTxt;
  83. private Disposable scanDisposable;
  84. @MemberType
  85. private String type;
  86. private SingleObserver<? super Boolean> dealMediaObserver;
  87. private long detectTime;
  88. @Inject
  89. public ImageRecoverViewModel() {
  90. barTitle.setValue(ContextUtil.getContext().getString(R.string.iamge_recover_all));
  91. initLiveData();
  92. }
  93. public LiveData<ImageDeepDetector.ImageFile> getFailScrollPosition() {
  94. return failScrollPosition;
  95. }
  96. public LiveData<?> getScrollTop() {
  97. return scrollTop;
  98. }
  99. public LiveData<?> getShowTrialFinishDialog() {
  100. return showTrialFinishDialog;
  101. }
  102. public LiveData<?> getShowTrialExportFailDialog() {
  103. return showTrialExportFailDialog;
  104. }
  105. public LiveData<String> getDetectedLastFileName() {
  106. return detectedLastFileName;
  107. }
  108. public LiveData<Boolean> getShowTrialView() {
  109. return showTrialView;
  110. }
  111. public LiveData<List<Uri>> getDeleteUriListSdk11() {
  112. return deleteUriListSdk11;
  113. }
  114. public LiveData<?> getNotifyList() {
  115. return notifyList;
  116. }
  117. public LiveData<Boolean> getShowLoadingEvent() {
  118. return showLoadingEvent;
  119. }
  120. public LiveData<Pair<List<ImageDeepDetector.ImageFile>, Integer>> getPreviewEvent() {
  121. return previewEvent;
  122. }
  123. public LiveData<String> getSelectedCountTxt() {
  124. return selectedCountTxt;
  125. }
  126. public LiveData<List<ImageDeepDetector.ImageFile>> getSelectedList() {
  127. return selectedList;
  128. }
  129. public LiveData<List<ImageDeepDetector.ImageFile>> getDetectedPhotoImg() {
  130. return detectedPhotoImg;
  131. }
  132. public LiveData<List<ImageDeepDetector.ImageFile>> getDetectedWxImg() {
  133. return detectedWxImg;
  134. }
  135. public LiveData<List<ImageDeepDetector.ImageFile>> getDetectedQQImg() {
  136. return detectedQQImg;
  137. }
  138. public LiveData<List<ImageDeepDetector.ImageFile>> getDetectedOtherImg() {
  139. return detectedOtherImg;
  140. }
  141. public LiveData<String> getDetectedPhotoTitle() {
  142. return detectedPhotoTitle;
  143. }
  144. public LiveData<String> getDetectedWxTitle() {
  145. return detectedWxTitle;
  146. }
  147. public LiveData<String> getDetectedQQTitle() {
  148. return detectedQQTitle;
  149. }
  150. public LiveData<String> getDetectedOtherTitle() {
  151. return detectedOtherTitle;
  152. }
  153. public LiveData<Boolean> getShowScanDialogEvent() {
  154. return showScanDialogEvent;
  155. }
  156. public LiveData<Boolean> getCheckAll() {
  157. return checkAll;
  158. }
  159. public LiveData<String> getBarTitle() {
  160. return barTitle;
  161. }
  162. public LiveData<?> getOnExportClickEvent() {
  163. return onExportClickEvent;
  164. }
  165. public String getType() {
  166. return type;
  167. }
  168. public void setType(@MemberType String type) {
  169. if (!TextUtils.isEmpty(this.type)) {
  170. return;
  171. }
  172. this.type = type;
  173. switch (type) {
  174. case MemberType.APP_IMAGE_CLEAN:
  175. selectedCountTxt = Transformations.map(selectedList, list -> {
  176. if (list == null || list.isEmpty()) {
  177. return ContextUtil.getContext().getString(R.string.delete);
  178. }
  179. return ContextUtil.getContext().getString(R.string.delete_count, list.size());
  180. });
  181. break;
  182. case MemberType.APP_IMAGE_RECOVER:
  183. selectedCountTxt = Transformations.map(selectedList, list -> {
  184. if (list == null || list.isEmpty()) {
  185. return ContextUtil.getContext().getString(R.string.export);
  186. }
  187. return ContextUtil.getContext().getString(R.string.export_count, list.size());
  188. });
  189. break;
  190. }
  191. }
  192. private void initLiveData() {
  193. detectedPhotoTitle = Transformations.map(detectedPhotoImg, list ->
  194. ContextUtil.getContext().getString(R.string.photo_count, (list == null || list.isEmpty()) ? 0 : list.size()));
  195. detectedWxTitle = Transformations.map(detectedWxImg, list ->
  196. ContextUtil.getContext().getString(R.string.wx_count, (list == null || list.isEmpty()) ? 0 : list.size()));
  197. detectedQQTitle = Transformations.map(detectedQQImg, list ->
  198. ContextUtil.getContext().getString(R.string.qq_count, (list == null || list.isEmpty()) ? 0 : list.size()));
  199. detectedOtherTitle = Transformations.map(detectedOtherImg, list ->
  200. ContextUtil.getContext().getString(R.string.other_count, (list == null || list.isEmpty()) ? 0 : list.size()));
  201. }
  202. public void onCheckAllClick(boolean isCheck) {
  203. checkAll.setValue(isCheck);
  204. setListCheck(detectedPhotoList, isCheck);
  205. setListCheck(detectedWxList, isCheck);
  206. setListCheck(detectedQQList, isCheck);
  207. setListCheck(detectedOtherList, isCheck);
  208. if (isCheck) {
  209. selectList.clear();
  210. selectList.addAll(detectedPhotoList);
  211. selectList.addAll(detectedWxList);
  212. selectList.addAll(detectedQQList);
  213. selectList.addAll(detectedOtherList);
  214. } else {
  215. selectList.clear();
  216. }
  217. selectedList.setValue(selectList);
  218. }
  219. private void setListCheck(List<ImageDeepDetector.ImageFile> list, boolean isCheck) {
  220. if (list == null || list.isEmpty()) {
  221. return;
  222. }
  223. for (ImageDeepDetector.ImageFile imageFile : list) {
  224. imageFile.setCheck(isCheck);
  225. }
  226. }
  227. public void startImageScanning() {
  228. if (scanDisposable != null && !scanDisposable.isDisposed()) {
  229. return;
  230. }
  231. ImageDeepDetector.detect(ContextUtil.getContext(), type)
  232. .take(SCANNING_COUNTDOWN, TimeUnit.MILLISECONDS)
  233. .observeOn(AndroidSchedulers.mainThread())
  234. .subscribe(new FlowableSubscriber<List<ImageDeepDetector.ImageFile>>() {
  235. @Override
  236. public void onSubscribe(@NonNull Subscription s) {
  237. s.request(Integer.MAX_VALUE);
  238. scanDisposable = Disposable.fromSubscription(s);
  239. addDisposable(scanDisposable);
  240. showScanDialogEvent.setValue(true);
  241. checkAll.setValue(false);
  242. detectTime = System.currentTimeMillis();
  243. detectedPhotoList.clear();
  244. detectedWxList.clear();
  245. detectedQQList.clear();
  246. detectedOtherList.clear();
  247. selectList.clear();
  248. }
  249. @Override
  250. public void onNext(List<ImageDeepDetector.ImageFile> imageFiles) {
  251. if (imageFiles == null) {
  252. return;
  253. }
  254. int photoCount = 0;
  255. int wxCount = 0;
  256. int qqCount = 0;
  257. int otherCount = 0;
  258. for (ImageDeepDetector.ImageFile imageFile : imageFiles) {
  259. detectedLastFileName.setValue(imageFile.getName());
  260. if (imageFile.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_GALLERY) {
  261. detectedPhotoList.add(imageFile);
  262. photoCount++;
  263. } else if (imageFile.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_WECHAT) {
  264. detectedWxList.add(imageFile);
  265. wxCount++;
  266. } else if (imageFile.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_QQ) {
  267. detectedQQList.add(imageFile);
  268. qqCount++;
  269. } else {
  270. detectedOtherList.add(imageFile);
  271. otherCount++;
  272. }
  273. }
  274. if (photoCount > 0) {
  275. detectedPhotoImg.setValue(detectedPhotoList);
  276. }
  277. if (wxCount > 0) {
  278. detectedWxImg.setValue(detectedWxList);
  279. }
  280. if (qqCount > 0) {
  281. detectedQQImg.setValue(detectedQQList);
  282. }
  283. if (otherCount > 0) {
  284. detectedOtherImg.setValue(detectedOtherList);
  285. }
  286. scrollTop.call();
  287. }
  288. @Override
  289. public void onError(Throwable t) {
  290. showScanDialogEvent.setValue(false);
  291. }
  292. @Override
  293. public void onComplete() {
  294. AtmobLog.d("ImageRecoverViewModel", System.currentTimeMillis() - detectTime + "ms");
  295. showScanDialogEvent.setValue(false);
  296. }
  297. });
  298. }
  299. public void cancelScan() {
  300. if (scanDisposable != null && !scanDisposable.isDisposed()) scanDisposable.dispose();
  301. showScanDialogEvent.setValue(false);
  302. }
  303. public void setItemCheck(@NonNull ImageDeepDetector.ImageFile imageFile) {
  304. imageFile.setCheck(!imageFile.isCheck());
  305. if (imageFile.isCheck()) {
  306. selectList.add(imageFile);
  307. } else {
  308. selectList.remove(imageFile);
  309. }
  310. selectedList.setValue(selectList);
  311. }
  312. public void checkPreview(@NonNull ImageDeepDetector.ImageFile imageFile) {
  313. if (Objects.equals(type, MemberType.APP_IMAGE_CLEAN)) {
  314. return;
  315. }
  316. sendPreviewEvent(imageFile);
  317. }
  318. public void sendPreviewEvent(@NonNull ImageDeepDetector.ImageFile imageFile) {
  319. List<ImageDeepDetector.ImageFile> allDetectedList = getAllDetectedList();
  320. int position = getPosition(allDetectedList, imageFile);
  321. previewEvent.setValue(new Pair<>(allDetectedList, position));
  322. }
  323. public void onOperationClick() {
  324. if (selectList.isEmpty()) {
  325. return;
  326. }
  327. onExportClickEvent.call();
  328. }
  329. public void executeImageDelete() {
  330. if (selectList.isEmpty()) {
  331. return;
  332. }
  333. Single.just(Build.VERSION.SDK_INT)
  334. .map(sdkInt -> sdkInt >= Build.VERSION_CODES.R)
  335. .map(isSdk11 -> {
  336. List<ImageDeepDetector.ImageFile> safList = new ArrayList<>();
  337. List<ImageDeepDetector.ImageFile> uriList = new ArrayList<>();
  338. if (isSdk11) {
  339. for (ImageDeepDetector.ImageFile item : selectList) {
  340. File tempFile = new File(item.getPath());
  341. long mediaID = getFilePathToMediaID(tempFile.getAbsolutePath(), ContextUtil.getContext());
  342. if (mediaID > 0) {
  343. Uri externalUri = ContentUris.withAppendedId(MediaStore.Images.Media.getContentUri("external"), mediaID);
  344. item.setExternalUri(externalUri);
  345. uriList.add(item);
  346. } else {
  347. safList.add(item);
  348. }
  349. }
  350. } else {
  351. safList.addAll(selectList);
  352. }
  353. return new Pair<>(safList, uriList);
  354. })
  355. .flatMap(pair -> Single.zip(
  356. imageDelete(pair.first).subscribeOn(Schedulers.io()),
  357. externalDelete(pair.second).subscribeOn(Schedulers.io()),
  358. Pair::new
  359. ))
  360. .compose(RxJavaUtil.SingleSchedule.io2Main())
  361. .subscribe(new SingleObserver<Pair<Pair<ImageDeepDetector.ImageFile, Exception>, Pair<ImageDeepDetector.ImageFile, Exception>>>() {
  362. @Override
  363. public void onSubscribe(@NonNull Disposable d) {
  364. addDisposable(d);
  365. showLoadingEvent.setValue(true);
  366. }
  367. @Override
  368. public void onSuccess(@NonNull Pair<Pair<ImageDeepDetector.ImageFile, Exception>, Pair<ImageDeepDetector.ImageFile, Exception>> pairPairPair) {
  369. showLoadingEvent.setValue(false);
  370. if (pairPairPair.first.second != null) {
  371. ToastUtil.show("部分图片清除失败:" + pairPairPair.first.second.getMessage(), ToastUtil.LENGTH_SHORT);
  372. failScrollPosition.setValue(pairPairPair.first.first);
  373. return;
  374. }
  375. if (pairPairPair.second.second instanceof CancelDeleteException) {
  376. return;
  377. }
  378. if (pairPairPair.second.second != null) {
  379. ToastUtil.show("部分图片清除失败:" + pairPairPair.second.second.getMessage(), ToastUtil.LENGTH_SHORT);
  380. failScrollPosition.setValue(pairPairPair.second.first);
  381. return;
  382. }
  383. if (pairPairPair.first.first == null && pairPairPair.second.first == null) {
  384. ToastUtil.show(R.string.delete_success, ToastUtil.LENGTH_SHORT);
  385. }
  386. AtmobAdHelper.showInterstitial(AdFuncId.INTERSTITIAL_CLEAN_SUCCESS, null);
  387. }
  388. @Override
  389. public void onError(@NonNull Throwable e) {
  390. showLoadingEvent.setValue(false);
  391. ToastUtil.show(R.string.delete_fail, ToastUtil.LENGTH_SHORT);
  392. }
  393. });
  394. }
  395. private @NonNull Single<Pair<ImageDeepDetector.ImageFile, Exception>> externalDelete(List<ImageDeepDetector.ImageFile> externalList) {
  396. return Single.create((SingleOnSubscribe<List<Uri>>) emitter -> {
  397. List<Uri> uriDeleteList = new ArrayList<>();
  398. if (externalList.isEmpty()) {
  399. emitter.onSuccess(uriDeleteList);
  400. return;
  401. }
  402. for (ImageDeepDetector.ImageFile item : externalList) {
  403. uriDeleteList.add(item.getExternalUri());
  404. }
  405. emitter.onSuccess(uriDeleteList);
  406. })
  407. .flatMap(uriDeleteList -> {
  408. if (!uriDeleteList.isEmpty()) {
  409. deleteUriListSdk11.postValue(uriDeleteList);
  410. return (SingleSource<Boolean>) observer -> this.dealMediaObserver = observer;
  411. } else {
  412. return Single.just(true);
  413. }
  414. })
  415. .flatMap(state -> {
  416. if (BoxingUtil.boxing(state)) {
  417. Exception exception = null;
  418. ImageDeepDetector.ImageFile deleteError = null;
  419. for (ImageDeepDetector.ImageFile item : externalList) {
  420. try {
  421. item.delete();
  422. selectList.remove(item);
  423. if (item.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_GALLERY) {
  424. detectedPhotoList.remove(item);
  425. } else if (item.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_WECHAT) {
  426. detectedWxList.remove(item);
  427. } else if (item.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_QQ) {
  428. detectedQQList.remove(item);
  429. } else {
  430. detectedOtherList.remove(item);
  431. }
  432. } catch (Exception throwable) {
  433. exception = throwable;
  434. deleteError = item;
  435. BuglyHelper.postCatchedException(new Exception("图片删除External:", throwable));
  436. }
  437. }
  438. selectedList.postValue(selectList);
  439. notifyList.postValue(null);
  440. return Single.just(new Pair<>(deleteError, exception));
  441. } else {
  442. return Single.just(new Pair<>(null, new CancelDeleteException()));
  443. }
  444. });
  445. }
  446. private Single<Pair<ImageDeepDetector.ImageFile, Exception>> imageDelete(List<ImageDeepDetector.ImageFile> safList) {
  447. return Single.create(emitter -> {
  448. Exception exception = null;
  449. ImageDeepDetector.ImageFile deleteError = null;
  450. if (safList.isEmpty()) {
  451. emitter.onSuccess(new Pair<>(deleteError, exception));
  452. return;
  453. }
  454. for (ImageDeepDetector.ImageFile item : safList) {
  455. try {
  456. item.delete();
  457. selectList.remove(item);
  458. if (item.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_GALLERY) {
  459. detectedPhotoList.remove(item);
  460. } else if (item.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_WECHAT) {
  461. detectedWxList.remove(item);
  462. } else if (item.getCategory() == ImageDeepDetector.ImageFile.CATEGORY_QQ) {
  463. detectedQQList.remove(item);
  464. } else {
  465. detectedOtherList.remove(item);
  466. }
  467. } catch (Exception throwable) {
  468. exception = throwable;
  469. deleteError = item;
  470. BuglyHelper.postCatchedException(new Exception("图片删除:", throwable));
  471. }
  472. }
  473. selectedList.postValue(selectList);
  474. notifyList.postValue(null);
  475. emitter.onSuccess(new Pair<>(deleteError, exception));
  476. });
  477. }
  478. public long getFilePathToMediaID(String songPath, Context context) {
  479. long id = 0;
  480. ContentResolver cr = context.getContentResolver();
  481. Uri uri = MediaStore.Files.getContentUri("external");
  482. String selection = MediaStore.Audio.Media.DATA;
  483. String[] selectionArgs = {songPath};
  484. String[] projection = {MediaStore.Audio.Media._ID};
  485. String sortOrder = MediaStore.Audio.Media.TITLE + " ASC";
  486. Cursor cursor = cr.query(uri, projection, selection + "=?", selectionArgs, null);
  487. if (cursor != null) {
  488. while (cursor.moveToNext()) {
  489. int idIndex = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
  490. id = Long.parseLong(cursor.getString(idIndex));
  491. }
  492. }
  493. return id;
  494. }
  495. public void exportImage() {
  496. if (selectList.isEmpty()) {
  497. return;
  498. }
  499. Single.just(selectList.size())
  500. .map(oldSize -> {
  501. Iterator<ImageDeepDetector.ImageFile> iterator = selectList.iterator();
  502. int errorCount = 0;
  503. Exception exception = null;
  504. while (iterator.hasNext()) {
  505. ImageDeepDetector.ImageFile item = iterator.next();
  506. try {
  507. MediaStoreHelper.saveToSharedStorage(MediaStoreHelper.TYPE_IMAGE, item.newInputStream(), FileUtil.getCreateFileName(MediaStoreHelper.TYPE_IMAGE, item.getName()));
  508. item.setCheck(false);
  509. iterator.remove();
  510. } catch (Exception throwable) {
  511. errorCount++;
  512. exception = throwable;
  513. BuglyHelper.postCatchedException(new Exception("图片导出:", throwable));
  514. }
  515. }
  516. if (errorCount == oldSize) {
  517. throw new Exception("导出失败" + (exception == null ? "" : ":" + exception.getMessage()));
  518. } else if (errorCount > 0) {
  519. throw new Exception("部分导出失败" + ":" + exception.getMessage());
  520. }
  521. return errorCount;
  522. })
  523. .compose(RxJavaUtil.SingleSchedule.io2Main())
  524. .subscribe(new SingleObserver<Integer>() {
  525. @Override
  526. public void onSubscribe(@NonNull Disposable d) {
  527. addDisposable(d);
  528. showLoadingEvent.setValue(true);
  529. }
  530. @Override
  531. public void onSuccess(@NonNull Integer integer) {
  532. showLoadingEvent.setValue(false);
  533. selectedList.setValue(selectList);
  534. checkAll.setValue(false);
  535. ToastUtil.show(R.string.export_success, ToastUtil.LENGTH_SHORT);
  536. AtmobAdHelper.showInterstitial(AdFuncId.INTERSTITIAL_RECOVER_SUCCESS, null);
  537. }
  538. @Override
  539. public void onError(@NonNull Throwable e) {
  540. showLoadingEvent.setValue(false);
  541. selectedList.setValue(selectList);
  542. ToastUtil.show(e.getMessage(), ToastUtil.LENGTH_SHORT);
  543. if (!selectList.isEmpty()) {
  544. failScrollPosition.setValue(selectList.get(0));
  545. }
  546. }
  547. });
  548. }
  549. public List<ImageDeepDetector.ImageFile> getAllDetectedList() {
  550. List<ImageDeepDetector.ImageFile> allList = new ReverseArrayList<>();
  551. allList.addAll(detectedOtherList);
  552. allList.addAll(detectedQQList);
  553. allList.addAll(detectedWxList);
  554. allList.addAll(detectedPhotoList);
  555. return allList;
  556. }
  557. public int getPosition(@NonNull List<ImageDeepDetector.ImageFile> list, ImageDeepDetector.ImageFile target) {
  558. return list.indexOf(target);
  559. }
  560. public void callDealComplete(boolean isDelete) {
  561. if (dealMediaObserver != null) {
  562. dealMediaObserver.onSuccess(isDelete);
  563. }
  564. }
  565. public void onTrialRecoverClick() {
  566. MemberActivity.start(ActivityUtil.getTopActivity(), type);
  567. }
  568. public void onViewTrialRecoverClick() {
  569. MemberActivity.start(ActivityUtil.getTopActivity(), type);
  570. }
  571. public void scrollPosition(int lastCompletelyItemPosition, int itemCount) {
  572. if (scanDisposable == null || !scanDisposable.isDisposed()) {
  573. return;
  574. }
  575. if (lastCompletelyItemPosition == itemCount - 1 && !BoxingUtil.boxing(showScanDialogEvent.getValue())) {
  576. showTrialFinishDialog.call();
  577. }
  578. }
  579. private static class CancelDeleteException extends Exception {
  580. }
  581. }