package com.mercandalli.android.apps.files.file.image; import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; import android.support.annotation.NonNull; import com.mercandalli.android.apps.files.file.FileModel; import com.mercandalli.android.apps.files.file.FileTypeModel; import com.mercandalli.android.apps.files.file.FileTypeModelENUM; import com.mercandalli.android.apps.files.file.audio.FileAudioModel; import com.mercandalli.android.apps.files.file.local.provider.FileLocalProviderManager; import com.mercandalli.android.library.base.precondition.Preconditions; import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import static com.mercandalli.android.library.base.java.FileUtils.getExtensionFromPath; import static com.mercandalli.android.library.base.java.FileUtils.getNameFromPath; import static com.mercandalli.android.library.base.java.FileUtils.getParentPathFromPath; /** * {@inheritDoc} */ /* package */ class FileImageManagerImpl extends FileImageManager { private final Context mContextApp; protected final FileLocalProviderManager mFileLocalProviderManager; @NonNull private final List<GetAllLocalImageListener> mGetAllLocalImageListeners = new ArrayList<>(); @NonNull private final List<GetLocalImageFoldersListener> mGetLocalImageFoldersListeners = new ArrayList<>(); @NonNull private final List<GetLocalImageListener> mGetLocalImageListeners = new ArrayList<>(); /* Cache */ @NonNull private final List<FileModel> mCacheGetAllLocalImage = new ArrayList<>(); @NonNull private final List<FileModel> mCacheGetLocalImagesFolders = new ArrayList<>(); private boolean mIsGetAllLocalImageLaunched; private boolean mIsGetLocalImageFoldersLaunched; protected FileImageManagerImpl(@NonNull final Context contextApp) { Preconditions.checkNotNull(contextApp); mContextApp = contextApp.getApplicationContext(); mFileLocalProviderManager = FileLocalProviderManager.getInstance(contextApp); } @Override @SuppressLint("NewApi") public void getAllLocalImage() { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { notifyLocalImageFoldersListenerFailed(); return; } if (!mCacheGetAllLocalImage.isEmpty()) { notifyAllLocalImageListenerSucceeded(mCacheGetAllLocalImage); return; } if (mIsGetAllLocalImageLaunched) { return; } mIsGetAllLocalImageLaunched = true; mFileLocalProviderManager.getFileImagePaths(new FileLocalProviderManager.GetFileImageListener() { @Override public void onGetFileImage(@NonNull final List<String> fileImagePaths) { final List<FileModel> fileModels = new ArrayList<>(); for (final String path : fileImagePaths) { if (!path.startsWith("/storage/emulated/0/Android/")) { final File file = new File(path); if (file.exists() && !file.isDirectory()) { fileModels.add(new FileModel.FileModelBuilder().file(file).build()); } } } notifyAllLocalImageListenerSucceeded(fileModels); mCacheGetAllLocalImage.clear(); mCacheGetAllLocalImage.addAll(fileModels); mIsGetAllLocalImageLaunched = false; } }); } //region getLocalImageFolders @Override @SuppressLint("NewApi") public void getLocalImageFolders() { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { notifyLocalImageFoldersListenerFailed(); return; } if (!mCacheGetLocalImagesFolders.isEmpty()) { notifyLocalImageFoldersListenerSucceeded(mCacheGetLocalImagesFolders); return; } if (mIsGetLocalImageFoldersLaunched) { return; } mIsGetLocalImageFoldersLaunched = true; mFileLocalProviderManager.getFileImagePaths( new FileLocalProviderManager.GetFileImageListener() { @Override public void onGetFileImage(@NonNull final List<String> fileImagePaths) { // Used to count the number of music inside. final Map<String, MutableInt> directories = new HashMap<>(); for (final String path : fileImagePaths) { final String parentPath = getParentPathFromPath(path); final MutableInt count = directories.get(parentPath); if (count == null) { directories.put(parentPath, new MutableInt()); } else { count.increment(); } } final List<FileModel> result = new ArrayList<>(); for (String path : directories.keySet()) { if (!path.startsWith("/storage/emulated/0/Android/")) { result.add(new FileModel.FileModelBuilder() .id(path.hashCode()) .url(path) .name(getNameFromPath(path)) .isDirectory(true) .countImage(directories.get(path).value) .isOnline(false) .build()); } } // Sorting Collections.sort(result, new Comparator<FileModel>() { @Override public int compare(final FileModel fileModel1, final FileModel fileModel2) { return fileModel2.getCountImage() - fileModel1.getCountImage(); } }); notifyLocalImageFoldersListenerSucceeded(result); mCacheGetLocalImagesFolders.clear(); mCacheGetLocalImagesFolders.addAll(result); mIsGetLocalImageFoldersLaunched = false; } }); } //endregion getLocalImageFolders //region getLocalImage @Override public void getLocalImage(final FileModel fileModelDirectParent) { Preconditions.checkNotNull(fileModelDirectParent); final File fileDirectoryParent = fileModelDirectParent.getFile(); if (!fileModelDirectParent.isDirectory() || fileDirectoryParent == null) { notifyLocalImageListenerFailed(); return; } final List<FileModel> files = new ArrayList<>(); final File[] filesArray = fileDirectoryParent.listFiles( new FilenameFilter() { @Override public boolean accept(File dir, String name) { return (new FileTypeModel(getExtensionFromPath(name))) .equals(FileTypeModelENUM.IMAGE.type); } } ); final List<File> fs = new ArrayList<>(); if (filesArray != null) { fs.addAll(Arrays.asList(filesArray)); } for (final File file : fs) { final FileModel.FileModelBuilder fileModelBuilder = new FileAudioModel.FileModelBuilder() .file(file); files.add(fileModelBuilder.build()); } notifyLocalImageListenerSucceeded(files); } @Override public void clearCache() { mCacheGetAllLocalImage.clear(); mCacheGetLocalImagesFolders.clear(); } @Override public boolean registerAllLocalImageListener( final GetAllLocalImageListener getAllLocalImageListener) { synchronized (mGetAllLocalImageListeners) { //noinspection SimplifiableIfStatement if (getAllLocalImageListener == null || mGetAllLocalImageListeners.contains(getAllLocalImageListener)) { // We don't allow to register null listener // And a listener can only be added once. return false; } return mGetAllLocalImageListeners.add(getAllLocalImageListener); } } @Override public boolean unregisterAllLocalImageListener( final GetAllLocalImageListener getAllLocalImageListener) { synchronized (mGetAllLocalImageListeners) { return mGetAllLocalImageListeners.remove(getAllLocalImageListener); } } //endregion getLocalImage //region Register / Unregister listeners @Override public boolean registerLocalImageFoldersListener( final GetLocalImageFoldersListener getLocalImageFoldersListener) { synchronized (mGetLocalImageFoldersListeners) { //noinspection SimplifiableIfStatement if (getLocalImageFoldersListener == null || mGetLocalImageFoldersListeners.contains(getLocalImageFoldersListener)) { // We don't allow to register null listener // And a listener can only be added once. return false; } return mGetLocalImageFoldersListeners.add(getLocalImageFoldersListener); } } @Override public boolean unregisterLocalImageFoldersListener( final GetLocalImageFoldersListener getLocalImageFoldersListener) { synchronized (mGetLocalImageFoldersListeners) { return mGetLocalImageFoldersListeners.remove(getLocalImageFoldersListener); } } @Override public boolean registerLocalImageListener(final GetLocalImageListener getLocalImageListener) { synchronized (mGetLocalImageListeners) { //noinspection SimplifiableIfStatement if (getLocalImageListener == null || mGetLocalImageListeners.contains(getLocalImageListener)) { // We don't allow to register null listener // And a listener can only be added once. return false; } return mGetLocalImageListeners.add(getLocalImageListener); } } @Override public boolean unregisterLocalImageListener( final GetLocalImageListener getLocalImageListener) { synchronized (mGetLocalImageListeners) { return mGetLocalImageListeners.remove(getLocalImageListener); } } //endregion Register / Unregister listeners //region notify listeners private void notifyAllLocalImageListenerSucceeded(final List<FileModel> fileModels) { synchronized (mGetAllLocalImageListeners) { for (int i = 0, size = mGetAllLocalImageListeners.size(); i < size; i++) { mGetAllLocalImageListeners.get(i).onAllLocalImageSucceeded(fileModels); } } } private void notifyLocalImageFoldersListenerSucceeded(final List<FileModel> fileModels) { synchronized (mGetLocalImageFoldersListeners) { for (int i = 0, size = mGetLocalImageFoldersListeners.size(); i < size; i++) { mGetLocalImageFoldersListeners.get(i).onLocalImageFoldersSucceeded(fileModels); } } } private void notifyLocalImageFoldersListenerFailed() { synchronized (mGetLocalImageFoldersListeners) { for (int i = 0, size = mGetLocalImageFoldersListeners.size(); i < size; i++) { mGetLocalImageFoldersListeners.get(i).onLocalImageFoldersFailed(); } } } private void notifyLocalImageListenerSucceeded(final List<FileModel> fileModels) { synchronized (mGetLocalImageListeners) { for (int i = 0, size = mGetLocalImageListeners.size(); i < size; i++) { mGetLocalImageListeners.get(i).onLocalImageSucceeded(fileModels); } } } private void notifyLocalImageListenerFailed() { synchronized (mGetLocalImageListeners) { for (int i = 0, size = mGetLocalImageListeners.size(); i < size; i++) { mGetLocalImageListeners.get(i).onLocalImageFailed(); } } } //endregion notify listeners /** * Class used to count. * See {@link #getLocalImageFolders()}. * http://stackoverflow.com/questions/81346/most-efficient-way-to-increment-a-map-value-in-java * Used to count with a map. */ protected class MutableInt { int value = 1; // note that we start at 1 since we're counting public void increment() { ++value; } } }