This commit is contained in:
h4h13 2018-08-22 23:24:07 +05:30
parent fbd5e8bb61
commit 3f3818efb7
270 changed files with 7441 additions and 6502 deletions

View file

@ -4,6 +4,7 @@ import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import code.name.monkey.retromusic.R;
/**
@ -11,13 +12,13 @@ import code.name.monkey.retromusic.R;
*/
public class AnimationUtil {
public static void runLayoutAnimation(final RecyclerView recyclerView) {
final Context context = recyclerView.getContext();
final LayoutAnimationController controller =
AnimationUtils.loadLayoutAnimation(context, R.anim.layout_animation_slide_from_bottom);
public static void runLayoutAnimation(final RecyclerView recyclerView) {
final Context context = recyclerView.getContext();
final LayoutAnimationController controller =
AnimationUtils.loadLayoutAnimation(context, R.anim.layout_animation_slide_from_bottom);
recyclerView.setLayoutAnimation(controller);
recyclerView.getAdapter().notifyDataSetChanged();
recyclerView.scheduleLayoutAnimation();
}
recyclerView.setLayoutAnimation(controller);
recyclerView.getAdapter().notifyDataSetChanged();
recyclerView.scheduleLayoutAnimation();
}
}

View file

@ -39,7 +39,7 @@ public class DensityUtil {
* Converts sp to px
*
* @param context Context
* @param sp the value in sp
* @param sp the value in sp
* @return int
*/
public static int dip2sp(Context context, float sp) {

View file

@ -7,10 +7,7 @@ import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.webkit.MimeTypeMap;
import code.name.monkey.retromusic.loaders.SongLoader;
import code.name.monkey.retromusic.loaders.SortedCursor;
import code.name.monkey.retromusic.model.Song;
import io.reactivex.Observable;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -25,227 +22,232 @@ import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import code.name.monkey.retromusic.loaders.SongLoader;
import code.name.monkey.retromusic.loaders.SortedCursor;
import code.name.monkey.retromusic.model.Song;
import io.reactivex.Observable;
public final class FileUtil {
private FileUtil() {
}
public static byte[] readBytes(InputStream stream) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int count;
while ((count = stream.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
stream.close();
return baos.toByteArray();
}
@NonNull
public static Observable<ArrayList<Song>> matchFilesWithMediaStore(@NonNull Context context,
@Nullable List<File> files) {
return SongLoader.getSongs(makeSongCursor(context, files));
}
public static String safeGetCanonicalPath(File file) {
try {
return file.getCanonicalPath();
} catch (IOException e) {
e.printStackTrace();
return file.getAbsolutePath();
}
}
@Nullable
public static SortedCursor makeSongCursor(@NonNull final Context context,
@Nullable final List<File> files) {
String selection = null;
String[] paths = null;
if (files != null) {
paths = toPathArray(files);
if (files.size() > 0
&& files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle.
selection =
MediaStore.Audio.AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")";
}
private FileUtil() {
}
Cursor songCursor = SongLoader
.makeSongCursor(context, selection, selection == null ? null : paths);
return songCursor == null ? null
: new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA);
}
private static String makePlaceholders(int len) {
StringBuilder sb = new StringBuilder(len * 2 - 1);
sb.append("?");
for (int i = 1; i < len; i++) {
sb.append(",?");
public static byte[] readBytes(InputStream stream) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int count;
while ((count = stream.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
stream.close();
return baos.toByteArray();
}
return sb.toString();
}
@Nullable
private static String[] toPathArray(@Nullable List<File> files) {
if (files != null) {
String[] paths = new String[files.size()];
for (int i = 0; i < files.size(); i++) {
@NonNull
public static Observable<ArrayList<Song>> matchFilesWithMediaStore(@NonNull Context context,
@Nullable List<File> files) {
return SongLoader.getSongs(makeSongCursor(context, files));
}
public static String safeGetCanonicalPath(File file) {
try {
return file.getCanonicalPath();
} catch (IOException e) {
e.printStackTrace();
return file.getAbsolutePath();
}
}
@Nullable
public static SortedCursor makeSongCursor(@NonNull final Context context,
@Nullable final List<File> files) {
String selection = null;
String[] paths = null;
if (files != null) {
paths = toPathArray(files);
if (files.size() > 0
&& files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle.
selection =
MediaStore.Audio.AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")";
}
}
Cursor songCursor = SongLoader
.makeSongCursor(context, selection, selection == null ? null : paths);
return songCursor == null ? null
: new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA);
}
private static String makePlaceholders(int len) {
StringBuilder sb = new StringBuilder(len * 2 - 1);
sb.append("?");
for (int i = 1; i < len; i++) {
sb.append(",?");
}
return sb.toString();
}
@Nullable
private static String[] toPathArray(@Nullable List<File> files) {
if (files != null) {
String[] paths = new String[files.size()];
for (int i = 0; i < files.size(); i++) {
/*try {
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();
}*/
paths[i] = safeGetCanonicalPath(files.get(i));
}
return paths;
}
return null;
}
@NonNull
public static List<File> listFiles(@NonNull File directory, @Nullable FileFilter fileFilter) {
List<File> fileList = new LinkedList<>();
File[] found = directory.listFiles(fileFilter);
if (found != null) {
Collections.addAll(fileList, found);
}
return fileList;
}
@NonNull
public static List<File> listFilesDeep(@NonNull File directory, @Nullable FileFilter fileFilter) {
List<File> files = new LinkedList<>();
internalListFilesDeep(files, directory, fileFilter);
return files;
}
@NonNull
public static List<File> listFilesDeep(@NonNull Collection<File> files,
@Nullable FileFilter fileFilter) {
List<File> resFiles = new LinkedList<>();
for (File file : files) {
if (file.isDirectory()) {
internalListFilesDeep(resFiles, file, fileFilter);
} else if (fileFilter == null || fileFilter.accept(file)) {
resFiles.add(file);
}
}
return resFiles;
}
private static void internalListFilesDeep(@NonNull Collection<File> files,
@NonNull File directory, @Nullable FileFilter fileFilter) {
File[] found = directory.listFiles(fileFilter);
if (found != null) {
for (File file : found) {
if (file.isDirectory()) {
internalListFilesDeep(files, file, fileFilter);
} else {
files.add(file);
paths[i] = safeGetCanonicalPath(files.get(i));
}
return paths;
}
}
return null;
}
}
public static boolean fileIsMimeType(File file, String mimeType, MimeTypeMap mimeTypeMap) {
if (mimeType == null || mimeType.equals("*/*")) {
return true;
} else {
// get the file mime type
String filename = file.toURI().toString();
int dotPos = filename.lastIndexOf('.');
if (dotPos == -1) {
return false;
}
String fileExtension = filename.substring(dotPos + 1).toLowerCase();
String fileType = mimeTypeMap.getMimeTypeFromExtension(fileExtension);
if (fileType == null) {
return false;
}
// check the 'type/subtype' pattern
if (fileType.equals(mimeType)) {
return true;
}
// check the 'type/*' pattern
int mimeTypeDelimiter = mimeType.lastIndexOf('/');
if (mimeTypeDelimiter == -1) {
return false;
}
String mimeTypeMainType = mimeType.substring(0, mimeTypeDelimiter);
String mimeTypeSubtype = mimeType.substring(mimeTypeDelimiter + 1);
if (!mimeTypeSubtype.equals("*")) {
return false;
}
int fileTypeDelimiter = fileType.lastIndexOf('/');
if (fileTypeDelimiter == -1) {
return false;
}
String fileTypeMainType = fileType.substring(0, fileTypeDelimiter);
if (fileTypeMainType.equals(mimeTypeMainType)) {
return true;
}
return fileTypeMainType.equals(mimeTypeMainType);
@NonNull
public static List<File> listFiles(@NonNull File directory, @Nullable FileFilter fileFilter) {
List<File> fileList = new LinkedList<>();
File[] found = directory.listFiles(fileFilter);
if (found != null) {
Collections.addAll(fileList, found);
}
return fileList;
}
}
public static String stripExtension(String str) {
if (str == null) {
return null;
@NonNull
public static List<File> listFilesDeep(@NonNull File directory, @Nullable FileFilter fileFilter) {
List<File> files = new LinkedList<>();
internalListFilesDeep(files, directory, fileFilter);
return files;
}
int pos = str.lastIndexOf('.');
if (pos == -1) {
return str;
@NonNull
public static List<File> listFilesDeep(@NonNull Collection<File> files,
@Nullable FileFilter fileFilter) {
List<File> resFiles = new LinkedList<>();
for (File file : files) {
if (file.isDirectory()) {
internalListFilesDeep(resFiles, file, fileFilter);
} else if (fileFilter == null || fileFilter.accept(file)) {
resFiles.add(file);
}
}
return resFiles;
}
return str.substring(0, pos);
}
public static String readFromStream(InputStream is) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (sb.length() > 0) {
sb.append("\n");
}
sb.append(line);
private static void internalListFilesDeep(@NonNull Collection<File> files,
@NonNull File directory, @Nullable FileFilter fileFilter) {
File[] found = directory.listFiles(fileFilter);
if (found != null) {
for (File file : found) {
if (file.isDirectory()) {
internalListFilesDeep(files, file, fileFilter);
} else {
files.add(file);
}
}
}
}
reader.close();
return sb.toString();
}
public static String read(File file) throws Exception {
FileInputStream fin = new FileInputStream(file);
String ret = readFromStream(fin);
fin.close();
return ret;
}
public static boolean isExternalMemoryAvailable() {
Boolean isSDPresent = Environment.getExternalStorageState()
.equals(android.os.Environment.MEDIA_MOUNTED);
Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable();
if (isSDSupportedDevice && isSDPresent) {
// yes SD-card is present
return true;
} else {
return false;
// Sorry
public static boolean fileIsMimeType(File file, String mimeType, MimeTypeMap mimeTypeMap) {
if (mimeType == null || mimeType.equals("*/*")) {
return true;
} else {
// get the file mime type
String filename = file.toURI().toString();
int dotPos = filename.lastIndexOf('.');
if (dotPos == -1) {
return false;
}
String fileExtension = filename.substring(dotPos + 1).toLowerCase();
String fileType = mimeTypeMap.getMimeTypeFromExtension(fileExtension);
if (fileType == null) {
return false;
}
// check the 'type/subtype' pattern
if (fileType.equals(mimeType)) {
return true;
}
// check the 'type/*' pattern
int mimeTypeDelimiter = mimeType.lastIndexOf('/');
if (mimeTypeDelimiter == -1) {
return false;
}
String mimeTypeMainType = mimeType.substring(0, mimeTypeDelimiter);
String mimeTypeSubtype = mimeType.substring(mimeTypeDelimiter + 1);
if (!mimeTypeSubtype.equals("*")) {
return false;
}
int fileTypeDelimiter = fileType.lastIndexOf('/');
if (fileTypeDelimiter == -1) {
return false;
}
String fileTypeMainType = fileType.substring(0, fileTypeDelimiter);
if (fileTypeMainType.equals(mimeTypeMainType)) {
return true;
}
return fileTypeMainType.equals(mimeTypeMainType);
}
}
}
public static File safeGetCanonicalFile(File file) {
try {
return file.getCanonicalFile();
} catch (IOException e) {
e.printStackTrace();
return file.getAbsoluteFile();
public static String stripExtension(String str) {
if (str == null) {
return null;
}
int pos = str.lastIndexOf('.');
if (pos == -1) {
return str;
}
return str.substring(0, pos);
}
public static String readFromStream(InputStream is) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (sb.length() > 0) {
sb.append("\n");
}
sb.append(line);
}
reader.close();
return sb.toString();
}
public static String read(File file) throws Exception {
FileInputStream fin = new FileInputStream(file);
String ret = readFromStream(fin);
fin.close();
return ret;
}
public static boolean isExternalMemoryAvailable() {
Boolean isSDPresent = Environment.getExternalStorageState()
.equals(android.os.Environment.MEDIA_MOUNTED);
Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable();
if (isSDSupportedDevice && isSDPresent) {
// yes SD-card is present
return true;
} else {
return false;
// Sorry
}
}
public static File safeGetCanonicalFile(File file) {
try {
return file.getCanonicalFile();
} catch (IOException e) {
e.printStackTrace();
return file.getAbsoluteFile();
}
}
}
}

View file

@ -9,6 +9,7 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.media.ExifInterface;
import android.support.annotation.NonNull;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@ -19,204 +20,204 @@ import java.io.IOException;
*/
public class ImageUtil {
private static final int TOLERANCE = 20;
// Alpha amount for which values below are considered transparent.
private static final int ALPHA_TOLERANCE = 50;
private static int[] mTempBuffer;
private static final int TOLERANCE = 20;
// Alpha amount for which values below are considered transparent.
private static final int ALPHA_TOLERANCE = 50;
private static int[] mTempBuffer;
private ImageUtil() {
private ImageUtil() {
}
public static boolean isGrayscale(Bitmap bitmap) {
final int height = bitmap.getHeight();
final int width = bitmap.getWidth();
int size = height * width;
ensureBufferSize(size);
bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height);
for (int i = 0; i < size; i++) {
if (!isGrayscale(mTempBuffer[i])) {
return false;
}
}
return true;
}
/**
* Makes sure that {@code mTempBuffer} has at least length {@code size}.
*/
private static void ensureBufferSize(int size) {
if (mTempBuffer == null || mTempBuffer.length < size) {
mTempBuffer = new int[size];
}
}
public static Bitmap setBitmapColor(Bitmap bitmap, int color) {
Bitmap result = Bitmap
.createBitmap(bitmap, 0, 0, bitmap.getWidth() - 1, bitmap.getHeight() - 1);
Paint paint = new Paint();
paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
Canvas canvas = new Canvas(result);
canvas.drawBitmap(result, 0, 0, paint);
return result;
}
public static boolean isGrayscale(int color) {
int alpha = 0xFF & (color >> 24);
if (alpha < ALPHA_TOLERANCE) {
return true;
}
int r = 0xFF & (color >> 16);
int g = 0xFF & (color >> 8);
int b = 0xFF & color;
return Math.abs(r - g) < TOLERANCE
&& Math.abs(r - b) < TOLERANCE
&& Math.abs(g - b) < TOLERANCE;
} // Amount (max is 255) that two channels can differ before the color is no longer "gray".
public static Bitmap resizeBitmap(@NonNull Bitmap src, int maxForSmallerSize) {
int width = src.getWidth();
int height = src.getHeight();
final int dstWidth;
final int dstHeight;
if (width < height) {
if (maxForSmallerSize >= width) {
return src;
}
float ratio = (float) height / width;
dstWidth = maxForSmallerSize;
dstHeight = Math.round(maxForSmallerSize * ratio);
} else {
if (maxForSmallerSize >= height) {
return src;
}
float ratio = (float) width / height;
dstWidth = Math.round(maxForSmallerSize * ratio);
dstHeight = maxForSmallerSize;
}
return Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
}
public static int calculateInSampleSize(int width, int height, int reqWidth) {
// setting reqWidth matching to desired 1:1 ratio and screen-size
if (width < height) {
reqWidth = (height / width) * reqWidth;
} else {
reqWidth = (width / height) * reqWidth;
public static boolean isGrayscale(Bitmap bitmap) {
final int height = bitmap.getHeight();
final int width = bitmap.getWidth();
int size = height * width;
ensureBufferSize(size);
bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height);
for (int i = 0; i < size; i++) {
if (!isGrayscale(mTempBuffer[i])) {
return false;
}
}
return true;
}
int inSampleSize = 1;
if (height > reqWidth || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqWidth
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
/**
* Makes sure that {@code mTempBuffer} has at least length {@code size}.
*/
private static void ensureBufferSize(int size) {
if (mTempBuffer == null || mTempBuffer.length < size) {
mTempBuffer = new int[size];
}
}
return inSampleSize;
}
public static Bitmap setBitmapColor(Bitmap bitmap, int color) {
Bitmap result = Bitmap
.createBitmap(bitmap, 0, 0, bitmap.getWidth() - 1, bitmap.getHeight() - 1);
Paint paint = new Paint();
paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
static File compressImage(File imageFile, int reqWidth, int reqHeight,
Bitmap.CompressFormat compressFormat, int quality, String destinationPath)
throws IOException {
FileOutputStream fileOutputStream = null;
File file = new File(destinationPath).getParentFile();
if (!file.exists()) {
file.mkdirs();
}
try {
fileOutputStream = new FileOutputStream(destinationPath);
// write the compressed bitmap at the destination specified by destinationPath.
decodeSampledBitmapFromFile(imageFile, reqWidth, reqHeight)
.compress(compressFormat, quality, fileOutputStream);
} finally {
if (fileOutputStream != null) {
fileOutputStream.flush();
fileOutputStream.close();
}
Canvas canvas = new Canvas(result);
canvas.drawBitmap(result, 0, 0, paint);
return result;
}
return new File(destinationPath);
}
public static boolean isGrayscale(int color) {
int alpha = 0xFF & (color >> 24);
if (alpha < ALPHA_TOLERANCE) {
return true;
}
int r = 0xFF & (color >> 16);
int g = 0xFF & (color >> 8);
int b = 0xFF & color;
return Math.abs(r - g) < TOLERANCE
&& Math.abs(r - b) < TOLERANCE
&& Math.abs(g - b) < TOLERANCE;
} // Amount (max is 255) that two channels can differ before the color is no longer "gray".
static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight)
throws IOException {
// First decode with inJustDecodeBounds=true to check dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);
public static Bitmap resizeBitmap(@NonNull Bitmap src, int maxForSmallerSize) {
int width = src.getWidth();
int height = src.getHeight();
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
final int dstWidth;
final int dstHeight;
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
if (width < height) {
if (maxForSmallerSize >= width) {
return src;
}
float ratio = (float) height / width;
dstWidth = maxForSmallerSize;
dstHeight = Math.round(maxForSmallerSize * ratio);
} else {
if (maxForSmallerSize >= height) {
return src;
}
float ratio = (float) width / height;
dstWidth = Math.round(maxForSmallerSize * ratio);
dstHeight = maxForSmallerSize;
}
Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);
//check the rotation of the image and display it properly
ExifInterface exif;
exif = new ExifInterface(imageFile.getAbsolutePath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
} else if (orientation == 3) {
matrix.postRotate(180);
} else if (orientation == 8) {
matrix.postRotate(270);
}
scaledBitmap = Bitmap
.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix,
true);
return scaledBitmap;
}
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth,
int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
return Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
}
return inSampleSize;
}
public static int calculateInSampleSize(int width, int height, int reqWidth) {
// setting reqWidth matching to desired 1:1 ratio and screen-size
if (width < height) {
reqWidth = (height / width) * reqWidth;
} else {
reqWidth = (width / height) * reqWidth;
}
public static Bitmap getResizedBitmap(Bitmap image, int maxSize) {
int width = image.getWidth();
int height = image.getHeight();
int inSampleSize = 1;
float bitmapRatio = (float) width / (float) height;
if (bitmapRatio > 1) {
width = maxSize;
height = (int) (width / bitmapRatio);
} else {
height = maxSize;
width = (int) (height * bitmapRatio);
if (height > reqWidth || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqWidth
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
static File compressImage(File imageFile, int reqWidth, int reqHeight,
Bitmap.CompressFormat compressFormat, int quality, String destinationPath)
throws IOException {
FileOutputStream fileOutputStream = null;
File file = new File(destinationPath).getParentFile();
if (!file.exists()) {
file.mkdirs();
}
try {
fileOutputStream = new FileOutputStream(destinationPath);
// write the compressed bitmap at the destination specified by destinationPath.
decodeSampledBitmapFromFile(imageFile, reqWidth, reqHeight)
.compress(compressFormat, quality, fileOutputStream);
} finally {
if (fileOutputStream != null) {
fileOutputStream.flush();
fileOutputStream.close();
}
}
return new File(destinationPath);
}
static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight)
throws IOException {
// First decode with inJustDecodeBounds=true to check dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);
//check the rotation of the image and display it properly
ExifInterface exif;
exif = new ExifInterface(imageFile.getAbsolutePath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
} else if (orientation == 3) {
matrix.postRotate(180);
} else if (orientation == 8) {
matrix.postRotate(270);
}
scaledBitmap = Bitmap
.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix,
true);
return scaledBitmap;
}
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth,
int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap getResizedBitmap(Bitmap image, int maxSize) {
int width = image.getWidth();
int height = image.getHeight();
float bitmapRatio = (float) width / (float) height;
if (bitmapRatio > 1) {
width = maxSize;
height = (int) (width / bitmapRatio);
} else {
height = maxSize;
width = (int) (height * bitmapRatio);
}
return Bitmap.createScaledBitmap(image, width, height, true);
}
return Bitmap.createScaledBitmap(image, width, height, true);
}
}

View file

@ -1,69 +1,70 @@
package code.name.monkey.retromusic.util;
import code.name.monkey.retromusic.rest.model.LastFmAlbum.Album.Image;
import code.name.monkey.retromusic.rest.model.LastFmArtist;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import code.name.monkey.retromusic.rest.model.LastFmAlbum.Album.Image;
import code.name.monkey.retromusic.rest.model.LastFmArtist;
public class LastFMUtil {
public static String getLargestAlbumImageUrl(List<Image> list) {
Map hashMap = new HashMap();
for (Image image : list) {
Object obj = null;
String size = image.getSize();
if (size == null) {
obj = ImageSize.UNKNOWN;
} else {
try {
obj = ImageSize.valueOf(size.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException ignored) {
public static String getLargestAlbumImageUrl(List<Image> list) {
Map hashMap = new HashMap();
for (Image image : list) {
Object obj = null;
String size = image.getSize();
if (size == null) {
obj = ImageSize.UNKNOWN;
} else {
try {
obj = ImageSize.valueOf(size.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException ignored) {
}
}
if (obj != null) {
hashMap.put(obj, image.getText());
}
}
}
if (obj != null) {
hashMap.put(obj, image.getText());
}
return getLargestImageUrl(hashMap);
}
return getLargestImageUrl(hashMap);
}
public static String getLargestArtistImageUrl(List<LastFmArtist.Artist.Image> list) {
Map hashMap = new HashMap();
for (LastFmArtist.Artist.Image image : list) {
Object obj = null;
String size = image.getSize();
if (size == null) {
obj = ImageSize.UNKNOWN;
} else {
try {
obj = ImageSize.valueOf(size.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException ignored) {
public static String getLargestArtistImageUrl(List<LastFmArtist.Artist.Image> list) {
Map hashMap = new HashMap();
for (LastFmArtist.Artist.Image image : list) {
Object obj = null;
String size = image.getSize();
if (size == null) {
obj = ImageSize.UNKNOWN;
} else {
try {
obj = ImageSize.valueOf(size.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException ignored) {
}
}
if (obj != null) {
hashMap.put(obj, image.getText());
}
}
}
if (obj != null) {
hashMap.put(obj, image.getText());
}
return getLargestImageUrl(hashMap);
}
return getLargestImageUrl(hashMap);
}
private static String getLargestImageUrl(Map<ImageSize, String> map) {
return map.containsKey(ImageSize.MEGA) ? map.get(ImageSize.MEGA)
: map.containsKey(ImageSize.EXTRALARGE) ? map.get(ImageSize.EXTRALARGE)
: map.containsKey(ImageSize.LARGE) ? map.get(ImageSize.LARGE)
private static String getLargestImageUrl(Map<ImageSize, String> map) {
return map.containsKey(ImageSize.MEGA) ? map.get(ImageSize.MEGA)
: map.containsKey(ImageSize.EXTRALARGE) ? map.get(ImageSize.EXTRALARGE)
: map.containsKey(ImageSize.LARGE) ? map.get(ImageSize.LARGE)
: map.containsKey(ImageSize.MEDIUM) ? map.get(ImageSize.MEDIUM)
: map.containsKey(ImageSize.SMALL) ? map.get(ImageSize.SMALL)
: map.containsKey(ImageSize.UNKNOWN) ? map.get(ImageSize.UNKNOWN) : null;
}
: map.containsKey(ImageSize.SMALL) ? map.get(ImageSize.SMALL)
: map.containsKey(ImageSize.UNKNOWN) ? map.get(ImageSize.UNKNOWN) : null;
}
private enum ImageSize {
SMALL,
MEDIUM,
LARGE,
EXTRALARGE,
MEGA,
UNKNOWN
}
private enum ImageSize {
SMALL,
MEDIUM,
LARGE,
EXTRALARGE,
MEGA,
UNKNOWN
}
}

View file

@ -18,6 +18,17 @@ import android.support.v4.content.FileProvider;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.tag.FieldKey;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
import code.name.monkey.retromusic.loaders.PlaylistLoader;
@ -27,384 +38,376 @@ import code.name.monkey.retromusic.model.Playlist;
import code.name.monkey.retromusic.model.Song;
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics;
import io.reactivex.Observable;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.tag.FieldKey;
public class MusicUtil {
public static final String TAG = MusicUtil.class.getSimpleName();
private static Playlist playlist;
public static final String TAG = MusicUtil.class.getSimpleName();
private static Playlist playlist;
public static Uri getMediaStoreAlbumCoverUri(int albumId) {
final Uri sArtworkUri = Uri
.parse("content://media/external/audio/albumart");
public static Uri getMediaStoreAlbumCoverUri(int albumId) {
final Uri sArtworkUri = Uri
.parse("content://media/external/audio/albumart");
return ContentUris.withAppendedId(sArtworkUri, albumId);
}
public static Uri getSongFileUri(int songId) {
return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);
}
@NonNull
public static Intent createShareSongFileIntent(@NonNull final Song song, Context context) {
try {
return new Intent()
.setAction(Intent.ACTION_SEND)
.putExtra(Intent.EXTRA_STREAM,
FileProvider.getUriForFile(context,
context.getApplicationContext().getPackageName(),
new File(song.data)))
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.setType("audio/*");
} catch (IllegalArgumentException e) {
// TODO the path is most likely not like /storage/emulated/0/... but something like /storage/28C7-75B0/...
e.printStackTrace();
Toast.makeText(context, "Could not share this file, I'm aware of the issue.",
Toast.LENGTH_SHORT).show();
return new Intent();
}
}
public static void setRingtone(@NonNull final Context context, final int id) {
final ContentResolver resolver = context.getContentResolver();
final Uri uri = getSongFileUri(id);
try {
final ContentValues values = new ContentValues(2);
values.put(MediaStore.Audio.AudioColumns.IS_RINGTONE, "1");
values.put(MediaStore.Audio.AudioColumns.IS_ALARM, "1");
resolver.update(uri, values, null, null);
} catch (@NonNull final UnsupportedOperationException ignored) {
return;
return ContentUris.withAppendedId(sArtworkUri, albumId);
}
try {
Cursor cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.MediaColumns.TITLE},
BaseColumns._ID + "=?",
new String[]{String.valueOf(id)},
null);
try {
if (cursor != null && cursor.getCount() == 1) {
cursor.moveToFirst();
Settings.System.putString(resolver, Settings.System.RINGTONE, uri.toString());
final String message = context
.getString(R.string.x_has_been_set_as_ringtone, cursor.getString(0));
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
public static Uri getSongFileUri(int songId) {
return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);
}
@NonNull
public static Intent createShareSongFileIntent(@NonNull final Song song, Context context) {
try {
return new Intent()
.setAction(Intent.ACTION_SEND)
.putExtra(Intent.EXTRA_STREAM,
FileProvider.getUriForFile(context,
context.getApplicationContext().getPackageName(),
new File(song.data)))
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.setType("audio/*");
} catch (IllegalArgumentException e) {
// TODO the path is most likely not like /storage/emulated/0/... but something like /storage/28C7-75B0/...
e.printStackTrace();
Toast.makeText(context, "Could not share this file, I'm aware of the issue.",
Toast.LENGTH_SHORT).show();
return new Intent();
}
} finally {
if (cursor != null) {
cursor.close();
}
}
} catch (SecurityException ignored) {
}
}
@NonNull
public static String getArtistInfoString(@NonNull final Context context,
@NonNull final Artist artist) {
int albumCount = artist.getAlbumCount();
int songCount = artist.getSongCount();
String albumString = albumCount == 1 ? context.getResources().getString(R.string.album)
: context.getResources().getString(R.string.albums);
String songString = songCount == 1 ? context.getResources().getString(R.string.song)
: context.getResources().getString(R.string.songs);
return albumCount + " " + albumString + "" + songCount + " " + songString;
}
@NonNull
public static String getArtistInfoStringSmall(@NonNull final Context context,
@NonNull final Artist artist) {
int songCount = artist.getSongCount();
String songString = songCount == 1 ? context.getResources().getString(R.string.song)
: context.getResources().getString(R.string.songs);
return songCount + " " + songString;
}
@NonNull
public static String getPlaylistInfoString(@NonNull final Context context,
@NonNull List<Song> songs) {
final int songCount = songs.size();
final String songString = songCount == 1 ? context.getResources().getString(R.string.song)
: context.getResources().getString(R.string.songs);
long duration = 0;
for (int i = 0; i < songs.size(); i++) {
duration += songs.get(i).duration;
}
return songCount + " " + songString + "" + MusicUtil.getReadableDurationString(duration);
}
public static String getReadableDurationString(long songDurationMillis) {
long minutes = (songDurationMillis / 1000) / 60;
long seconds = (songDurationMillis / 1000) % 60;
if (minutes < 60) {
return String.format(Locale.getDefault(), "%01d:%02d", minutes, seconds);
} else {
long hours = minutes / 60;
minutes = minutes % 60;
return String.format(Locale.getDefault(), "%d:%02d:%02d", hours, minutes, seconds);
}
}
//iTunes uses for example 1002 for track 2 CD1 or 3011 for track 11 CD3.
//this method converts those values to normal tracknumbers
public static int getFixedTrackNumber(int trackNumberToFix) {
return trackNumberToFix % 1000;
}
public static void insertAlbumArt(@NonNull Context context, int albumId, String path) {
ContentResolver contentResolver = context.getContentResolver();
Uri artworkUri = Uri.parse("content://media/external/audio/albumart");
contentResolver.delete(ContentUris.withAppendedId(artworkUri, albumId), null, null);
ContentValues values = new ContentValues();
values.put("album_id", albumId);
values.put("_data", path);
contentResolver.insert(artworkUri, values);
}
@NonNull
public static File createAlbumArtFile() {
return new File(createAlbumArtDir(), String.valueOf(System.currentTimeMillis()));
}
@NonNull
@SuppressWarnings("ResultOfMethodCallIgnored")
private static File createAlbumArtDir() {
File albumArtDir = new File(Environment.getExternalStorageDirectory(), "/albumthumbs/");
if (!albumArtDir.exists()) {
albumArtDir.mkdirs();
try {
new File(albumArtDir, ".nomedia").createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
return albumArtDir;
}
public static void deleteTracks(@NonNull final Activity activity,
@NonNull final List<Song> songs) {
final String[] projection = new String[]{
BaseColumns._ID, MediaStore.MediaColumns.DATA
};
final StringBuilder selection = new StringBuilder();
selection.append(BaseColumns._ID + " IN (");
for (int i = 0; i < songs.size(); i++) {
selection.append(songs.get(i).id);
if (i < songs.size() - 1) {
selection.append(",");
}
}
selection.append(")");
try {
final Cursor cursor = activity.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection.toString(),
null, null);
if (cursor != null) {
// Step 1: Remove selected tracks from the current playlist, as well
// as from the album art cache
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
final int id = cursor.getInt(0);
Song song = SongLoader.getSong(activity, id).blockingFirst();
MusicPlayerRemote.removeFromQueue(song);
cursor.moveToNext();
public static void setRingtone(@NonNull final Context context, final int id) {
final ContentResolver resolver = context.getContentResolver();
final Uri uri = getSongFileUri(id);
try {
final ContentValues values = new ContentValues(2);
values.put(MediaStore.Audio.AudioColumns.IS_RINGTONE, "1");
values.put(MediaStore.Audio.AudioColumns.IS_ALARM, "1");
resolver.update(uri, values, null, null);
} catch (@NonNull final UnsupportedOperationException ignored) {
return;
}
// Step 2: Remove selected tracks from the database
activity.getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
selection.toString(), null);
// Step 3: Remove files from card
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
final String name = cursor.getString(1);
try { // File.delete can throw a security exception
final File f = new File(name);
if (!f.delete()) {
// I'm not sure if we'd ever get here (deletion would
// have to fail, but no exception thrown)
Log.e("MusicUtils", "Failed to delete file " + name);
}
cursor.moveToNext();
} catch (@NonNull final SecurityException ex) {
cursor.moveToNext();
} catch (NullPointerException e) {
Log.e("MusicUtils", "Failed to find file " + name);
}
}
cursor.close();
}
activity.getContentResolver().notifyChange(Uri.parse("content://media"), null);
Toast.makeText(activity, activity.getString(R.string.deleted_x_songs, songs.size()),
Toast.LENGTH_SHORT).show();
} catch (SecurityException ignored) {
}
}
public static void deleteAlbumArt(@NonNull Context context, int albumId) {
ContentResolver contentResolver = context.getContentResolver();
Uri localUri = Uri.parse("content://media/external/audio/albumart");
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId), null, null);
}
@Nullable
public static String getLyrics(Song song) {
String lyrics = null;
File file = new File(song.data);
try {
lyrics = AudioFileIO.read(file).getTagOrCreateDefault().getFirst(FieldKey.LYRICS);
} catch (Exception e) {
e.printStackTrace();
}
if (lyrics == null || lyrics.trim().isEmpty() || !AbsSynchronizedLyrics
.isSynchronized(lyrics)) {
File dir = file.getAbsoluteFile().getParentFile();
if (dir != null && dir.exists() && dir.isDirectory()) {
String format = ".*%s.*\\.(lrc|txt)";
String filename = Pattern.quote(FileUtil.stripExtension(file.getName()));
String songtitle = Pattern.quote(song.title);
final ArrayList<Pattern> patterns = new ArrayList<>();
patterns.add(Pattern.compile(String.format(format, filename),
Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE));
patterns.add(Pattern.compile(String.format(format, songtitle),
Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE));
File[] files = dir.listFiles(f -> {
for (Pattern pattern : patterns) {
if (pattern.matcher(f.getName()).matches()) {
return true;
}
}
return false;
});
if (files != null && files.length > 0) {
for (File f : files) {
try {
Cursor cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.MediaColumns.TITLE},
BaseColumns._ID + "=?",
new String[]{String.valueOf(id)},
null);
try {
String newLyrics = FileUtil.read(f);
if (newLyrics != null && !newLyrics.trim().isEmpty()) {
if (AbsSynchronizedLyrics.isSynchronized(newLyrics)) {
return newLyrics;
if (cursor != null && cursor.getCount() == 1) {
cursor.moveToFirst();
Settings.System.putString(resolver, Settings.System.RINGTONE, uri.toString());
final String message = context
.getString(R.string.x_has_been_set_as_ringtone, cursor.getString(0));
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
} finally {
if (cursor != null) {
cursor.close();
}
lyrics = newLyrics;
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (SecurityException ignored) {
}
}
}
return lyrics;
}
public static void toggleFavorite(@NonNull final Context context, @NonNull final Song song) {
if (isFavorite(context, song)) {
PlaylistsUtil
.removeFromPlaylist(context, song, getFavoritesPlaylist(context).blockingFirst().id);
} else {
PlaylistsUtil
.addToPlaylist(context, song, getOrCreateFavoritesPlaylist(context).blockingFirst().id,
false);
@NonNull
public static String getArtistInfoString(@NonNull final Context context,
@NonNull final Artist artist) {
int albumCount = artist.getAlbumCount();
int songCount = artist.getSongCount();
String albumString = albumCount == 1 ? context.getResources().getString(R.string.album)
: context.getResources().getString(R.string.albums);
String songString = songCount == 1 ? context.getResources().getString(R.string.song)
: context.getResources().getString(R.string.songs);
return albumCount + " " + albumString + "" + songCount + " " + songString;
}
}
public static boolean isFavoritePlaylist(@NonNull final Context context,
@NonNull final Playlist playlist) {
return playlist.name != null && playlist.name.equals(context.getString(R.string.favorites));
}
@NonNull
public static String getArtistInfoStringSmall(@NonNull final Context context,
@NonNull final Artist artist) {
int songCount = artist.getSongCount();
String songString = songCount == 1 ? context.getResources().getString(R.string.song)
: context.getResources().getString(R.string.songs);
return songCount + " " + songString;
}
private static Observable<Playlist> getFavoritesPlaylist(@NonNull final Context context) {
return PlaylistLoader.getPlaylist(context, context.getString(R.string.favorites));
}
@NonNull
public static String getPlaylistInfoString(@NonNull final Context context,
@NonNull List<Song> songs) {
final int songCount = songs.size();
final String songString = songCount == 1 ? context.getResources().getString(R.string.song)
: context.getResources().getString(R.string.songs);
private static Observable<Playlist> getOrCreateFavoritesPlaylist(@NonNull final Context context) {
return PlaylistLoader.getPlaylist(context,
PlaylistsUtil.createPlaylist(context, context.getString(R.string.favorites)));
}
long duration = 0;
for (int i = 0; i < songs.size(); i++) {
duration += songs.get(i).duration;
}
public static boolean isFavorite(@NonNull final Context context, @NonNull final Song song) {
return songCount + " " + songString + "" + MusicUtil.getReadableDurationString(duration);
}
public static String getReadableDurationString(long songDurationMillis) {
long minutes = (songDurationMillis / 1000) / 60;
long seconds = (songDurationMillis / 1000) % 60;
if (minutes < 60) {
return String.format(Locale.getDefault(), "%01d:%02d", minutes, seconds);
} else {
long hours = minutes / 60;
minutes = minutes % 60;
return String.format(Locale.getDefault(), "%d:%02d:%02d", hours, minutes, seconds);
}
}
//iTunes uses for example 1002 for track 2 CD1 or 3011 for track 11 CD3.
//this method converts those values to normal tracknumbers
public static int getFixedTrackNumber(int trackNumberToFix) {
return trackNumberToFix % 1000;
}
public static void insertAlbumArt(@NonNull Context context, int albumId, String path) {
ContentResolver contentResolver = context.getContentResolver();
Uri artworkUri = Uri.parse("content://media/external/audio/albumart");
contentResolver.delete(ContentUris.withAppendedId(artworkUri, albumId), null, null);
ContentValues values = new ContentValues();
values.put("album_id", albumId);
values.put("_data", path);
contentResolver.insert(artworkUri, values);
}
@NonNull
public static File createAlbumArtFile() {
return new File(createAlbumArtDir(), String.valueOf(System.currentTimeMillis()));
}
@NonNull
@SuppressWarnings("ResultOfMethodCallIgnored")
private static File createAlbumArtDir() {
File albumArtDir = new File(Environment.getExternalStorageDirectory(), "/albumthumbs/");
if (!albumArtDir.exists()) {
albumArtDir.mkdirs();
try {
new File(albumArtDir, ".nomedia").createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
return albumArtDir;
}
public static void deleteTracks(@NonNull final Activity activity,
@NonNull final List<Song> songs) {
final String[] projection = new String[]{
BaseColumns._ID, MediaStore.MediaColumns.DATA
};
final StringBuilder selection = new StringBuilder();
selection.append(BaseColumns._ID + " IN (");
for (int i = 0; i < songs.size(); i++) {
selection.append(songs.get(i).id);
if (i < songs.size() - 1) {
selection.append(",");
}
}
selection.append(")");
try {
final Cursor cursor = activity.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection.toString(),
null, null);
if (cursor != null) {
// Step 1: Remove selected tracks from the current playlist, as well
// as from the album art cache
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
final int id = cursor.getInt(0);
Song song = SongLoader.getSong(activity, id).blockingFirst();
MusicPlayerRemote.removeFromQueue(song);
cursor.moveToNext();
}
// Step 2: Remove selected tracks from the database
activity.getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
selection.toString(), null);
// Step 3: Remove files from card
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
final String name = cursor.getString(1);
try { // File.delete can throw a security exception
final File f = new File(name);
if (!f.delete()) {
// I'm not sure if we'd ever get here (deletion would
// have to fail, but no exception thrown)
Log.e("MusicUtils", "Failed to delete file " + name);
}
cursor.moveToNext();
} catch (@NonNull final SecurityException ex) {
cursor.moveToNext();
} catch (NullPointerException e) {
Log.e("MusicUtils", "Failed to find file " + name);
}
}
cursor.close();
}
activity.getContentResolver().notifyChange(Uri.parse("content://media"), null);
Toast.makeText(activity, activity.getString(R.string.deleted_x_songs, songs.size()),
Toast.LENGTH_SHORT).show();
} catch (SecurityException ignored) {
}
}
public static void deleteAlbumArt(@NonNull Context context, int albumId) {
ContentResolver contentResolver = context.getContentResolver();
Uri localUri = Uri.parse("content://media/external/audio/albumart");
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId), null, null);
}
@Nullable
public static String getLyrics(Song song) {
String lyrics = null;
File file = new File(song.data);
try {
lyrics = AudioFileIO.read(file).getTagOrCreateDefault().getFirst(FieldKey.LYRICS);
} catch (Exception e) {
e.printStackTrace();
}
if (lyrics == null || lyrics.trim().isEmpty() || !AbsSynchronizedLyrics
.isSynchronized(lyrics)) {
File dir = file.getAbsoluteFile().getParentFile();
if (dir != null && dir.exists() && dir.isDirectory()) {
String format = ".*%s.*\\.(lrc|txt)";
String filename = Pattern.quote(FileUtil.stripExtension(file.getName()));
String songtitle = Pattern.quote(song.title);
final ArrayList<Pattern> patterns = new ArrayList<>();
patterns.add(Pattern.compile(String.format(format, filename),
Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE));
patterns.add(Pattern.compile(String.format(format, songtitle),
Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE));
File[] files = dir.listFiles(f -> {
for (Pattern pattern : patterns) {
if (pattern.matcher(f.getName()).matches()) {
return true;
}
}
return false;
});
if (files != null && files.length > 0) {
for (File f : files) {
try {
String newLyrics = FileUtil.read(f);
if (newLyrics != null && !newLyrics.trim().isEmpty()) {
if (AbsSynchronizedLyrics.isSynchronized(newLyrics)) {
return newLyrics;
}
lyrics = newLyrics;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
return lyrics;
}
public static void toggleFavorite(@NonNull final Context context, @NonNull final Song song) {
if (isFavorite(context, song)) {
PlaylistsUtil
.removeFromPlaylist(context, song, getFavoritesPlaylist(context).blockingFirst().id);
} else {
PlaylistsUtil
.addToPlaylist(context, song, getOrCreateFavoritesPlaylist(context).blockingFirst().id,
false);
}
}
public static boolean isFavoritePlaylist(@NonNull final Context context,
@NonNull final Playlist playlist) {
return playlist.name != null && playlist.name.equals(context.getString(R.string.favorites));
}
private static Observable<Playlist> getFavoritesPlaylist(@NonNull final Context context) {
return PlaylistLoader.getPlaylist(context, context.getString(R.string.favorites));
}
private static Observable<Playlist> getOrCreateFavoritesPlaylist(@NonNull final Context context) {
return PlaylistLoader.getPlaylist(context,
PlaylistsUtil.createPlaylist(context, context.getString(R.string.favorites)));
}
public static boolean isFavorite(@NonNull final Context context, @NonNull final Song song) {
/*return Observable.create(e -> getFavoritesPlaylist(context).subscribe(playlist1 -> {
boolean isBoolean = PlaylistsUtil.doPlaylistContains(context, playlist1.id, song.id);
e.onNext(isBoolean);
e.onComplete();
}));*/
//getFavoritesPlaylist(context).blockingFirst().id.subscribe(MusicUtil::setPlaylist);
//return PlaylistsUtil.doPlaylistContains(context, getFavoritesPlaylist(context).blockingFirst().id, song.id);
return PlaylistsUtil
.doPlaylistContains(context, getFavoritesPlaylist(context).blockingFirst().id, song.id);
}
public static boolean isArtistNameUnknown(@Nullable String artistName) {
if (TextUtils.isEmpty(artistName)) {
return false;
//getFavoritesPlaylist(context).blockingFirst().id.subscribe(MusicUtil::setPlaylist);
//return PlaylistsUtil.doPlaylistContains(context, getFavoritesPlaylist(context).blockingFirst().id, song.id);
return PlaylistsUtil
.doPlaylistContains(context, getFavoritesPlaylist(context).blockingFirst().id, song.id);
}
if (artistName.equals(Artist.UNKNOWN_ARTIST_DISPLAY_NAME)) {
return true;
}
artistName = artistName.trim().toLowerCase();
return artistName.equals("unknown") || artistName.equals("<unknown>");
}
@NonNull
public static String getSectionName(@Nullable String musicMediaTitle) {
if (TextUtils.isEmpty(musicMediaTitle)) {
return "";
public static boolean isArtistNameUnknown(@Nullable String artistName) {
if (TextUtils.isEmpty(artistName)) {
return false;
}
if (artistName.equals(Artist.UNKNOWN_ARTIST_DISPLAY_NAME)) {
return true;
}
artistName = artistName.trim().toLowerCase();
return artistName.equals("unknown") || artistName.equals("<unknown>");
}
musicMediaTitle = musicMediaTitle.trim().toLowerCase();
if (musicMediaTitle.startsWith("the ")) {
musicMediaTitle = musicMediaTitle.substring(4);
} else if (musicMediaTitle.startsWith("a ")) {
musicMediaTitle = musicMediaTitle.substring(2);
@NonNull
public static String getSectionName(@Nullable String musicMediaTitle) {
if (TextUtils.isEmpty(musicMediaTitle)) {
return "";
}
musicMediaTitle = musicMediaTitle.trim().toLowerCase();
if (musicMediaTitle.startsWith("the ")) {
musicMediaTitle = musicMediaTitle.substring(4);
} else if (musicMediaTitle.startsWith("a ")) {
musicMediaTitle = musicMediaTitle.substring(2);
}
if (musicMediaTitle.isEmpty()) {
return "";
}
return String.valueOf(musicMediaTitle.charAt(0)).toUpperCase();
}
if (musicMediaTitle.isEmpty()) {
return "";
public static Playlist getPlaylist() {
return playlist;
}
return String.valueOf(musicMediaTitle.charAt(0)).toUpperCase();
}
public static Playlist getPlaylist() {
return playlist;
}
public static void setPlaylist(Playlist playlist) {
MusicUtil.playlist = playlist;
}
public static long getTotalDuration(@NonNull final Context context, @NonNull List<Song> songs) {
long duration = 0;
for (int i = 0; i < songs.size(); i++) {
duration += songs.get(i).duration;
public static void setPlaylist(Playlist playlist) {
MusicUtil.playlist = playlist;
}
return duration;
}
@NonNull
public static String getYearString(int year) {
return year > 0 ? String.valueOf(year) : "-";
}
public static long getTotalDuration(@NonNull final Context context, @NonNull List<Song> songs) {
long duration = 0;
for (int i = 0; i < songs.size(); i++) {
duration += songs.get(i).duration;
}
return duration;
}
@NonNull
public static String getYearString(int year) {
return year > 0 ? String.valueOf(year) : "-";
}
}

View file

@ -25,7 +25,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
@ -34,7 +33,6 @@ import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import java.lang.reflect.Method;
import java.net.InetAddress;

View file

@ -5,64 +5,64 @@ package code.name.monkey.retromusic.util;
*/
public class TempUtils {
// Enums
public static final int TEMPO_STROLL = 0;
public static final int TEMPO_WALK = 1;
public static final int TEMPO_LIGHT_JOG = 2;
public static final int TEMPO_JOG = 3;
public static final int TEMPO_RUN = 4;
public static final int TEMPO_SPRINT = 5;
public static final int TEMPO_UNKNOWN = 6;
// Enums
public static final int TEMPO_STROLL = 0;
public static final int TEMPO_WALK = 1;
public static final int TEMPO_LIGHT_JOG = 2;
public static final int TEMPO_JOG = 3;
public static final int TEMPO_RUN = 4;
public static final int TEMPO_SPRINT = 5;
public static final int TEMPO_UNKNOWN = 6;
// take BPM as an int
public static int getTempoFromBPM(int bpm) {
// take BPM as an int
public static int getTempoFromBPM(int bpm) {
// STROLL less than 60
if (bpm < 60) {
return TEMPO_STROLL;
// STROLL less than 60
if (bpm < 60) {
return TEMPO_STROLL;
}
// WALK between 60 and 70, or between 120 and 140
else if (bpm < 70 || bpm >= 120 && bpm < 140) {
return TEMPO_WALK;
}
// LIGHT_JOG between 70 and 80, or between 140 and 160
else if (bpm < 80 || bpm >= 140 && bpm < 160) {
return TEMPO_LIGHT_JOG;
}
// JOG between 80 and 90, or between 160 and 180
else if (bpm < 90 || bpm >= 160 && bpm < 180) {
return TEMPO_JOG;
}
// RUN between 90 and 100, or between 180 and 200
else if (bpm < 100 || bpm >= 180 && bpm < 200) {
return TEMPO_RUN;
}
// SPRINT between 100 and 120
else if (bpm < 120) {
return TEMPO_SPRINT;
}
// UNKNOWN
else {
return TEMPO_UNKNOWN;
}
}
// WALK between 60 and 70, or between 120 and 140
else if (bpm < 70 || bpm >= 120 && bpm < 140) {
return TEMPO_WALK;
}
// take BPM as a string
public static int getTempoFromBPM(String bpm) {
// cast to an int from string
try {
// convert the string to an int
return getTempoFromBPM(Integer.parseInt(bpm.trim()));
} catch (NumberFormatException nfe) {
// LIGHT_JOG between 70 and 80, or between 140 and 160
else if (bpm < 80 || bpm >= 140 && bpm < 160) {
return TEMPO_LIGHT_JOG;
//
return TEMPO_UNKNOWN;
}
}
// JOG between 80 and 90, or between 160 and 180
else if (bpm < 90 || bpm >= 160 && bpm < 180) {
return TEMPO_JOG;
}
// RUN between 90 and 100, or between 180 and 200
else if (bpm < 100 || bpm >= 180 && bpm < 200) {
return TEMPO_RUN;
}
// SPRINT between 100 and 120
else if (bpm < 120) {
return TEMPO_SPRINT;
}
// UNKNOWN
else {
return TEMPO_UNKNOWN;
}
}
// take BPM as a string
public static int getTempoFromBPM(String bpm) {
// cast to an int from string
try {
// convert the string to an int
return getTempoFromBPM(Integer.parseInt(bpm.trim()));
} catch (NumberFormatException nfe) {
//
return TEMPO_UNKNOWN;
}
}
}

View file

@ -7,52 +7,54 @@ import android.support.v4.view.ViewCompat;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import code.name.monkey.appthemehelper.util.ColorUtil;
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
public class ViewUtil {
public final static int RETRO_MUSIC_ANIM_TIME = 1000;
public final static int RETRO_MUSIC_ANIM_TIME = 1000;
public static void setStatusBarHeight(final Context context, View statusBar) {
ViewGroup.LayoutParams lp = statusBar.getLayoutParams();
lp.height = getStatusBarHeight(context);
statusBar.requestLayout();
}
public static int getStatusBarHeight(final Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
public static void setStatusBarHeight(final Context context, View statusBar) {
ViewGroup.LayoutParams lp = statusBar.getLayoutParams();
lp.height = getStatusBarHeight(context);
statusBar.requestLayout();
}
return result;
}
public static boolean hitTest(View v, int x, int y) {
final int tx = (int) (ViewCompat.getTranslationX(v) + 0.5f);
final int ty = (int) (ViewCompat.getTranslationY(v) + 0.5f);
final int left = v.getLeft() + tx;
final int right = v.getRight() + tx;
final int top = v.getTop() + ty;
final int bottom = v.getBottom() + ty;
public static int getStatusBarHeight(final Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
return (x >= left) && (x <= right) && (y >= top) && (y <= bottom);
}
public static boolean hitTest(View v, int x, int y) {
final int tx = (int) (ViewCompat.getTranslationX(v) + 0.5f);
final int ty = (int) (ViewCompat.getTranslationY(v) + 0.5f);
final int left = v.getLeft() + tx;
final int right = v.getRight() + tx;
final int top = v.getTop() + ty;
final int bottom = v.getBottom() + ty;
public static void setUpFastScrollRecyclerViewColor(Context context,
FastScrollRecyclerView recyclerView, int accentColor) {
recyclerView.setPopupBgColor(accentColor);
recyclerView.setPopupTextColor(
MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(accentColor)));
recyclerView.setThumbColor(accentColor);
recyclerView.setTrackColor(Color.TRANSPARENT);
//recyclerView.setTrackColor(ColorUtil.withAlpha(ATHUtil.resolveColor(context, R.attr.colorControlNormal), 0.12f));
}
return (x >= left) && (x <= right) && (y >= top) && (y <= bottom);
}
public static float convertDpToPixel(float dp, Resources resources) {
DisplayMetrics metrics = resources.getDisplayMetrics();
return dp * metrics.density;
}
public static void setUpFastScrollRecyclerViewColor(Context context,
FastScrollRecyclerView recyclerView, int accentColor) {
recyclerView.setPopupBgColor(accentColor);
recyclerView.setPopupTextColor(
MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(accentColor)));
recyclerView.setThumbColor(accentColor);
recyclerView.setTrackColor(Color.TRANSPARENT);
//recyclerView.setTrackColor(ColorUtil.withAlpha(ATHUtil.resolveColor(context, R.attr.colorControlNormal), 0.12f));
}
public static float convertDpToPixel(float dp, Resources resources) {
DisplayMetrics metrics = resources.getDisplayMetrics();
return dp * metrics.density;
}
}

View file

@ -32,62 +32,62 @@ import android.graphics.drawable.Drawable;
*/
public class ImageGradientColorizer {
public Bitmap colorize(Drawable drawable, int backgroundColor, boolean isRtl) {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
int size = Math.min(width, height);
int widthInset = (width - size) / 2;
int heightInset = (height - size) / 2;
drawable = drawable.mutate();
drawable.setBounds(-widthInset, -heightInset, width - widthInset, height - heightInset);
Bitmap newBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
// Values to calculate the luminance of a color
float lr = 0.2126f;
float lg = 0.7152f;
float lb = 0.0722f;
// Extract the red, green, blue components of the color extraction color in
// float and int form
int tri = Color.red(backgroundColor);
int tgi = Color.green(backgroundColor);
int tbi = Color.blue(backgroundColor);
float tr = tri / 255f;
float tg = tgi / 255f;
float tb = tbi / 255f;
// Calculate the luminance of the color extraction color
float cLum = (tr * lr + tg * lg + tb * lb) * 255;
ColorMatrix m = new ColorMatrix(new float[]{
lr, lg, lb, 0, tri - cLum,
lr, lg, lb, 0, tgi - cLum,
lr, lg, lb, 0, tbi - cLum,
0, 0, 0, 1, 0,
});
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
LinearGradient linearGradient = new LinearGradient(0, 0, size, 0,
new int[]{0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
new float[]{0.0f, 0.4f, 1.0f}, Shader.TileMode.CLAMP);
paint.setShader(linearGradient);
Bitmap fadeIn = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas fadeInCanvas = new Canvas(fadeIn);
drawable.clearColorFilter();
drawable.draw(fadeInCanvas);
if (isRtl) {
// Let's flip the gradient
fadeInCanvas.translate(size, 0);
fadeInCanvas.scale(-1, 1);
public Bitmap colorize(Drawable drawable, int backgroundColor, boolean isRtl) {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
int size = Math.min(width, height);
int widthInset = (width - size) / 2;
int heightInset = (height - size) / 2;
drawable = drawable.mutate();
drawable.setBounds(-widthInset, -heightInset, width - widthInset, height - heightInset);
Bitmap newBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
// Values to calculate the luminance of a color
float lr = 0.2126f;
float lg = 0.7152f;
float lb = 0.0722f;
// Extract the red, green, blue components of the color extraction color in
// float and int form
int tri = Color.red(backgroundColor);
int tgi = Color.green(backgroundColor);
int tbi = Color.blue(backgroundColor);
float tr = tri / 255f;
float tg = tgi / 255f;
float tb = tbi / 255f;
// Calculate the luminance of the color extraction color
float cLum = (tr * lr + tg * lg + tb * lb) * 255;
ColorMatrix m = new ColorMatrix(new float[]{
lr, lg, lb, 0, tri - cLum,
lr, lg, lb, 0, tgi - cLum,
lr, lg, lb, 0, tbi - cLum,
0, 0, 0, 1, 0,
});
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
LinearGradient linearGradient = new LinearGradient(0, 0, size, 0,
new int[]{0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
new float[]{0.0f, 0.4f, 1.0f}, Shader.TileMode.CLAMP);
paint.setShader(linearGradient);
Bitmap fadeIn = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas fadeInCanvas = new Canvas(fadeIn);
drawable.clearColorFilter();
drawable.draw(fadeInCanvas);
if (isRtl) {
// Let's flip the gradient
fadeInCanvas.translate(size, 0);
fadeInCanvas.scale(-1, 1);
}
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
fadeInCanvas.drawPaint(paint);
Paint coloredPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
coloredPaint.setColorFilter(new ColorMatrixColorFilter(m));
coloredPaint.setAlpha((int) (0.5f * 255));
canvas.drawBitmap(fadeIn, 0, 0, coloredPaint);
linearGradient = new LinearGradient(0, 0, size, 0,
new int[]{0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
new float[]{0.0f, 0.6f, 1.0f}, Shader.TileMode.CLAMP);
paint.setShader(linearGradient);
fadeInCanvas.drawPaint(paint);
canvas.drawBitmap(fadeIn, 0, 0, null);
return newBitmap;
}
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
fadeInCanvas.drawPaint(paint);
Paint coloredPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
coloredPaint.setColorFilter(new ColorMatrixColorFilter(m));
coloredPaint.setAlpha((int) (0.5f * 255));
canvas.drawBitmap(fadeIn, 0, 0, coloredPaint);
linearGradient = new LinearGradient(0, 0, size, 0,
new int[]{0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
new float[]{0.0f, 0.6f, 1.0f}, Shader.TileMode.CLAMP);
paint.setShader(linearGradient);
fadeInCanvas.drawPaint(paint);
canvas.drawBitmap(fadeIn, 0, 0, null);
return newBitmap;
}
}

View file

@ -8,12 +8,11 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.VisibleForTesting;
import android.support.v7.graphics.Palette;
import android.util.LayoutDirection;
import code.name.monkey.appthemehelper.util.ColorUtil;
import java.util.List;
import code.name.monkey.appthemehelper.util.ColorUtil;
/**
* @author Hemanth S (h4h13).
*/
@ -46,13 +45,13 @@ public class MediaNotificationProcessor {
private static final int RESIZE_BITMAP_AREA = 150 * 150;
private final ImageGradientColorizer mColorizer;
private final Context mContext;
private float[] mFilteredBackgroundHsl = null;
private Palette.Filter mBlackWhiteFilter = (rgb, hsl) -> !isWhiteOrBlack(hsl);
/**
* The context of the notification. This is the app context of the package posting the
* notification.
*/
private final Context mPackageContext;
private float[] mFilteredBackgroundHsl = null;
private Palette.Filter mBlackWhiteFilter = (rgb, hsl) -> !isWhiteOrBlack(hsl);
private boolean mIsLowPriority;
private onColorThing onColorThing;

View file

@ -1,7 +1,6 @@
package code.name.monkey.retromusic.util.color;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
@ -9,15 +8,13 @@ import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.TextAppearanceSpan;
import android.util.Log;
import android.util.Pair;
import code.name.monkey.retromusic.util.ImageUtil;
import java.util.Arrays;
import java.util.WeakHashMap;
import code.name.monkey.retromusic.util.ImageUtil;
/**
* Helper class to process legacy (Holo) notifications to make them look like quantum
* notifications.
@ -26,109 +23,109 @@ import java.util.WeakHashMap;
*/
public class NotificationColorUtil {
private static final String TAG = "NotificationColorUtil";
private static final Object sLock = new Object();
private static NotificationColorUtil sInstance;
private static final String TAG = "NotificationColorUtil";
private static final Object sLock = new Object();
private static NotificationColorUtil sInstance;
private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
public static NotificationColorUtil getInstance() {
synchronized (sLock) {
if (sInstance == null) {
sInstance = new NotificationColorUtil();
}
return sInstance;
}
}
/**
* Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect gray".
*
* @param bitmap The bitmap to test.
* @return Whether the bitmap is grayscale.
*/
public boolean isGrayscale(Bitmap bitmap) {
synchronized (sLock) {
Pair<Boolean, Integer> cached = mGrayscaleBitmapCache.get(bitmap);
if (cached != null) {
if (cached.second == bitmap.getGenerationId()) {
return cached.first;
public static NotificationColorUtil getInstance() {
synchronized (sLock) {
if (sInstance == null) {
sInstance = new NotificationColorUtil();
}
return sInstance;
}
}
}
boolean result;
int generationId;
result = ImageUtil.isGrayscale(bitmap);
// generationId and the check whether the Bitmap is grayscale can't be read atomically
// here. However, since the thread is in the process of posting the notification, we can
// assume that it doesn't modify the bitmap while we are checking the pixels.
generationId = bitmap.getGenerationId();
/**
* Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect gray".
*
* @param bitmap The bitmap to test.
* @return Whether the bitmap is grayscale.
*/
public boolean isGrayscale(Bitmap bitmap) {
synchronized (sLock) {
Pair<Boolean, Integer> cached = mGrayscaleBitmapCache.get(bitmap);
if (cached != null) {
if (cached.second == bitmap.getGenerationId()) {
return cached.first;
}
}
}
boolean result;
int generationId;
synchronized (sLock) {
mGrayscaleBitmapCache.put(bitmap, Pair.create(result, generationId));
result = ImageUtil.isGrayscale(bitmap);
// generationId and the check whether the Bitmap is grayscale can't be read atomically
// here. However, since the thread is in the process of posting the notification, we can
// assume that it doesn't modify the bitmap while we are checking the pixels.
generationId = bitmap.getGenerationId();
synchronized (sLock) {
mGrayscaleBitmapCache.put(bitmap, Pair.create(result, generationId));
}
return result;
}
return result;
}
/**
* Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect gray".
*
* @param d The drawable to test.
* @return Whether the drawable is grayscale.
*/
public boolean isGrayscale(Drawable d) {
if (d == null) {
return false;
} else if (d instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) d;
return bd.getBitmap() != null && isGrayscale(bd.getBitmap());
} else if (d instanceof AnimationDrawable) {
AnimationDrawable ad = (AnimationDrawable) d;
int count = ad.getNumberOfFrames();
return count > 0 && isGrayscale(ad.getFrame(0));
} else if (d instanceof VectorDrawable) {
// We just assume you're doing the right thing if using vectors
return true;
} else {
return false;
/**
* Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect gray".
*
* @param d The drawable to test.
* @return Whether the drawable is grayscale.
*/
public boolean isGrayscale(Drawable d) {
if (d == null) {
return false;
} else if (d instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) d;
return bd.getBitmap() != null && isGrayscale(bd.getBitmap());
} else if (d instanceof AnimationDrawable) {
AnimationDrawable ad = (AnimationDrawable) d;
int count = ad.getNumberOfFrames();
return count > 0 && isGrayscale(ad.getFrame(0));
} else if (d instanceof VectorDrawable) {
// We just assume you're doing the right thing if using vectors
return true;
} else {
return false;
}
}
}
/**
* Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close to a
* perfect gray".
*
* @param context The context to load the drawable from.
* @return Whether the drawable is grayscale.
*/
public boolean isGrayscale(Context context, int drawableResId) {
if (drawableResId != 0) {
try {
return isGrayscale(context.getDrawable(drawableResId));
} catch (Resources.NotFoundException ex) {
Log.e(TAG, "Drawable not found: " + drawableResId);
return false;
}
} else {
return false;
/**
* Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close to a
* perfect gray".
*
* @param context The context to load the drawable from.
* @return Whether the drawable is grayscale.
*/
public boolean isGrayscale(Context context, int drawableResId) {
if (drawableResId != 0) {
try {
return isGrayscale(context.getDrawable(drawableResId));
} catch (Resources.NotFoundException ex) {
Log.e(TAG, "Drawable not found: " + drawableResId);
return false;
}
} else {
return false;
}
}
}
/**
* Inverts all the grayscale colors set by {@link android.text.style.TextAppearanceSpan}s on the
* text.
*
* @param charSequence The text to process.
* @return The color inverted text.
*/
/**
* Inverts all the grayscale colors set by {@link android.text.style.TextAppearanceSpan}s on the
* text.
*
* @param charSequence The text to process.
* @return The color inverted text.
*/
private int processColor(int color) {
return Color.argb(Color.alpha(color),
255 - Color.red(color),
255 - Color.green(color),
255 - Color.blue(color));
}
private int processColor(int color) {
return Color.argb(Color.alpha(color),
255 - Color.red(color),
255 - Color.green(color),
255 - Color.blue(color));
}
}

View file

@ -12,7 +12,7 @@ import io.reactivex.schedulers.Schedulers;
public class SchedulerProvider implements BaseSchedulerProvider {
@NonNull
private static SchedulerProvider INSTANCE ;
private static SchedulerProvider INSTANCE;
public SchedulerProvider() {
}