Commit f2ec33be authored by Donald's avatar Donald

* reintroduced excluded folders

* included folders (White list) now are folders that will be scanned periodically
* fixed issue that doesn't open media from other apps (also added work-around for new general uris)
* general  clean and improvements
parent 70538052
......@@ -161,7 +161,7 @@
</activity>
<activity
android:name="org.horaapps.leafpic.activities.WhiteListActivity"
android:name="org.horaapps.leafpic.activities.BlackWhiteListActivity"
android:label="@string/chose_folders"
android:theme="@style/Theme.AppCompat.NoActionBar">
<intent-filter>
......
......@@ -24,8 +24,8 @@ import java.util.ArrayList;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class LookForMediaJob extends JobService {
private final String TAG = "FUCK";
private final String TAG = "LookForMediaJob";
private boolean DEBUG = true;
@Override
public void onCreate() {
......@@ -40,13 +40,13 @@ public class LookForMediaJob extends JobService {
@Override
public void run() {
try {
HandlingAlbums instance = HandlingAlbums.getInstance(getApplicationContext());
ArrayList<String> whiteList = instance.getPaths();
ArrayList<String> whiteList = HandlingAlbums.getInstance(getApplicationContext()).getFolders(HandlingAlbums.INCLUDED);
for (String s : whiteList) {
scanFolder(s);
Log.wtf(TAG, s);
Log.wtf(TAG, "Scanned: " + s);
}
notification(whiteList);
if(DEBUG)
notification(whiteList);
} finally {
jobFinished(jobParameters, false);
}
......@@ -67,6 +67,7 @@ public class LookForMediaJob extends JobService {
new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Looked for media")
.setAutoCancel(true)
.setContentText(builder.toString()); //Required on Gingerbread and below
NotificationManager notificationManager =
......
......@@ -364,7 +364,7 @@ public class PlayerActivity extends ThemedActivity implements ExoPlayer.EventLi
: new ConcatenatingMediaSource(mediaSources);
player.prepare(mediaSource, !isTimelineStatic, !isTimelineStatic);
playerNeedsSource = false;
invalidateOptionsMenu();
supportInvalidateOptionsMenu();
}
}
......@@ -422,7 +422,7 @@ public class PlayerActivity extends ThemedActivity implements ExoPlayer.EventLi
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == ExoPlayer.STATE_ENDED)
showControls();
invalidateOptionsMenu();
supportInvalidateOptionsMenu();
}
@Override
......@@ -457,14 +457,14 @@ public class PlayerActivity extends ThemedActivity implements ExoPlayer.EventLi
if (errorString != null)
showToast(errorString);
playerNeedsSource = true;
invalidateOptionsMenu();
supportInvalidateOptionsMenu();
showControls();
}
// MappingTrackSelector.EventListener implementation
@Override
public void onTrackSelectionsChanged(TrackSelections<? extends MappedTrackInfo> trackSelections) {
invalidateOptionsMenu();
supportInvalidateOptionsMenu();
MappedTrackInfo trackInfo = trackSelections.info;
if (trackInfo.hasOnlyUnplayableTracks(C.TRACK_TYPE_VIDEO))
showToast(R.string.error_unsupported_video);
......
......@@ -156,7 +156,7 @@ public class SettingsActivity extends ThemedActivity {
findViewById(R.id.ll_white_list).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getApplicationContext(), WhiteListActivity.class));
startActivity(new Intent(getApplicationContext(), BlackWhiteListActivity.class));
}
});
......
......@@ -41,6 +41,9 @@ import org.horaapps.leafpic.adapters.MediaPagerAdapter;
import org.horaapps.leafpic.animations.DepthPageTransformer;
import org.horaapps.leafpic.fragments.ImageFragment;
import org.horaapps.leafpic.model.Album;
import org.horaapps.leafpic.model.AlbumSettings;
import org.horaapps.leafpic.model.ContentProviderHelper;
import org.horaapps.leafpic.model.Media;
import org.horaapps.leafpic.model.base.SortingMode;
import org.horaapps.leafpic.model.base.SortingOrder;
import org.horaapps.leafpic.util.AlertDialogsHelper;
......@@ -80,34 +83,37 @@ public class SingleMediaActivity extends SharedMediaActivity {
mViewPager = (HackyViewPager) findViewById(R.id.photos_pager);
SP = PreferenceUtil.getInstance(getApplicationContext());
adapter = new MediaPagerAdapter(getSupportFragmentManager(), getAlbum().getMedia());
initUi();
if (savedInstanceState != null)
mViewPager.setLocked(savedInstanceState.getBoolean(ISLOCKED_ARG, false));
try
{
Album album;
if ((getIntent().getAction().equals(Intent.ACTION_VIEW) || getIntent().getAction().equals(ACTION_REVIEW)) && getIntent().getData() != null) {
String path = ContentHelper.getMediaPath(getApplicationContext(), getIntent().getData());
Album album = null;
if (path != null) {
album = ContentProviderHelper.getAlbumFromMedia(getApplicationContext(), path);
if (album != null) {
album.updatePhotos(getApplicationContext());
album.setCurrentMedia(path);
}
}
File file = null;
if (path != null)
file = new File(path);
if (file != null && file.isFile())
//the image is stored in the storage
album = new Album(getApplicationContext(), file);
else {
//try to choseProvider with Uri
album = new Album(getApplicationContext(), getIntent().getData());
if (album == null) {
Uri mediaUri = getIntent().getData();
album = new Album(mediaUri.toString(), mediaUri.getPath());
album.settings = AlbumSettings.getDefaults();
album.addMedia(new Media(getApplicationContext(), mediaUri));
album.setCount(1);
customUri = true;
}
getAlbums().addAlbum(0, album);
}
} catch (Exception e) { e.printStackTrace(); }
adapter = new MediaPagerAdapter(getSupportFragmentManager(), getAlbum().getMedia());
initUi();
}
private void initUi() {
......@@ -140,20 +146,15 @@ public class SingleMediaActivity extends SharedMediaActivity {
mViewPager.setPageTransformer(true, new DepthPageTransformer());
mViewPager.setOffscreenPageLimit(3);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
@Override
public void onPageSelected(int position) {
@Override public void onPageSelected(int position) {
getAlbum().setCurrentMedia(position);
updatePageTitle(position);
invalidateOptionsMenu();
supportInvalidateOptionsMenu();
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override public void onPageScrollStateChanged(int state) { }
});
Display aa = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
......
......@@ -22,6 +22,7 @@ import org.horaapps.leafpic.LookForMediaJob;
import org.horaapps.leafpic.R;
import org.horaapps.leafpic.activities.base.SharedMediaActivity;
import org.horaapps.leafpic.model.Album;
import org.horaapps.leafpic.model.HandlingAlbums;
import org.horaapps.leafpic.util.ColorPalette;
import org.horaapps.leafpic.util.PermissionUtils;
import org.horaapps.leafpic.util.PreferenceUtil;
......@@ -78,8 +79,10 @@ public class SplashScreen extends SharedMediaActivity {
new PrefetchPhotosData().execute();
}
} else StringUtils.showToast(getApplicationContext(), "Album not found");
} else
} else { // default intent
new PrefetchAlbumsData().execute();
}
if (getIntent().getAction().equals(Intent.ACTION_GET_CONTENT) || getIntent().getAction().equals(Intent.ACTION_PICK))
PICK_INTENT = true;
......@@ -92,24 +95,35 @@ public class SplashScreen extends SharedMediaActivity {
private void startLookingForMedia() {
ComponentName serviceName = new ComponentName(getApplicationContext(), LookForMediaJob.class);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
JobInfo job = new JobInfo.Builder(0, serviceName)
.setPeriodic(1000)
.setRequiresDeviceIdle(true)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
// TODO: 11/29/16 asdasd
//scheduler.cancelAll();
List<JobInfo> allPendingJobs = scheduler.getAllPendingJobs();
Log.wtf("FUCK", allPendingJobs.size() +"");
int result = scheduler.schedule(job);
if (result == JobScheduler.RESULT_SUCCESS) {
Log.wtf("FUCK", "Job scheduled successfully!");
} else
Log.wtf("FUCK", "Job scheduled failed!");
}
new Thread(new Runnable() {
@Override
public void run() {
ComponentName serviceName = new ComponentName(getApplicationContext(), LookForMediaJob.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (getAlbums().getFoldersCount(HandlingAlbums.EXCLUDED) > 0) {
JobInfo job = new JobInfo.Builder(0, serviceName)
.setPeriodic(1000)
.setRequiresDeviceIdle(true)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
if (scheduler.getAllPendingJobs().size() == 0) {
List<JobInfo> allPendingJobs = scheduler.getAllPendingJobs();
Log.wtf("FUCK", allPendingJobs.size() + "");
int result = scheduler.schedule(job);
if (result == JobScheduler.RESULT_SUCCESS) {
Log.wtf("FUCK", "Job scheduled successfully!");
} else
Log.wtf("FUCK", "Job scheduled failed!");
}
}
}
}
}).start();
}
@Override
......
......@@ -11,11 +11,9 @@ import org.horaapps.leafpic.model.base.FilterMode;
import org.horaapps.leafpic.model.base.MediaComparators;
import org.horaapps.leafpic.model.base.SortingMode;
import org.horaapps.leafpic.model.base.SortingOrder;
import org.horaapps.leafpic.model.providers.MediaStoreProvider;
import org.horaapps.leafpic.util.ContentHelper;
import org.horaapps.leafpic.util.PreferenceUtil;
import org.horaapps.leafpic.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.Serializable;
......@@ -39,59 +37,40 @@ public class Album implements Serializable {
private ArrayList<Media> media;
private ArrayList<Media> selectedMedia;
private Album() {
public Album(String path, String name) {
media = new ArrayList<>();
selectedMedia = new ArrayList<>();
this.name = name;
this.path = path;
}
public Album(Context context, String path, long id, String name, int count) {
this();
this.path = path;
this.name = name;
this(path, name);
this.count = count;
this.id = id;
settings = AlbumSettings.getSettings(context, this);
}
public Album(String path, long id, AlbumSettings settings, int count) {
this();
this.path = path;
this.name = StringUtils.getName(path);
this(path, StringUtils.getName(path));
this.id = id;
this.settings = settings;
this.count = count;
}
public Album(Context context, @NotNull File mediaPath) {
this();
File folder = mediaPath.getParentFile();
this.path = folder.getPath();
this.name = folder.getName();
settings = AlbumSettings.getSettings(context, this);
updatePhotos(context);
setCurrentPhoto(mediaPath.getAbsolutePath());
}
/**
* used for open an image from an unknown content storage
*
* @param context context
* @param mediaUri uri of the media to display
*/
public Album(Context context, Uri mediaUri) {
this();
this.path = mediaUri.toString();
this.name = mediaUri.getPath();
media.add(0, new Media(context, mediaUri));
setCurrentMedia(0);
}
public static Album getEmptyAlbum() {
Album album = new Album();
Album album = new Album(null, null);
album.settings = AlbumSettings.getDefaults();
return album;
}
static Album withPath(String path) {
Album emptyAlbum = getEmptyAlbum();
emptyAlbum.path = path;
return emptyAlbum;
}
public ArrayList<Media> getMedia() {
ArrayList<Media> mediaArrayList = new ArrayList<>();
switch (getFilterMode()) {
......@@ -150,19 +129,15 @@ public class Album implements Serializable {
}
private ArrayList<Media> getMedia(Context context) {
PreferenceUtil SP = PreferenceUtil.getInstance(context);
ArrayList<Media> mediaArrayList = new ArrayList<>();
// TODO: 18/08/16
mediaArrayList.addAll(
MediaStoreProvider.getMedia(context, id, SP.getBoolean("set_include_video", true)));
/*if (isFromMediaStore()) {
if (hasId()) {
mediaArrayList.addAll(
MediaStoreProvider.getMedia(
context, id, SP.getBoolean("set_include_video", true)));
ContentProviderHelper.getMedia(
context, id, PreferenceUtil.getBool(context, "set_include_video", true)));
} else {
mediaArrayList.addAll(StorageProvider.getMedia(
getPath(), SP.getBoolean("set_include_video", true)));
}*/
mediaArrayList.addAll(ContentProviderHelper.getMedia(
getPath(), PreferenceUtil.getBool(context, "set_include_video", true)));
}
return mediaArrayList;
}
......@@ -198,7 +173,7 @@ public class Album implements Serializable {
public int getCurrentMediaIndex() { return currentMediaIndex; }
private void setCurrentPhoto(String path) {
public void setCurrentMedia(String path) {
for (int i = 0; i < media.size(); i++)
if (media.get(i).getPath().equals(path)) {
currentMediaIndex = i;
......@@ -228,7 +203,7 @@ public class Album implements Serializable {
return new Media();
}
private boolean isFromMediaStore() {
private boolean hasId() {
return id != -1;
}
......@@ -333,7 +308,7 @@ public class Album implements Serializable {
//region Album Properties Setters
private void setCount(int count) {
public void setCount(int count) {
this.count = count;
}
......@@ -511,7 +486,7 @@ public class Album implements Serializable {
// TODO: 05/08/16 it sucks! look for a better solution!
if (!found_id_album) {
id = MediaStoreProvider.getAlbumId(context, s);
id = ContentProviderHelper.getAlbumId(context, s);
found_id_album = true;
}
Log.d(s, "onScanCompleted: "+s);
......@@ -526,7 +501,7 @@ public class Album implements Serializable {
path = dir.getAbsolutePath();
name = newName;
// NOTE: the following line doesn't work
//id = MediaStoreProvider.getAlbumId(context, media.getValue(0).getPath());
//id = ContentProviderHelper.getAlbumId(context, media.getValue(0).getPath());
}
return success;
......
......@@ -20,11 +20,10 @@ public class AlbumSettings implements Serializable {
FilterMode filterMode = FilterMode.ALL;
static AlbumSettings getSettings(Context context, Album album) {
AlbumSettings settings = HandlingAlbums.getInstance(context).getSettings(album.getPath());
return settings != null ? settings : getDefaults();
return HandlingAlbums.getInstance(context).getSettings(album.getPath());
}
static AlbumSettings getDefaults() {
public static AlbumSettings getDefaults() {
return new AlbumSettings(null, SortingMode.DATE.getValue(), SortingOrder.DESCENDING.getValue(), 0);
}
......
package org.horaapps.leafpic.model;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import org.horaapps.leafpic.model.base.FoldersFileFilter;
import org.horaapps.leafpic.model.base.ImageFileFilter;
import org.horaapps.leafpic.util.ContentHelper;
import org.horaapps.leafpic.util.PreferenceUtil;
import org.horaapps.leafpic.util.StringUtils;
import org.jetbrains.annotations.TestOnly;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
/**
* Created by dnld on 24/07/16.
*/
public class ContentProviderHelper {
@Nullable private static Media getLastMedia(Context context, long albumId) {
ArrayList<Media> list = getMedia(context, albumId, 1, true);
return list.size() > 0 ? list.get(0) : null;
}
static ArrayList<Media> getMedia(Context context, long albumId, boolean includeVideo) {
return getMedia(context, albumId, -1, includeVideo);
}
private static ArrayList<Media> getMedia(Context context, long albumId, int n, boolean includeVideo) {
String limit = n == -1 ? "" : "LIMIT " + n;
ArrayList<Media> list = new ArrayList<Media>();
String[] projection = new String[]{
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.MIME_TYPE,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.ORIENTATION
};
Uri images = MediaStore.Files.getContentUri("external");
String selection, selectionArgs[];
if(includeVideo) {
selection = String.format("(%s=? or %s=?) and %s=?",
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.PARENT);
selectionArgs = new String[] {
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE),
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO),
String.valueOf(albumId)
};
} else {
selection = String.format("%s=? and %s=?",
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.PARENT);
selectionArgs = new String[] { String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE), String.valueOf(albumId) };
}
Cursor cur = context.getContentResolver().query(
images, projection, selection, selectionArgs,
MediaStore.Images.Media.DATE_TAKEN + " DESC " + limit);
if (cur != null) {
if (cur.moveToFirst()) do list.add(new Media(cur)); while (cur.moveToNext());
cur.close();
}
return list;
}
public static long getAlbumId(Context context, String mediaPath) {
long id = -1;
Cursor cur = context.getContentResolver().query(MediaStore.Files.getContentUri("external"),
new String[]{ MediaStore.Files.FileColumns.PARENT },
MediaStore.Files.FileColumns.DATA+"=?", new String[]{ mediaPath }, null);
if(cur != null && cur.moveToNext()){
id = cur.getLong(0);
cur.close();
}
return id;
}
@TestOnly
public static ArrayList<Media> getAllMedia(Context context) {
ArrayList<Media> list = new ArrayList<Media>();
// TODO: 11/21/16 implement
return list;
}
@TestOnly
private String getThumbnailPath(Context context, long id) {
Cursor cursor = MediaStore.Images.Thumbnails.queryMiniThumbnail(
context.getContentResolver(), id, MediaStore.Images.Thumbnails.MINI_KIND,
new String[]{ MediaStore.Images.Thumbnails.DATA });
if(cursor.moveToFirst())
return cursor.getString(cursor.getColumnIndex(MediaStore.Images.Thumbnails.DATA));
return null;
}
static ArrayList<Media> getMedia(String path, boolean includeVideo) {
ArrayList<Media> list = new ArrayList<Media>();
File[] images = new File(path).listFiles(new ImageFileFilter(includeVideo));
for (File image : images)
list.add(new Media(image));
return list;
}
static ArrayList<Album> getAlbums(Context context, HashSet<String> excludedAlbums, boolean hidden) {
return hidden ? getHiddenAlbums(context, excludedAlbums) : getAlbums(context, excludedAlbums);
}
private static ArrayList<Album> getHiddenAlbums(Context context, HashSet<String> excludedAlbums) {
ArrayList<Album> list = new ArrayList<Album>();
for (File storage : ContentHelper.getStorageRoots(context))
fetchRecursivelyHiddenFolder(context, storage, list, excludedAlbums, PreferenceUtil.getBool(context, "set_include_video", true));
return list;
}
private static void fetchRecursivelyHiddenFolder(Context context, File dir, ArrayList<Album> albumArrayList, HashSet<String> excludedAlbums, boolean includeVideo) {
if (!isExcluded(dir.getPath(), excludedAlbums)) {
File[] folders = dir.listFiles(new FoldersFileFilter());
if (folders != null) {
for (File temp : folders) {
File nomedia = new File(temp, ".nomedia");
if (!isExcluded(temp.getPath(), excludedAlbums) && (nomedia.exists() || temp.isHidden()))
checkAndAddFolder(context, temp, albumArrayList, includeVideo);
fetchRecursivelyHiddenFolder(context, temp, albumArrayList, excludedAlbums, includeVideo);
}
}
}
}
private static void checkAndAddFolder(Context context, File dir, ArrayList<Album> albumArrayList, boolean includeVideo) {
File[] files = dir.listFiles(new ImageFileFilter(includeVideo));
if (files != null && files.length > 0) {
//valid folder
Album asd = new Album(context, dir.getAbsolutePath(), -1, dir.getName(), files.length);
if (!asd.hasCustomCover()) {
long lastMod = Long.MIN_VALUE;
File choice = null;
for (File file : files) {
if (file.lastModified() > lastMod) {
choice = file;
lastMod = file.lastModified();
}
}
if (choice != null)
asd.addMedia(new Media(choice.getAbsolutePath(), choice.lastModified()));
}
albumArrayList.add(asd);
}
}
private static boolean isExcluded(String path, HashSet<String> excludedAlbums) {
for(String s : excludedAlbums) if (path.startsWith(s)) return true;
return false;
}
public static Album getAlbumFromMedia(Context context, String mediaPath) {
File parentFolder = new File(mediaPath).getParentFile();
if (parentFolder == null || !parentFolder.isDirectory())
return null;
return new Album(context, parentFolder.getPath(), getAlbumId(context, mediaPath), parentFolder.getName(), 0);
}
private static ArrayList<Album> getAlbums(Context context, HashSet<String> excludedAlbums) {
ArrayList<Album> list = new ArrayList<>();
String[] projection = new String[]{
MediaStore.Files.FileColumns.PARENT,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
"count(*)",
MediaStore.Images.Media.DATA,
};
String selection, selectionArgs[];
if (PreferenceUtil.getBool(context, "set_include_video", true)) {
selection = String.format("%s=? or %s=?) group by ( %s ",
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.PARENT);
selectionArgs = new String[]{
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE),
String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO),
};
} else {
selection = String.format("%s=?) group by ( %s ",
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.PARENT);
selectionArgs = new String[] { String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE) };
}
Cursor cur = context.getContentResolver().query(
MediaStore.Files.getContentUri("external"), projection, selection, selectionArgs, null);
if (cur != null) {
if (cur.moveToFirst()) {
do {
String path = StringUtils.getBucketPathByImagePath(cur.getString(3));
boolean excluded = isExcluded(path, excludedAlbums);
if (!excluded) {
Album album = new Album(context, path, cur.getLong(0), cur.getString(1), cur.getInt(2));
if(!album.hasCustomCover())
album.addMedia(getLastMedia(context, cur.getLong(0)));
list.add(album);
}
}
while (cur.moveToNext());
}
cur.close();
}
return list;
}
}
......@@ -25,7 +25,6 @@ import org.horaapps.leafpic.util.StringUtils;
import org.jetbrains.annotations.TestOnly;