commit
4ecd5986dd
13 changed files with 574 additions and 28 deletions
|
|
@ -2,7 +2,6 @@ package com.kabouzeid.gramophone;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.anjlab.android.iab.v3.BillingProcessor;
|
import com.anjlab.android.iab.v3.BillingProcessor;
|
||||||
import com.anjlab.android.iab.v3.TransactionDetails;
|
import com.anjlab.android.iab.v3.TransactionDetails;
|
||||||
|
|
@ -21,7 +20,7 @@ public class App extends Application {
|
||||||
public static final String GOOGLE_PLAY_LICENSE_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjMeADN5Ffnt/ml5SYxNPCn8kGcOYGpHEfNSCts99vVxqmCn6C01E94c17j7rUK2aeHur5uxphZylzopPlQ8P8l1fqty0GPUNRSo18FCJzfGH8HZAwZYOcnRFPaXdaq3InyFJhBiODh2oeAcVK/idH6QraQ4r9HIlzigAg6lgwzxl2wJKDh7X/GMdDntCyzDh8xDQ0wIawFgvgojHwqh2Ci8Gnq6EYRwPA9yHiIIksT8Q30QyM5ewl5QcnWepsls7enNqeHarhpmSibRUDgCsxHoOpny7SyuvZvUI3wuLckDR0ds9hrt614scHHqDOBp/qWCZiAgOPVAEQcURbV09qQIDAQAB";
|
public static final String GOOGLE_PLAY_LICENSE_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjMeADN5Ffnt/ml5SYxNPCn8kGcOYGpHEfNSCts99vVxqmCn6C01E94c17j7rUK2aeHur5uxphZylzopPlQ8P8l1fqty0GPUNRSo18FCJzfGH8HZAwZYOcnRFPaXdaq3InyFJhBiODh2oeAcVK/idH6QraQ4r9HIlzigAg6lgwzxl2wJKDh7X/GMdDntCyzDh8xDQ0wIawFgvgojHwqh2Ci8Gnq6EYRwPA9yHiIIksT8Q30QyM5ewl5QcnWepsls7enNqeHarhpmSibRUDgCsxHoOpny7SyuvZvUI3wuLckDR0ds9hrt614scHHqDOBp/qWCZiAgOPVAEQcURbV09qQIDAQAB";
|
||||||
public static final String PRO_VERSION_PRODUCT_ID = "pro_version";
|
public static final String PRO_VERSION_PRODUCT_ID = "pro_version";
|
||||||
|
|
||||||
public static App app;
|
private static App app;
|
||||||
|
|
||||||
private BillingProcessor billingProcessor;
|
private BillingProcessor billingProcessor;
|
||||||
|
|
||||||
|
|
@ -49,7 +48,7 @@ public class App extends Application {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPurchaseHistoryRestored() {
|
public void onPurchaseHistoryRestored() {
|
||||||
Toast.makeText(App.this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show();
|
// Toast.makeText(App.this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
package com.kabouzeid.gramophone.dialogs;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.app.ActivityCompat;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.afollestad.materialdialogs.DialogAction;
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog;
|
||||||
|
import com.kabouzeid.gramophone.R;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aidan Follestad (afollestad), modified by Karim Abou Zeid
|
||||||
|
*/
|
||||||
|
public class BlacklistFolderChooserDialog extends DialogFragment implements MaterialDialog.ListCallback {
|
||||||
|
|
||||||
|
private File parentFolder;
|
||||||
|
private File[] parentContents;
|
||||||
|
private boolean canGoUp = false;
|
||||||
|
|
||||||
|
private FolderCallback callback;
|
||||||
|
|
||||||
|
String initialPath = Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||||
|
|
||||||
|
private String[] getContentsArray() {
|
||||||
|
if (parentContents == null) {
|
||||||
|
if (canGoUp) {
|
||||||
|
return new String[]{".."};
|
||||||
|
}
|
||||||
|
return new String[]{};
|
||||||
|
}
|
||||||
|
String[] results = new String[parentContents.length + (canGoUp ? 1 : 0)];
|
||||||
|
if (canGoUp) {
|
||||||
|
results[0] = "..";
|
||||||
|
}
|
||||||
|
for (int i = 0; i < parentContents.length; i++) {
|
||||||
|
results[canGoUp ? i + 1 : i] = parentContents[i].getName();
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File[] listFiles() {
|
||||||
|
File[] contents = parentFolder.listFiles();
|
||||||
|
List<File> results = new ArrayList<>();
|
||||||
|
if (contents != null) {
|
||||||
|
for (File fi : contents) {
|
||||||
|
if (fi.isDirectory()) {
|
||||||
|
results.add(fi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(results, new FolderSorter());
|
||||||
|
return results.toArray(new File[results.size()]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlacklistFolderChooserDialog create() {
|
||||||
|
return new BlacklistFolderChooserDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
|
&& ActivityCompat.checkSelfPermission(
|
||||||
|
getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
return new MaterialDialog.Builder(getActivity())
|
||||||
|
.title(R.string.md_error_label)
|
||||||
|
.content(R.string.md_storage_perm_error)
|
||||||
|
.positiveText(android.R.string.ok)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
savedInstanceState = new Bundle();
|
||||||
|
}
|
||||||
|
if (!savedInstanceState.containsKey("current_path")) {
|
||||||
|
savedInstanceState.putString("current_path", initialPath);
|
||||||
|
}
|
||||||
|
parentFolder = new File(savedInstanceState.getString("current_path", File.pathSeparator));
|
||||||
|
checkIfCanGoUp();
|
||||||
|
parentContents = listFiles();
|
||||||
|
MaterialDialog.Builder builder =
|
||||||
|
new MaterialDialog.Builder(getActivity())
|
||||||
|
.title(parentFolder.getAbsolutePath())
|
||||||
|
.items((CharSequence[]) getContentsArray())
|
||||||
|
.itemsCallback(this)
|
||||||
|
.autoDismiss(false)
|
||||||
|
.onPositive(new MaterialDialog.SingleButtonCallback() {
|
||||||
|
@Override
|
||||||
|
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
|
||||||
|
dismiss();
|
||||||
|
callback.onFolderSelection(BlacklistFolderChooserDialog.this, parentFolder);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onNegative(new MaterialDialog.SingleButtonCallback() {
|
||||||
|
@Override
|
||||||
|
public void onClick(@NonNull MaterialDialog materialDialog, @NonNull DialogAction dialogAction) {
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.positiveText(R.string.add_action)
|
||||||
|
.negativeText(android.R.string.cancel);
|
||||||
|
if (File.pathSeparator.equals(initialPath)) {
|
||||||
|
canGoUp = false;
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSelection(MaterialDialog materialDialog, View view, int i, CharSequence s) {
|
||||||
|
if (canGoUp && i == 0) {
|
||||||
|
parentFolder = parentFolder.getParentFile();
|
||||||
|
if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
|
||||||
|
parentFolder = parentFolder.getParentFile();
|
||||||
|
}
|
||||||
|
canGoUp = parentFolder.getParent() != null;
|
||||||
|
} else {
|
||||||
|
parentFolder = parentContents[canGoUp ? i - 1 : i];
|
||||||
|
canGoUp = true;
|
||||||
|
if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
|
||||||
|
parentFolder = Environment.getExternalStorageDirectory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkIfCanGoUp() {
|
||||||
|
try {
|
||||||
|
canGoUp = parentFolder.getPath().split(File.pathSeparator).length > 1;
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
canGoUp = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reload() {
|
||||||
|
parentContents = listFiles();
|
||||||
|
MaterialDialog dialog = (MaterialDialog) getDialog();
|
||||||
|
dialog.setTitle(parentFolder.getAbsolutePath());
|
||||||
|
dialog.setItems((CharSequence[]) getContentsArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putString("current_path", parentFolder.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallback(FolderCallback callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface FolderCallback {
|
||||||
|
void onFolderSelection(@NonNull BlacklistFolderChooserDialog dialog, @NonNull File folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FolderSorter implements Comparator<File> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(File lhs, File rhs) {
|
||||||
|
return lhs.getName().compareTo(rhs.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,10 +9,13 @@ import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import com.kabouzeid.gramophone.model.Song;
|
import com.kabouzeid.gramophone.model.Song;
|
||||||
|
import com.kabouzeid.gramophone.provider.BlacklistStore;
|
||||||
import com.kabouzeid.gramophone.util.PreferenceUtil;
|
import com.kabouzeid.gramophone.util.PreferenceUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import hugo.weaving.DebugLog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karim Abou Zeid (kabouzeid)
|
* @author Karim Abou Zeid (kabouzeid)
|
||||||
*/
|
*/
|
||||||
|
|
@ -87,11 +90,20 @@ public class SongLoader {
|
||||||
return makeSongCursor(context, selection, selectionValues, PreferenceUtil.getInstance(context).getSongSortOrder());
|
return makeSongCursor(context, selection, selectionValues, PreferenceUtil.getInstance(context).getSongSortOrder());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DebugLog
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Cursor makeSongCursor(@NonNull final Context context, @Nullable final String selection, final String[] selectionValues, final String sortOrder) {
|
public static Cursor makeSongCursor(@NonNull final Context context, @Nullable String selection, String[] selectionValues, final String sortOrder) {
|
||||||
String baseSelection = BASE_SELECTION;
|
|
||||||
if (selection != null && !selection.trim().equals("")) {
|
if (selection != null && !selection.trim().equals("")) {
|
||||||
baseSelection += " AND " + selection;
|
selection = BASE_SELECTION + " AND " + selection;
|
||||||
|
} else {
|
||||||
|
selection = BASE_SELECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blacklist
|
||||||
|
ArrayList<String> paths = BlacklistStore.getInstance(context).getPaths();
|
||||||
|
if (!paths.isEmpty()) {
|
||||||
|
selection = generateBlacklistSelection(selection, paths.size());
|
||||||
|
selectionValues = addBlacklistSelectionValues(selectionValues, paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -109,9 +121,30 @@ public class SongLoader {
|
||||||
AudioColumns.ARTIST_ID,// 9
|
AudioColumns.ARTIST_ID,// 9
|
||||||
AudioColumns.ARTIST,// 10
|
AudioColumns.ARTIST,// 10
|
||||||
|
|
||||||
}, baseSelection, selectionValues, sortOrder);
|
}, selection, selectionValues, sortOrder);
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DebugLog
|
||||||
|
private static String generateBlacklistSelection(String selection, int pathCount) {
|
||||||
|
String newSelection = selection != null && !selection.trim().equals("") ? selection + " AND " : "";
|
||||||
|
newSelection += AudioColumns.DATA + " NOT LIKE ?";
|
||||||
|
for (int i = 0; i < pathCount - 1; i++) {
|
||||||
|
newSelection += " AND " + AudioColumns.DATA + " NOT LIKE ?";
|
||||||
|
}
|
||||||
|
return newSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DebugLog
|
||||||
|
private static String[] addBlacklistSelectionValues(String[] selectionValues, ArrayList<String> paths) {
|
||||||
|
if (selectionValues == null) selectionValues = new String[0];
|
||||||
|
String[] newSelectionValues = new String[selectionValues.length + paths.size()];
|
||||||
|
System.arraycopy(selectionValues, 0, newSelectionValues, 0, selectionValues.length);
|
||||||
|
for (int i = selectionValues.length; i < newSelectionValues.length; i++) {
|
||||||
|
newSelectionValues[i] = paths.get(i - selectionValues.length) + "%";
|
||||||
|
}
|
||||||
|
return newSelectionValues;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.kabouzeid.gramophone.preferences;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEDialogPreference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karim Abou Zeid (kabouzeid)
|
||||||
|
*/
|
||||||
|
public class BlacklistPreference extends ATEDialogPreference {
|
||||||
|
public BlacklistPreference(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlacklistPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlacklistPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlacklistPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
package com.kabouzeid.gramophone.preferences;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.afollestad.materialdialogs.DialogAction;
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog;
|
||||||
|
import com.kabouzeid.gramophone.R;
|
||||||
|
import com.kabouzeid.gramophone.dialogs.BlacklistFolderChooserDialog;
|
||||||
|
import com.kabouzeid.gramophone.provider.BlacklistStore;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karim Abou Zeid (kabouzeid)
|
||||||
|
*/
|
||||||
|
public class BlacklistPreferenceDialog extends DialogFragment implements BlacklistFolderChooserDialog.FolderCallback {
|
||||||
|
public static final String TAG = BlacklistPreferenceDialog.class.getSimpleName();
|
||||||
|
|
||||||
|
private ArrayList<String> paths;
|
||||||
|
|
||||||
|
public static BlacklistPreferenceDialog newInstance() {
|
||||||
|
return new BlacklistPreferenceDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
BlacklistFolderChooserDialog blacklistFolderChooserDialog = (BlacklistFolderChooserDialog) getChildFragmentManager().findFragmentByTag("FOLDER_CHOOSER");
|
||||||
|
if (blacklistFolderChooserDialog != null) {
|
||||||
|
blacklistFolderChooserDialog.setCallback(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshBlacklistData();
|
||||||
|
return new MaterialDialog.Builder(getContext())
|
||||||
|
.title(R.string.blacklist)
|
||||||
|
.positiveText(android.R.string.ok)
|
||||||
|
.neutralText(R.string.clear_action)
|
||||||
|
.negativeText(R.string.add_action)
|
||||||
|
.items(paths)
|
||||||
|
.autoDismiss(false)
|
||||||
|
.itemsCallback(new MaterialDialog.ListCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSelection(MaterialDialog materialDialog, View view, int i, final CharSequence charSequence) {
|
||||||
|
new MaterialDialog.Builder(getContext())
|
||||||
|
.title(R.string.remove_from_blacklist)
|
||||||
|
.content(Html.fromHtml(getString(R.string.do_you_want_to_remove_from_the_blacklist, charSequence)))
|
||||||
|
.positiveText(R.string.remove_action)
|
||||||
|
.negativeText(android.R.string.cancel)
|
||||||
|
.onPositive(new MaterialDialog.SingleButtonCallback() {
|
||||||
|
@Override
|
||||||
|
public void onClick(@NonNull MaterialDialog materialDialog, @NonNull DialogAction dialogAction) {
|
||||||
|
BlacklistStore.getInstance(getContext()).removePath(new File(charSequence.toString()));
|
||||||
|
refreshBlacklistData();
|
||||||
|
}
|
||||||
|
}).show();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// clear
|
||||||
|
.onNeutral(new MaterialDialog.SingleButtonCallback() {
|
||||||
|
@Override
|
||||||
|
public void onClick(@NonNull MaterialDialog materialDialog, @NonNull DialogAction dialogAction) {
|
||||||
|
new MaterialDialog.Builder(getContext())
|
||||||
|
.title(R.string.clear_blacklist)
|
||||||
|
.content(R.string.do_you_want_to_clear_the_blacklist)
|
||||||
|
.positiveText(R.string.clear_action)
|
||||||
|
.negativeText(android.R.string.cancel)
|
||||||
|
.onPositive(new MaterialDialog.SingleButtonCallback() {
|
||||||
|
@Override
|
||||||
|
public void onClick(@NonNull MaterialDialog materialDialog, @NonNull DialogAction dialogAction) {
|
||||||
|
BlacklistStore.getInstance(getContext()).clear();
|
||||||
|
refreshBlacklistData();
|
||||||
|
}
|
||||||
|
}).show();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// add
|
||||||
|
.onNegative(new MaterialDialog.SingleButtonCallback() {
|
||||||
|
@Override
|
||||||
|
public void onClick(@NonNull MaterialDialog materialDialog, @NonNull DialogAction dialogAction) {
|
||||||
|
BlacklistFolderChooserDialog dialog = BlacklistFolderChooserDialog.create();
|
||||||
|
dialog.setCallback(BlacklistPreferenceDialog.this);
|
||||||
|
dialog.show(getChildFragmentManager(), "FOLDER_CHOOSER");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onPositive(new MaterialDialog.SingleButtonCallback() {
|
||||||
|
@Override
|
||||||
|
public void onClick(@NonNull MaterialDialog materialDialog, @NonNull DialogAction dialogAction) {
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshBlacklistData() {
|
||||||
|
paths = BlacklistStore.getInstance(getContext()).getPaths();
|
||||||
|
|
||||||
|
MaterialDialog dialog = (MaterialDialog) getDialog();
|
||||||
|
if (dialog != null) {
|
||||||
|
String[] pathArray = new String[paths.size()];
|
||||||
|
pathArray = paths.toArray(pathArray);
|
||||||
|
dialog.setItems((CharSequence[]) pathArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFolderSelection(@NonNull BlacklistFolderChooserDialog folderChooserDialog, @NonNull File file) {
|
||||||
|
BlacklistStore.getInstance(getContext()).addPath(file);
|
||||||
|
refreshBlacklistData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
package com.kabouzeid.gramophone.provider;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.kabouzeid.gramophone.service.MusicService;
|
||||||
|
import com.kabouzeid.gramophone.util.FileUtil;
|
||||||
|
import com.kabouzeid.gramophone.util.PreferenceUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import hugo.weaving.DebugLog;
|
||||||
|
|
||||||
|
public class BlacklistStore extends SQLiteOpenHelper {
|
||||||
|
private static BlacklistStore sInstance = null;
|
||||||
|
public static final String DATABASE_NAME = "blacklist.db";
|
||||||
|
private static final int VERSION = 1;
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
public BlacklistStore(final Context context) {
|
||||||
|
super(context, DATABASE_NAME, null, VERSION);
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@NonNull final SQLiteDatabase db) {
|
||||||
|
db.execSQL("CREATE TABLE IF NOT EXISTS " + BlacklistStoreColumns.NAME + " ("
|
||||||
|
+ BlacklistStoreColumns.PATH + " STRING NOT NULL);");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||||
|
db.execSQL("DROP TABLE IF EXISTS " + BlacklistStoreColumns.NAME);
|
||||||
|
onCreate(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDowngrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
db.execSQL("DROP TABLE IF EXISTS " + BlacklistStoreColumns.NAME);
|
||||||
|
onCreate(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static synchronized BlacklistStore getInstance(@NonNull final Context context) {
|
||||||
|
if (sInstance == null) {
|
||||||
|
sInstance = new BlacklistStore(context.getApplicationContext());
|
||||||
|
if (!PreferenceUtil.getInstance(context).initializedBlacklist()) {
|
||||||
|
// blacklisted by default
|
||||||
|
sInstance.addPathImpl(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS));
|
||||||
|
sInstance.addPathImpl(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_NOTIFICATIONS));
|
||||||
|
sInstance.addPathImpl(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES));
|
||||||
|
|
||||||
|
PreferenceUtil.getInstance(context).setInitializedBlacklist();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPath(File file) {
|
||||||
|
addPathImpl(file);
|
||||||
|
notifyMediaStoreChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPathImpl(File file) {
|
||||||
|
if (file == null || contains(file)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String path = FileUtil.safeGetCanonicalPath(file);
|
||||||
|
|
||||||
|
final SQLiteDatabase database = getWritableDatabase();
|
||||||
|
database.beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// add the entry
|
||||||
|
final ContentValues values = new ContentValues(1);
|
||||||
|
values.put(BlacklistStoreColumns.PATH, path);
|
||||||
|
database.insert(BlacklistStoreColumns.NAME, null, values);
|
||||||
|
|
||||||
|
database.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
database.endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(File file) {
|
||||||
|
if (file == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String path = FileUtil.safeGetCanonicalPath(file);
|
||||||
|
|
||||||
|
final SQLiteDatabase database = getReadableDatabase();
|
||||||
|
Cursor cursor = database.query(BlacklistStoreColumns.NAME,
|
||||||
|
new String[]{BlacklistStoreColumns.PATH},
|
||||||
|
BlacklistStoreColumns.PATH + "=?",
|
||||||
|
new String[]{path},
|
||||||
|
null, null, null, null);
|
||||||
|
|
||||||
|
boolean containsPath = cursor != null && cursor.moveToFirst();
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
return containsPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePath(File file) {
|
||||||
|
final SQLiteDatabase database = getWritableDatabase();
|
||||||
|
String path = FileUtil.safeGetCanonicalPath(file);
|
||||||
|
|
||||||
|
database.delete(BlacklistStoreColumns.NAME,
|
||||||
|
BlacklistStoreColumns.PATH + "=?",
|
||||||
|
new String[]{path});
|
||||||
|
|
||||||
|
notifyMediaStoreChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
final SQLiteDatabase database = getWritableDatabase();
|
||||||
|
database.delete(BlacklistStoreColumns.NAME, null, null);
|
||||||
|
|
||||||
|
notifyMediaStoreChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyMediaStoreChanged() {
|
||||||
|
context.sendBroadcast(new Intent(MusicService.MEDIA_STORE_CHANGED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@DebugLog
|
||||||
|
public ArrayList<String> getPaths() {
|
||||||
|
Cursor cursor = getReadableDatabase().query(BlacklistStoreColumns.NAME,
|
||||||
|
new String[]{BlacklistStoreColumns.PATH},
|
||||||
|
null, null, null, null, null);
|
||||||
|
|
||||||
|
ArrayList<String> paths = new ArrayList<>();
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
do {
|
||||||
|
paths.add(cursor.getString(0));
|
||||||
|
} while (cursor.moveToNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null)
|
||||||
|
cursor.close();
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface BlacklistStoreColumns {
|
||||||
|
String NAME = "blacklist";
|
||||||
|
|
||||||
|
String PATH = "path";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -146,11 +146,10 @@ public class MainActivity extends AbsSlidingMusicPanelActivity {
|
||||||
if (!hasPermissions()) {
|
if (!hasPermissions()) {
|
||||||
requestPermissions();
|
requestPermissions();
|
||||||
}
|
}
|
||||||
|
checkSetUpPro(); // good chance that pro version check was delayed on first start
|
||||||
} else if (requestCode == PURCHASE_REQUEST) {
|
} else if (requestCode == PURCHASE_REQUEST) {
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
if (App.isProVersion()) {
|
checkSetUpPro();
|
||||||
setUpPro();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -174,9 +173,7 @@ public class MainActivity extends AbsSlidingMusicPanelActivity {
|
||||||
NavigationViewUtil.setItemIconColors(navigationView, ATHUtil.resolveColor(this, R.attr.iconColor, ThemeStore.textColorSecondary(this)), accentColor);
|
NavigationViewUtil.setItemIconColors(navigationView, ATHUtil.resolveColor(this, R.attr.iconColor, ThemeStore.textColorSecondary(this)), accentColor);
|
||||||
NavigationViewUtil.setItemTextColors(navigationView, ThemeStore.textColorPrimary(this), accentColor);
|
NavigationViewUtil.setItemTextColors(navigationView, ThemeStore.textColorPrimary(this), accentColor);
|
||||||
|
|
||||||
if (App.isProVersion()) {
|
checkSetUpPro();
|
||||||
setUpPro();
|
|
||||||
}
|
|
||||||
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
|
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
|
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
|
||||||
|
|
@ -228,6 +225,12 @@ public class MainActivity extends AbsSlidingMusicPanelActivity {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkSetUpPro() {
|
||||||
|
if (App.isProVersion()) {
|
||||||
|
setUpPro();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setUpPro() {
|
private void setUpPro() {
|
||||||
navigationView.getMenu().removeGroup(R.id.navigation_drawer_menu_category_buy_pro);
|
navigationView.getMenu().removeGroup(R.id.navigation_drawer_menu_category_buy_pro);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ import com.kabouzeid.gramophone.App;
|
||||||
import com.kabouzeid.gramophone.R;
|
import com.kabouzeid.gramophone.R;
|
||||||
import com.kabouzeid.gramophone.appshortcuts.DynamicShortcutManager;
|
import com.kabouzeid.gramophone.appshortcuts.DynamicShortcutManager;
|
||||||
import com.kabouzeid.gramophone.misc.NonProAllowedColors;
|
import com.kabouzeid.gramophone.misc.NonProAllowedColors;
|
||||||
|
import com.kabouzeid.gramophone.preferences.BlacklistPreference;
|
||||||
|
import com.kabouzeid.gramophone.preferences.BlacklistPreferenceDialog;
|
||||||
import com.kabouzeid.gramophone.preferences.NowPlayingScreenPreference;
|
import com.kabouzeid.gramophone.preferences.NowPlayingScreenPreference;
|
||||||
import com.kabouzeid.gramophone.preferences.NowPlayingScreenPreferenceDialog;
|
import com.kabouzeid.gramophone.preferences.NowPlayingScreenPreferenceDialog;
|
||||||
import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity;
|
import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity;
|
||||||
|
|
@ -155,6 +157,7 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
|
||||||
addPreferencesFromResource(R.xml.pref_lockscreen);
|
addPreferencesFromResource(R.xml.pref_lockscreen);
|
||||||
addPreferencesFromResource(R.xml.pref_audio);
|
addPreferencesFromResource(R.xml.pref_audio);
|
||||||
addPreferencesFromResource(R.xml.pref_playlists);
|
addPreferencesFromResource(R.xml.pref_playlists);
|
||||||
|
addPreferencesFromResource(R.xml.pref_blacklist);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
@ -162,6 +165,8 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
|
||||||
public DialogFragment onCreatePreferenceDialog(Preference preference) {
|
public DialogFragment onCreatePreferenceDialog(Preference preference) {
|
||||||
if (preference instanceof NowPlayingScreenPreference) {
|
if (preference instanceof NowPlayingScreenPreference) {
|
||||||
return NowPlayingScreenPreferenceDialog.newInstance();
|
return NowPlayingScreenPreferenceDialog.newInstance();
|
||||||
|
} else if (preference instanceof BlacklistPreference) {
|
||||||
|
return BlacklistPreferenceDialog.newInstance();
|
||||||
}
|
}
|
||||||
return super.onCreatePreferenceDialog(preference);
|
return super.onCreatePreferenceDialog(preference);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -658,12 +658,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements MainActi
|
||||||
paths = new String[files.size()];
|
paths = new String[files.size()];
|
||||||
for (int i = 0; i < files.size(); i++) {
|
for (int i = 0; i < files.size(); i++) {
|
||||||
File f = files.get(i);
|
File f = files.get(i);
|
||||||
try {
|
paths[i] = FileUtil.safeGetCanonicalPath(f);
|
||||||
paths[i] = f.getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
paths[i] = f.getPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCancelled() || checkCallbackReference() == null) return paths;
|
if (isCancelled() || checkCallbackReference() == null) return paths;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,12 +68,7 @@ public final class FileUtil {
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
String[] paths = new String[files.size()];
|
String[] paths = new String[files.size()];
|
||||||
for (int i = 0; i < files.size(); i++) {
|
for (int i = 0; i < files.size(); i++) {
|
||||||
try {
|
paths[i] = safeGetCanonicalPath(files.get(i));
|
||||||
paths[i] = files.get(i).getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
paths[i] = files.get(i).getPath();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
@ -190,4 +185,13 @@ public final class FileUtil {
|
||||||
fin.close();
|
fin.close();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String safeGetCanonicalPath(File file) {
|
||||||
|
try {
|
||||||
|
return file.getCanonicalPath();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,8 @@ public final class PreferenceUtil {
|
||||||
|
|
||||||
public static final String SYNCHRONIZED_LYRICS_SHOW = "synchronized_lyrics_show";
|
public static final String SYNCHRONIZED_LYRICS_SHOW = "synchronized_lyrics_show";
|
||||||
|
|
||||||
|
public static final String INITIALIZED_BLACKLIST = "initialized_blacklist";
|
||||||
|
|
||||||
private static PreferenceUtil sInstance;
|
private static PreferenceUtil sInstance;
|
||||||
|
|
||||||
private final SharedPreferences mPreferences;
|
private final SharedPreferences mPreferences;
|
||||||
|
|
@ -405,11 +407,21 @@ public final class PreferenceUtil {
|
||||||
|
|
||||||
public void setStartDirectory(File file) {
|
public void setStartDirectory(File file) {
|
||||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||||
editor.putString(START_DIRECTORY, file.getPath());
|
editor.putString(START_DIRECTORY, FileUtil.safeGetCanonicalPath(file));
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean synchronizedLyricsShow() {
|
public final boolean synchronizedLyricsShow() {
|
||||||
return mPreferences.getBoolean(SYNCHRONIZED_LYRICS_SHOW, true);
|
return mPreferences.getBoolean(SYNCHRONIZED_LYRICS_SHOW, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setInitializedBlacklist() {
|
||||||
|
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||||
|
editor.putBoolean(INITIALIZED_BLACKLIST, true);
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean initializedBlacklist() {
|
||||||
|
return mPreferences.getBoolean(INITIALIZED_BLACKLIST, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -286,4 +286,10 @@
|
||||||
<string name="restore">Restore</string>
|
<string name="restore">Restore</string>
|
||||||
<string name="no_purchase_found">No purchase found.</string>
|
<string name="no_purchase_found">No purchase found.</string>
|
||||||
<string name="eugene_cheung_summary">For his contributions to the source code.</string>
|
<string name="eugene_cheung_summary">For his contributions to the source code.</string>
|
||||||
|
<string name="add_action">Add</string>
|
||||||
|
<string name="blacklist">Blacklist</string>
|
||||||
|
<string name="remove_from_blacklist">Remove from blacklist</string>
|
||||||
|
<string name="do_you_want_to_remove_from_the_blacklist"><![CDATA[Do you want to remove <b>%1$s</b> from the blacklist?]]></string>
|
||||||
|
<string name="clear_blacklist">Clear blacklist</string>
|
||||||
|
<string name="do_you_want_to_clear_the_blacklist">Do you want to clear the blacklist?</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
12
app/src/main/res/xml/pref_blacklist.xml
Normal file
12
app/src/main/res/xml/pref_blacklist.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<android.support.v7.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory android:title="Blacklist">
|
||||||
|
|
||||||
|
<com.kabouzeid.gramophone.preferences.BlacklistPreference
|
||||||
|
android:key="blacklist"
|
||||||
|
android:summary="The content of blacklisted folders is hidden from your library."
|
||||||
|
android:title="Blacklist" />
|
||||||
|
|
||||||
|
</com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory>
|
||||||
|
|
||||||
|
</android.support.v7.preference.PreferenceScreen>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue