diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt index 4bac8e84..017bbf4e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt @@ -12,10 +12,10 @@ import androidx.appcompat.widget.Toolbar import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.helper.MusicPlayerRemote -import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment +import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.ViewUtil import code.name.monkey.retromusic.views.DrawableGradient @@ -100,16 +100,6 @@ class PlayerFragment : AbsPlayerFragment() { super.onViewCreated(view, savedInstanceState) setUpSubFragments() setUpPlayerToolbar() - - - //val display = activity?.windowManager?.defaultDisplay - //val outMetrics = DisplayMetrics() - //display?.getMetrics(outMetrics) - - //val density = resources.displayMetrics.density - //val dpWidth = outMetrics.widthPixels / density - - //playerAlbumCoverContainer?.layoutParams?.height = RetroUtil.convertDpToPixel((dpWidth - getCutOff()), context!!).toInt() } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java index 5078b3a8..42553bcd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java @@ -77,7 +77,6 @@ import code.name.monkey.retromusic.service.notification.PlayingNotificationImpl2 import code.name.monkey.retromusic.service.notification.PlayingNotificationOreo; import code.name.monkey.retromusic.service.playback.Playback; import code.name.monkey.retromusic.util.MusicUtil; -import code.name.monkey.retromusic.util.PackageValidator; import code.name.monkey.retromusic.util.PreferenceUtil; import code.name.monkey.retromusic.util.RetroUtil; @@ -275,7 +274,6 @@ public class MusicService extends Service implements } } }; - private PackageValidator mPackageValidator; private static String getTrackUri(@NonNull Song song) { return MusicUtil.getSongFileUri(song.getId()).toString(); @@ -341,9 +339,6 @@ public class MusicService extends Service implements restoreState(); - mPackageValidator = new PackageValidator(this, R.xml.allowed_media_browser_callers); - - sendBroadcast(new Intent("code.name.monkey.retromusic.RETRO_MUSIC_SERVICE_CREATED")); registerHeadsetEvents(); diff --git a/app/src/main/java/code/name/monkey/retromusic/util/AttrsUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/AttrsUtil.kt deleted file mode 100644 index 93da81ea..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/AttrsUtil.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.util - -import android.content.Context -import androidx.annotation.AttrRes - -object AttrsUtil { - @JvmOverloads - fun resolveColor(context: Context, @AttrRes attr: Int, fallback: Int = 0): Int { - val a = context.theme.obtainStyledAttributes(intArrayOf(attr)) - try { - return a.getColor(0, fallback) - } finally { - a.recycle() - } - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/DensityUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/DensityUtil.java index b0bf619b..6c5c650c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/DensityUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/DensityUtil.java @@ -16,9 +16,7 @@ package code.name.monkey.retromusic.util; import android.app.Activity; import android.content.Context; -import android.content.res.Resources; import android.util.DisplayMetrics; -import android.util.TypedValue; import androidx.annotation.NonNull; @@ -33,38 +31,9 @@ public class DensityUtil { return displayMetrics.heightPixels; } - public static int getScreenWidth(@NonNull Context context) { - DisplayMetrics displayMetrics = new DisplayMetrics(); - ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); - return displayMetrics.widthPixels; - } - public static int dip2px(@NonNull Context context, float dpVale) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpVale * scale + 0.5f); } - public static int getStatusBarHeight(@NonNull Context context) { - Resources resources = context.getResources(); - int resourcesId = resources.getIdentifier("status_bar_height", "dimen", "android"); - int height = resources.getDimensionPixelSize(resourcesId); - return height; - } - - /** - * Converts sp to px - * - * @param context Context - * @param sp the value in sp - * @return int - */ - public static int dip2sp(@NonNull Context context, float sp) { - return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics()); - } - - public static int px2dip(@NonNull Context context, float pxValue) { - final float scale = context.getResources().getDisplayMetrics().density; - return (int) (pxValue / scale + 0.5f); - } - } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java index 5c9337d3..eca52b84 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java @@ -47,7 +47,6 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote; import code.name.monkey.retromusic.loaders.PlaylistLoader; import code.name.monkey.retromusic.loaders.SongLoader; import code.name.monkey.retromusic.model.Artist; -import code.name.monkey.retromusic.model.Genre; import code.name.monkey.retromusic.model.Playlist; import code.name.monkey.retromusic.model.Song; import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics; @@ -72,17 +71,6 @@ public class MusicUtil { @NonNull public static Intent createShareSongFileIntent(@NonNull final Song song, @NonNull Context context) { - /*Uri file = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", new File(song.getData())); - try { - return new Intent().setAction(Intent.ACTION_SEND).putExtra(Intent.EXTRA_STREAM, file) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - .setType("audio/*"); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - Toast.makeText(context, "Could not share this file, I'm aware of the issue.", Toast.LENGTH_SHORT).show(); - return new Intent(); - }*/ - try { return new Intent() .setAction(Intent.ACTION_SEND) @@ -123,36 +111,6 @@ public class MusicUtil { 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 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).getDuration(); - } - - return songCount + " " + songString + " • " + MusicUtil.getReadableDurationString(duration); - }*/ - - @NonNull - public static String getGenreInfoString(@NonNull final Context context, @NonNull final Genre genre) { - int songCount = genre.getSongCount(); - return MusicUtil.getSongCountString(context, songCount); - } - @NonNull public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List songs) { final long duration = getTotalDuration(context, songs); @@ -185,31 +143,6 @@ public class MusicUtil { return string1 + " • " + string2; } - /** - * Build a concatenated string from the provided arguments - * The intended purpose is to show extra annotations - * to a music library item. - * Ex: for a given album --> buildInfoString(album.artist, album.songCount) - */ - @NonNull - public static String buildInfoString(@Nullable final String string1, @Nullable final String string2, @NonNull final String string3) { - // Skip empty strings - if (TextUtils.isEmpty(string1)) { - //noinspection ConstantConditions - return TextUtils.isEmpty(string2) ? "" : string2; - } - if (TextUtils.isEmpty(string2)) { - //noinspection ConstantConditions - return TextUtils.isEmpty(string1) ? "" : string1; - } - if (TextUtils.isEmpty(string3)) { - //noinspection ConstantConditions - return TextUtils.isEmpty(string1) ? "" : string3; - } - - return string1 + " • " + string2 + " • " + string3; - } - public static String getReadableDurationString(long songDurationMillis) { long minutes = (songDurationMillis / 1000) / 60; long seconds = (songDurationMillis / 1000) % 60; diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt b/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt deleted file mode 100644 index d75bd28b..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.util - - -import android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE -import android.Manifest.permission.MEDIA_CONTENT_CONTROL -import android.annotation.SuppressLint -import android.content.Context -import android.content.pm.PackageInfo -import android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED -import android.content.pm.PackageManager -import android.content.res.XmlResourceParser -import android.os.Process -import android.support.v4.media.session.MediaSessionCompat -import android.util.Base64 -import android.util.Log -import androidx.annotation.XmlRes -import androidx.media.MediaBrowserServiceCompat -import code.name.monkey.retromusic.BuildConfig -import org.xmlpull.v1.XmlPullParserException -import java.io.IOException -import java.security.MessageDigest -import java.security.NoSuchAlgorithmException - -/** - * Validates that the calling package is authorized to browse a [MediaBrowserServiceCompat]. - * - * The list of allowed signing certificates and their corresponding package names is defined in - * res/xml/allowed_media_browser_callers.xml. - * - * If you want to add a new caller to allowed_media_browser_callers.xml and you don't know - * its signature, this class will print to logcat (INFO level) a message with the proper - * xml tags to add to allow the caller. - * - * For more information, see res/xml/allowed_media_browser_callers.xml. - */ -class PackageValidator( - context: Context, - @XmlRes xmlResId: Int -) { - private val context: Context - private val packageManager: PackageManager - - private val certificateWhitelist: Map - private val platformSignature: String - - private val callerChecked = mutableMapOf>() - - init { - val parser = context.resources.getXml(xmlResId) - this.context = context.applicationContext - this.packageManager = this.context.packageManager - - certificateWhitelist = buildCertificateWhitelist(parser) - platformSignature = getSystemSignature() - } - - /** - * Checks whether the caller attempting to connect to a [MediaBrowserServiceCompat] is known. - * See [MusicService.onGetRoot] for where this is utilized. - * - * @param callingPackage The package name of the caller. - * @param callingUid The user id of the caller. - * @return `true` if the caller is known, `false` otherwise. - */ - fun isKnownCaller(callingPackage: String, callingUid: Int): Boolean { - // If the caller has already been checked, return the previous result here. - val (checkedUid, checkResult) = callerChecked[callingPackage] ?: Pair(0, false) - if (checkedUid == callingUid) { - return checkResult - } - - /** - * Because some of these checks can be slow, we save the results in [callerChecked] after - * this code is run. - * - * In particular, there's little reason to recompute the calling package's certificate - * signature (SHA-256) each call. - * - * This is safe to do as we know the UID matches the package's UID (from the check above), - * and app UIDs are set at install time. Additionally, a package name + UID is guaranteed to - * be constant until a reboot. (After a reboot then a previously assigned UID could be - * reassigned.) - */ - - // Build the caller info for the rest of the checks here. - val callerPackageInfo = buildCallerInfo(callingPackage) - ?: throw IllegalStateException("Caller wasn't found in the system?") - - // Verify that things aren't ... broken. (This test should always pass.) - if (callerPackageInfo.uid != callingUid) { - throw IllegalStateException("Caller's package UID doesn't match caller's actual UID?") - } - - val callerSignature = callerPackageInfo.signature - val isPackageInWhitelist = certificateWhitelist[callingPackage]?.signatures?.first { - it.signature == callerSignature - } != null - - val isCallerKnown = when { - // If it's our own app making the call, allow it. - callingUid == Process.myUid() -> true - // If it's one of the apps on the whitelist, allow it. - isPackageInWhitelist -> true - // If the system is making the call, allow it. - callingUid == Process.SYSTEM_UID -> true - // If the app was signed by the same certificate as the platform itself, also allow it. - callerSignature == platformSignature -> true - /** - * [MEDIA_CONTENT_CONTROL] permission is only available to system applications, and - * while it isn't required to allow these apps to connect to a - * [MediaBrowserServiceCompat], allowing this ensures optimal compatability with apps - * such as Android TV and the Google Assistant. - */ - callerPackageInfo.permissions.contains(MEDIA_CONTENT_CONTROL) -> true - /** - * This last permission can be specifically granted to apps, and, in addition to - * allowing them to retrieve notifications, it also allows them to connect to an - * active [MediaSessionCompat]. - * As with the above, it's not required to allow apps holding this permission to - * connect to your [MediaBrowserServiceCompat], but it does allow easy comparability - * with apps such as Wear OS. - */ - callerPackageInfo.permissions.contains(BIND_NOTIFICATION_LISTENER_SERVICE) -> true - // If none of the pervious checks succeeded, then the caller is unrecognized. - else -> false - } - - if (!isCallerKnown) { - logUnknownCaller(callerPackageInfo) - } - - // Save our work for next time. - callerChecked[callingPackage] = Pair(callingUid, isCallerKnown) - return isCallerKnown - } - - /** - * Logs an info level message with details of how to add a caller to the allowed callers list - * when the app is debuggable. - */ - private fun logUnknownCaller(callerPackageInfo: CallerPackageInfo) { - if (BuildConfig.DEBUG && callerPackageInfo.signature != null) { - Log.i(TAG, "PackageValidator call" + callerPackageInfo.name + callerPackageInfo.packageName + callerPackageInfo.signature) - } - } - - /** - * Builds a [CallerPackageInfo] for a given package that can be used for all the - * various checks that are performed before allowing an app to connect to a - * [MediaBrowserServiceCompat]. - */ - private fun buildCallerInfo(callingPackage: String): CallerPackageInfo? { - val packageInfo = getPackageInfo(callingPackage) ?: return null - - val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString() - val uid = packageInfo.applicationInfo.uid - val signature = getSignature(packageInfo) - - val requestedPermissions = packageInfo.requestedPermissions - val permissionFlags = packageInfo.requestedPermissionsFlags - val activePermissions = mutableSetOf() - requestedPermissions?.forEachIndexed { index, permission -> - if (permissionFlags[index] and REQUESTED_PERMISSION_GRANTED != 0) { - activePermissions += permission - } - } - - return CallerPackageInfo(appName, callingPackage, uid, signature, activePermissions.toSet()) - } - - /** - * Looks up the [PackageInfo] for a package name. - * This requests both the signatures (for checking if an app is on the whitelist) and - * the app's permissions, which allow for more flexibility in the whitelist. - * - * @return [PackageInfo] for the package name or null if it's not found. - */ - @SuppressLint("PackageManagerGetSignatures") - private fun getPackageInfo(callingPackage: String): PackageInfo? = - packageManager.getPackageInfo(callingPackage, - PackageManager.GET_SIGNATURES or PackageManager.GET_PERMISSIONS) - - /** - * Gets the signature of a given package's [PackageInfo]. - * - * The "signature" is a SHA-256 hash of the public key of the signing certificate used by - * the app. - * - * If the app is not found, or if the app does not have exactly one signature, this method - * returns `null` as the signature. - */ - private fun getSignature(packageInfo: PackageInfo): String? { - // Security best practices dictate that an app should be signed with exactly one (1) - // signature. Because of this, if there are multiple signatures, reject it. - if (packageInfo.signatures == null || packageInfo.signatures.size != 1) { - return null - } else { - val certificate = packageInfo.signatures[0].toByteArray() - return getSignatureSha256(certificate) - } - } - - private fun buildCertificateWhitelist(parser: XmlResourceParser): Map { - - val certificateWhitelist = LinkedHashMap() - try { - var eventType = parser.next() - while (eventType != XmlResourceParser.END_DOCUMENT) { - if (eventType == XmlResourceParser.START_TAG) { - val callerInfo = when (parser.name) { - "signing_certificate" -> parseV1Tag(parser) - "signature" -> parseV2Tag(parser) - else -> null - } - - callerInfo?.let { info -> - val packageName = info.packageName - val existingCallerInfo = certificateWhitelist[packageName] - if (existingCallerInfo != null) { - existingCallerInfo.signatures += callerInfo.signatures - } else { - certificateWhitelist[packageName] = callerInfo - } - } - } - - eventType = parser.next() - } - } catch (xmlException: XmlPullParserException) { - Log.e(TAG, "Could not read allowed callers from XML.", xmlException) - } catch (ioException: IOException) { - Log.e(TAG, "Could not read allowed callers from XML.", ioException) - } - - return certificateWhitelist - } - - /** - * Parses a v1 format tag. See allowed_media_browser_callers.xml for more details. - */ - private fun parseV1Tag(parser: XmlResourceParser): KnownCallerInfo { - val name = parser.getAttributeValue(null, "name") - val packageName = parser.getAttributeValue(null, "package") - val isRelease = parser.getAttributeBooleanValue(null, "release", false) - val certificate = parser.nextText().replace(WHITESPACE_REGEX, "") - val signature = getSignatureSha256(certificate) - - val callerSignature = KnownSignature(signature, isRelease) - return KnownCallerInfo(name, packageName, mutableSetOf(callerSignature)) - } - - /** - * Parses a v2 format tag. See allowed_media_browser_callers.xml for more details. - */ - private fun parseV2Tag(parser: XmlResourceParser): KnownCallerInfo { - val name = parser.getAttributeValue(null, "name") - val packageName = parser.getAttributeValue(null, "package") - - val callerSignatures = mutableSetOf() - var eventType = parser.next() - while (eventType != XmlResourceParser.END_TAG) { - val isRelease = parser.getAttributeBooleanValue(null, "release", false) - val signature = parser.nextText().replace(WHITESPACE_REGEX, "").toLowerCase() - callerSignatures += KnownSignature(signature, isRelease) - - eventType = parser.next() - } - - return KnownCallerInfo(name, packageName, callerSignatures) - } - - /** - * Finds the Android platform signing key signature. This key is never null. - */ - private fun getSystemSignature(): String = - getPackageInfo(ANDROID_PLATFORM)?.let { platformInfo -> - getSignature(platformInfo) - } ?: throw IllegalStateException("Platform signature not found") - - /** - * Creates a SHA-256 signature given a Base64 encoded certificate. - */ - private fun getSignatureSha256(certificate: String): String { - return getSignatureSha256(Base64.decode(certificate, Base64.DEFAULT)) - } - - /** - * Creates a SHA-256 signature given a certificate byte array. - */ - private fun getSignatureSha256(certificate: ByteArray): String { - val md: MessageDigest - try { - md = MessageDigest.getInstance("SHA256") - } catch (noSuchAlgorithmException: NoSuchAlgorithmException) { - Log.e(TAG, "No such algorithm: $noSuchAlgorithmException") - throw RuntimeException("Could not find SHA256 hash algorithm", noSuchAlgorithmException) - } - md.update(certificate) - - // This code takes the byte array generated by `md.digest()` and joins each of the bytes - // to a string, applying the string format `%02x` on each digit before it's appended, with - // a colon (':') between each of the items. - // For example: input=[0,2,4,6,8,10,12], output="00:02:04:06:08:0a:0c" - return md.digest().joinToString(":") { String.format("%02x", it) } - } - - private data class KnownCallerInfo( - internal val name: String, - internal val packageName: String, - internal val signatures: MutableSet - ) - - private data class KnownSignature( - internal val signature: String, - internal val release: Boolean - ) - - /** - * Convenience class to hold all of the information about an app that's being checked - * to see if it's a known caller. - */ - private data class CallerPackageInfo( - internal val name: String, - internal val packageName: String, - internal val uid: Int, - internal val signature: String?, - internal val permissions: Set - ) -} - -private const val TAG = "PackageValidator" -private const val ANDROID_PLATFORM = "android" -private val WHITESPACE_REGEX = "\\s|\\n".toRegex() diff --git a/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java index 9efea8f5..601d1770 100755 --- a/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; -import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -31,9 +30,6 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.Build; -import android.os.ResultReceiver; -import android.provider.BaseColumns; -import android.provider.MediaStore; import android.util.DisplayMetrics; import android.view.Display; import android.view.View; @@ -45,16 +41,8 @@ import androidx.annotation.ColorInt; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.util.Collections; -import java.util.List; - -import code.name.monkey.appthemehelper.ThemeStore; import code.name.monkey.appthemehelper.util.TintHelper; import code.name.monkey.retromusic.App; @@ -88,40 +76,6 @@ public class RetroUtil { return config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; } - @TargetApi(19) - public static void setStatusBarTranslucent(@NonNull Window window) { - window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, - WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); - } - - public static boolean isMarshMellow() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; - } - - public static boolean isNougat() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; - } - - public static boolean isOreo() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; - } - - public static float getDistance(float x1, float y1, float x2, float y2) { - return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); - } - - public static float convertDpToPixel(float dp, @NonNull Context context) { - Resources resources = context.getResources(); - DisplayMetrics metrics = resources.getDisplayMetrics(); - return dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT); - } - - public static float convertPixelsToDp(float px, @NonNull Context context) { - Resources resources = context.getResources(); - DisplayMetrics metrics = resources.getDisplayMetrics(); - return px / ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT); - } - public static void openUrl(@NonNull Activity context, @NonNull String str) { Intent intent = new Intent("android.intent.action.VIEW"); intent.setData(Uri.parse(str)); @@ -154,20 +108,6 @@ public class RetroUtil { } } - public static void showIme(@NonNull View view) { - InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService - (Context.INPUT_METHOD_SERVICE); - // the public methods don't seem to work for me, so… reflection. - try { - Method showSoftInputUnchecked = InputMethodManager.class.getMethod( - "showSoftInputUnchecked", int.class, ResultReceiver.class); - showSoftInputUnchecked.setAccessible(true); - showSoftInputUnchecked.invoke(imm, 0, null); - } catch (Exception e) { - // ho hum - } - } - @Nullable public static Drawable getVectorDrawable(@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) { @@ -184,17 +124,6 @@ public class RetroUtil { getVectorDrawable(context.getResources(), id, context.getTheme()), color); } - public static Drawable getTintedDrawable(@NonNull Context context, @DrawableRes int id, - @ColorInt int color) { - return TintHelper.createTintedDrawable(ContextCompat.getDrawable(context, id), color); - } - - public static Drawable getTintedDrawable(@DrawableRes int id) { - return TintHelper - .createTintedDrawable(ContextCompat.getDrawable(App.Companion.getContext(), id), - ThemeStore.Companion.accentColor(App.Companion.getContext())); - } - @NonNull public static Bitmap createBitmap(@NonNull Drawable drawable, float sizeMultiplier) { Bitmap bitmap = Bitmap.createBitmap((int) (drawable.getIntrinsicWidth() * sizeMultiplier), @@ -227,64 +156,6 @@ public class RetroUtil { } } - public static String getIPAddress(boolean useIPv4) { - try { - List interfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); - for (NetworkInterface intf : interfaces) { - List addrs = Collections.list(intf.getInetAddresses()); - for (InetAddress addr : addrs) { - if (!addr.isLoopbackAddress()) { - String sAddr = addr.getHostAddress(); - //boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr); - boolean isIPv4 = sAddr.indexOf(':') < 0; - - if (useIPv4) { - if (isIPv4) - return sAddr; - } else { - if (!isIPv4) { - int delim = sAddr.indexOf('%'); // drop ip6 zone suffix - return delim < 0 ? sAddr.toUpperCase() : sAddr.substring(0, delim).toUpperCase(); - } - } - } - } - } - } catch (Exception ex) { - } - return ""; - } - - public static Uri getSongUri(Context context, long id) { - final String[] projection = new String[]{ - BaseColumns._ID, MediaStore.MediaColumns.DATA, MediaStore.Audio.AudioColumns.ALBUM_ID - }; - final StringBuilder selection = new StringBuilder(); - selection.append(BaseColumns._ID + " IN ("); - selection.append(id); - selection.append(")"); - final Cursor c = context.getContentResolver().query( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection.toString(), - null, null); - - if (c == null) { - return null; - } - c.moveToFirst(); - - - try { - - Uri uri = Uri.parse(c.getString(1)); - c.close(); - - return uri; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - public static int getStatusBarHeight() { int result = 0; int resourceId = App.Companion.getContext().getResources().getIdentifier("status_bar_height", "dimen", "android"); diff --git a/app/src/main/java/code/name/monkey/retromusic/util/SwipeAndDragHelper.java b/app/src/main/java/code/name/monkey/retromusic/util/SwipeAndDragHelper.java index 1e2c82ba..f8fa85da 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/SwipeAndDragHelper.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/SwipeAndDragHelper.java @@ -15,6 +15,8 @@ package code.name.monkey.retromusic.util; import android.graphics.Canvas; + +import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.ItemTouchHelper; @@ -22,7 +24,7 @@ public class SwipeAndDragHelper extends ItemTouchHelper.Callback { private ActionCompletionContract contract; - public SwipeAndDragHelper(ActionCompletionContract contract) { + public SwipeAndDragHelper(@NonNull ActionCompletionContract contract) { this.contract = contract; } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/ViewUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/ViewUtil.kt index b31a3884..65c03c5a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/ViewUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/ViewUtil.kt @@ -28,41 +28,18 @@ import android.view.View import android.view.animation.PathInterpolator import android.widget.ProgressBar import android.widget.SeekBar -import android.widget.TextView import androidx.annotation.ColorInt import androidx.core.view.ViewCompat import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.retromusic.R -import com.google.android.material.card.MaterialCardView -import com.google.android.material.shape.CornerFamily -import com.google.android.material.shape.MaterialShapeDrawable import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView object ViewUtil { const val RETRO_MUSIC_ANIM_TIME = 1000 - fun cardViewTopCorners(cardView: MaterialCardView) { - - val radius = PreferenceUtil.getInstance(cardView.context).dialogCorner - (cardView.background as? MaterialShapeDrawable).let { - it?.shapeAppearanceModel?.apply { - toBuilder() - .setTopLeftCorner(CornerFamily.CUT, 10f) - .build() - } - } - } - - fun createTextColorTransition(v: TextView, @ColorInt startColor: Int, @ColorInt endColor: Int): Animator { - return createColorAnimator(v, "textColor", startColor, endColor) - } - - fun createBackgroundColorTransition(v: View, @ColorInt startColor: Int, @ColorInt endColor: Int): Animator { - return createColorAnimator(v, "backgroundColor", startColor, endColor) - } fun setProgressDrawable(progressSlider: SeekBar, newColor: Int, thumbTint: Boolean = false) { @@ -103,21 +80,6 @@ object ViewUtil { return animator } - fun setStatusBarHeight(context: Context, statusBar: View) { - val lp = statusBar.layoutParams - lp.height = getStatusBarHeight(context) - statusBar.requestLayout() - } - - fun getStatusBarHeight(context: Context): Int { - var result = 0 - val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android") - if (resourceId > 0) { - result = context.resources.getDimensionPixelSize(resourceId) - } - return result - } - fun hitTest(v: View, x: Int, y: Int): Boolean { val tx = (ViewCompat.getTranslationX(v) + 0.5f).toInt() val ty = (ViewCompat.getTranslationY(v) + 0.5f).toInt() diff --git a/app/src/main/java/code/name/monkey/retromusic/util/color/ImageGradientColorizer.java b/app/src/main/java/code/name/monkey/retromusic/util/color/ImageGradientColorizer.java deleted file mode 100644 index 7963e563..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/color/ImageGradientColorizer.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ -package code.name.monkey.retromusic.util.color; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.Shader; -import android.graphics.drawable.Drawable; - -/** - * A utility class to colorize bitmaps with a color gradient and a special blending mode - */ -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); - } - 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; - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/color/MediaNotificationProcessor.java b/app/src/main/java/code/name/monkey/retromusic/util/color/MediaNotificationProcessor.java index 1e87ea02..16804d8a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/color/MediaNotificationProcessor.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/color/MediaNotificationProcessor.java @@ -20,6 +20,7 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; + import androidx.annotation.VisibleForTesting; import androidx.palette.graphics.Palette; @@ -57,7 +58,6 @@ public class MediaNotificationProcessor { private static final float BLACK_MAX_LIGHTNESS = 0.08f; private static final float WHITE_MIN_LIGHTNESS = 0.90f; private static final int RESIZE_BITMAP_AREA = 150 * 150; - private final ImageGradientColorizer mColorizer; private final Context mContext; /** * The context of the notification. This is the app context of the package posting the @@ -70,16 +70,14 @@ public class MediaNotificationProcessor { private onColorThing onColorThing; public MediaNotificationProcessor(Context context, Context packageContext, onColorThing thing) { - this(context, packageContext, new ImageGradientColorizer()); + this(context, packageContext); onColorThing = thing; } @VisibleForTesting - MediaNotificationProcessor(Context context, Context packageContext, - ImageGradientColorizer colorizer) { + MediaNotificationProcessor(Context context, Context packageContext) { mContext = context; mPackageContext = packageContext; - mColorizer = colorizer; } /** @@ -292,228 +290,4 @@ public class MediaNotificationProcessor { public interface onColorThing { void bothColor(int i, int i2); } - - /** - * The fraction below which we select the vibrant instead of the light/dark vibrant color - *//* - private static final float POPULATION_FRACTION_FOR_MORE_VIBRANT = 1.0f; - *//** - * Minimum saturation that a muted color must have if there exists if deciding between two colors - *//* - private static final float MIN_SATURATION_WHEN_DECIDING = 0.19f; - *//** - * Minimum fraction that any color must have to be picked up as a text color - *//* - private static final double MINIMUM_IMAGE_FRACTION = 0.002; - *//** - * The population fraction to select the dominant color as the text color over a the colored - * ones. - *//* - private static final float POPULATION_FRACTION_FOR_DOMINANT = 0.01f; - *//** - * The population fraction to select a white or black color as the background over a color. - *//* - private static final float POPULATION_FRACTION_FOR_WHITE_OR_BLACK = 2.5f; - - private static final float BLACK_MAX_LIGHTNESS = 0.08f; - private static final float WHITE_MIN_LIGHTNESS = 0.90f; - private static final int RESIZE_BITMAP_AREA = 150 * 150; - private static float[] mFilteredBackgroundHsl = null; - private final ImageGradientColorizer mColorizer; - private final Context mContext; - *//** - * The context of the notification. This is the app context of the package posting the - * notification. - *//* - private final Context mPackageContext; - private static Palette.Filter mBlackWhiteFilter = (rgb, hsl) -> !isWhiteOrBlack(hsl); - private boolean mIsLowPriority; - - public MediaNotificationProcessor(Context context, Context packageContext) { - this(context, packageContext, new ImageGradientColorizer()); - } - - @VisibleForTesting - MediaNotificationProcessor(Context context, Context packageContext, - ImageGradientColorizer colorizer) { - mContext = context; - mPackageContext = packageContext; - mColorizer = colorizer; - } - - @Nullable - public static Palette.Builder generatePalette(Bitmap bitmap) { - return bitmap == null ? null : Palette.from(bitmap).clearFilters().resizeBitmapArea(RESIZE_BITMAP_AREA); - } - - public static int getBackgroundColor(Palette.Builder builder) { - return findBackgroundColorAndFilter(builder.generate()); - } - - public static int getTextColor(Palette.Builder builder) { - int backgroundColor = 0; - if (mFilteredBackgroundHsl != null) { - builder.addFilter((rgb, hsl) -> { - // at least 10 degrees hue difference - float diff = Math.abs(hsl[0] - mFilteredBackgroundHsl[0]); - return diff > 10 && diff < 350; - }); - } - builder.addFilter(mBlackWhiteFilter); - Palette palette = builder.generate(); - return selectForegroundColor(backgroundColor, palette); - } - - private static int selectForegroundColor(int backgroundColor, Palette palette) { - if (ColorUtil.isColorLight(backgroundColor)) { - return selectForegroundColorForSwatches(palette.getDarkVibrantSwatch(), - palette.getVibrantSwatch(), - palette.getDarkMutedSwatch(), - palette.getMutedSwatch(), - palette.getDominantSwatch(), - Color.BLACK); - } else { - return selectForegroundColorForSwatches(palette.getLightVibrantSwatch(), - palette.getVibrantSwatch(), - palette.getLightMutedSwatch(), - palette.getMutedSwatch(), - palette.getDominantSwatch(), - Color.WHITE); - } - } - - private static int selectForegroundColorForSwatches(Palette.Swatch moreVibrant, - Palette.Swatch vibrant, Palette.Swatch moreMutedSwatch, Palette.Swatch mutedSwatch, - Palette.Swatch dominantSwatch, int fallbackColor) { - Palette.Swatch coloredCandidate = selectVibrantCandidate(moreVibrant, vibrant); - if (coloredCandidate == null) { - coloredCandidate = selectMutedCandidate(mutedSwatch, moreMutedSwatch); - } - if (coloredCandidate != null) { - if (dominantSwatch == coloredCandidate) { - return coloredCandidate.getRgb(); - } else if ((float) coloredCandidate.getPopulation() / dominantSwatch.getPopulation() - < POPULATION_FRACTION_FOR_DOMINANT - && dominantSwatch.getHsl()[1] > MIN_SATURATION_WHEN_DECIDING) { - return dominantSwatch.getRgb(); - } else { - return coloredCandidate.getRgb(); - } - } else if (hasEnoughPopulation(dominantSwatch)) { - return dominantSwatch.getRgb(); - } else { - return fallbackColor; - } - } - - private static Palette.Swatch selectMutedCandidate(Palette.Swatch first, - Palette.Swatch second) { - boolean firstValid = hasEnoughPopulation(first); - boolean secondValid = hasEnoughPopulation(second); - if (firstValid && secondValid) { - float firstSaturation = first.getHsl()[1]; - float secondSaturation = second.getHsl()[1]; - float populationFraction = first.getPopulation() / (float) second.getPopulation(); - if (firstSaturation * populationFraction > secondSaturation) { - return first; - } else { - return second; - } - } else if (firstValid) { - return first; - } else if (secondValid) { - return second; - } - return null; - } - - private static Palette.Swatch selectVibrantCandidate(Palette.Swatch first, - Palette.Swatch second) { - boolean firstValid = hasEnoughPopulation(first); - boolean secondValid = hasEnoughPopulation(second); - if (firstValid && secondValid) { - int firstPopulation = first.getPopulation(); - int secondPopulation = second.getPopulation(); - if (firstPopulation / (float) secondPopulation - < POPULATION_FRACTION_FOR_MORE_VIBRANT) { - return second; - } else { - return first; - } - } else if (firstValid) { - return first; - } else if (secondValid) { - return second; - } - return null; - } - - private static boolean hasEnoughPopulation(Palette.Swatch swatch) { - // We want a fraction that is at least 1% of the image - return swatch != null - && (swatch.getPopulation() / (float) RESIZE_BITMAP_AREA > MINIMUM_IMAGE_FRACTION); - } - - public static int findBackgroundColorAndFilter(Palette palette) { - // by default we use the dominant palette - Palette.Swatch dominantSwatch = palette.getDominantSwatch(); - if (dominantSwatch == null) { - // We're not filtering on white or black - mFilteredBackgroundHsl = null; - return Color.WHITE; - } - if (!isWhiteOrBlack(dominantSwatch.getHsl())) { - mFilteredBackgroundHsl = dominantSwatch.getHsl(); - return dominantSwatch.getRgb(); - } - // Oh well, we selected black or white. Lets look at the second color! - List swatches = palette.getSwatches(); - float highestNonWhitePopulation = -1; - Palette.Swatch second = null; - for (Palette.Swatch swatch : swatches) { - if (swatch != dominantSwatch - && swatch.getPopulation() > highestNonWhitePopulation - && !isWhiteOrBlack(swatch.getHsl())) { - second = swatch; - highestNonWhitePopulation = swatch.getPopulation(); - } - } - if (second == null) { - // We're not filtering on white or black - mFilteredBackgroundHsl = null; - return dominantSwatch.getRgb(); - } - if (dominantSwatch.getPopulation() / highestNonWhitePopulation - > POPULATION_FRACTION_FOR_WHITE_OR_BLACK) { - // The dominant swatch is very dominant, lets take it! - // We're not filtering on white or black - mFilteredBackgroundHsl = null; - return dominantSwatch.getRgb(); - } else { - mFilteredBackgroundHsl = second.getHsl(); - return second.getRgb(); - } - } - - private static boolean isWhiteOrBlack(float[] hsl) { - return isBlack(hsl) || isWhite(hsl); - } - - *//** - * @return true if the color represents a color which is close to black. - *//* - private static boolean isBlack(float[] hslColor) { - return hslColor[2] <= BLACK_MAX_LIGHTNESS; - } - - *//** - * @return true if the color represents a color which is close to white. - *//* - private static boolean isWhite(float[] hslColor) { - return hslColor[2] >= WHITE_MIN_LIGHTNESS; - } - - public void setIsLowPriority(boolean isLowPriority) { - mIsLowPriority = isLowPriority; - }*/ } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/schedulers/BaseSchedulerProvider.java b/app/src/main/java/code/name/monkey/retromusic/util/schedulers/BaseSchedulerProvider.java deleted file mode 100644 index 1c844235..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/schedulers/BaseSchedulerProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.util.schedulers; - -import androidx.annotation.NonNull; -import io.reactivex.Scheduler; - -/** - * Created by hemanths on 12/08/17. - */ - -public interface BaseSchedulerProvider { - @NonNull - Scheduler computation(); - - @NonNull - Scheduler io(); - - @NonNull - Scheduler ui(); -} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/schedulers/SchedulerProvider.java b/app/src/main/java/code/name/monkey/retromusic/util/schedulers/SchedulerProvider.java deleted file mode 100644 index 481f0232..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/schedulers/SchedulerProvider.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.util.schedulers; - -import androidx.annotation.NonNull; - -import io.reactivex.Scheduler; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -/** - * Created by hemanths on 12/08/17. - */ - -public class SchedulerProvider implements BaseSchedulerProvider { - @NonNull - private static SchedulerProvider INSTANCE; - - public SchedulerProvider() { - } - - public static synchronized SchedulerProvider getInstance() { - if (INSTANCE == null) { - INSTANCE = new SchedulerProvider(); - } - return INSTANCE; - } - - @Override - @NonNull - public Scheduler computation() { - return Schedulers.computation(); - } - - @Override - @NonNull - public Scheduler io() { - return Schedulers.io(); - } - - @Override - @NonNull - public Scheduler ui() { - return AndroidSchedulers.mainThread(); - } -} diff --git a/app/src/main/res/drawable/background_image.xml b/app/src/main/res/drawable/background_image.xml index 34810f56..3e55dfa0 100644 --- a/app/src/main/res/drawable/background_image.xml +++ b/app/src/main/res/drawable/background_image.xml @@ -1,12 +1,11 @@ - - + android:shape="rectangle"> + \ No newline at end of file diff --git a/app/src/main/res/layout-v24/layout_notification_collapsed.xml b/app/src/main/res/layout-v24/layout_notification_collapsed.xml index 5eff4110..cc70cd7d 100644 --- a/app/src/main/res/layout-v24/layout_notification_collapsed.xml +++ b/app/src/main/res/layout-v24/layout_notification_collapsed.xml @@ -1,157 +1,159 @@ - - - - - - - - - - - - - - - - - - - - + tools:ignore="ContentDescription"> - + - + - + - + - + - + - + - + - - + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-v24/layout_notification_expanded.xml b/app/src/main/res/layout-v24/layout_notification_expanded.xml index 74efd499..50615fab 100644 --- a/app/src/main/res/layout-v24/layout_notification_expanded.xml +++ b/app/src/main/res/layout-v24/layout_notification_expanded.xml @@ -1,146 +1,135 @@ + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/background" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + android:id="@+id/image" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/content" + android:layout_alignParentEnd="true"> + android:id="@+id/largeIcon" + android:layout_width="@dimen/notification_big_image_size" + android:layout_height="@dimen/notification_big_image_size" + android:layout_alignParentEnd="true" + android:scaleType="centerCrop" + tools:src="@tools:sample/avatars" /> + android:id="@+id/foregroundImage" + android:layout_width="96dp" + android:layout_height="match_parent" + android:layout_alignStart="@id/largeIcon" + android:src="@drawable/background_image" /> + android:id="@+id/content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentStart="true" + android:orientation="vertical" + android:paddingStart="0dp" + android:paddingTop="8dp" + android:paddingEnd="144dp"> - - - - + android:layout_marginBottom="4dp" + android:gravity="center_vertical" + android:orientation="horizontal"> + android:id="@+id/smallIcon" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_marginStart="8dp" + tools:src="@drawable/ic_audiotrack_black_24dp" + tools:tint="@color/md_black_1000" /> + + + + + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:lines="1" + android:paddingStart="16dp" + android:paddingEnd="0dp" + android:singleLine="true" + android:textStyle="bold" + tools:text="@tools:sample/lorem/random" /> + android:id="@+id/subtitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:lines="1" + android:paddingStart="16dp" + android:paddingEnd="0dp" + android:singleLine="true" + tools:text="@tools:sample/lorem/random" /> + android:paddingEnd="0dp" + android:paddingStart="12dp" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:orientation="horizontal"> + android:id="@+id/action_prev" + android:layout_width="42dp" + android:layout_height="42dp" + android:scaleType="centerInside" /> + android:id="@+id/action_play_pause" + android:layout_width="42dp" + android:layout_height="42dp" + android:scaleType="centerInside" /> + android:id="@+id/action_next" + android:layout_width="42dp" + android:layout_height="42dp" + android:scaleType="centerInside" /> - + android:id="@+id/action_quit" + android:layout_width="42dp" + android:layout_height="42dp" + android:scaleType="centerInside" /> \ No newline at end of file diff --git a/app/src/main/res/layout/layout_notification_collapsed.xml b/app/src/main/res/layout/layout_notification_collapsed.xml index e0c5189b..55c36340 100644 --- a/app/src/main/res/layout/layout_notification_collapsed.xml +++ b/app/src/main/res/layout/layout_notification_collapsed.xml @@ -19,7 +19,8 @@ android:layout_height="match_parent" android:layout_alignParentEnd="true" android:adjustViewBounds="true" - android:scaleType="centerCrop" /> + android:scaleType="centerCrop" + tools:src="@tools:sample/avatars" /> + tools:tint="?colorPrimary" /> @@ -36,11 +37,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="48dp" - android:layout_marginBottom="4dp" android:gravity="center_vertical" android:orientation="horizontal" android:paddingStart="8dp" - android:paddingTop="6dp" + android:paddingTop="4dp" android:paddingEnd="8dp"> + android:paddingStart="16dp" + android:paddingEnd="12dp"> + tools:text="@tools:sample/lorem/random" /> + tools:text="@tools:sample/lorem/random" /> @@ -124,33 +119,39 @@ + android:layout_width="38dp" + android:layout_height="38dp" + android:scaleType="centerInside" + android:src="@drawable/ic_skip_previous_round_white_32dp" + android:tint="?colorOnPrimary" /> + android:layout_width="38dp" + android:layout_height="38dp" + android:scaleType="centerInside" + android:src="@drawable/ic_pause_white_24dp" + android:tint="?colorOnPrimary" /> + android:layout_width="38dp" + android:layout_height="38dp" + android:scaleType="centerInside" + android:src="@drawable/ic_skip_next_round_white_32dp" + android:tint="?colorOnPrimary" /> \ No newline at end of file diff --git a/app/src/main/res/layout/layout_notification_expanded.xml b/app/src/main/res/layout/layout_notification_expanded.xml index 6f98469e..df873134 100644 --- a/app/src/main/res/layout/layout_notification_expanded.xml +++ b/app/src/main/res/layout/layout_notification_expanded.xml @@ -1,142 +1,133 @@ - - + android:layout_height="wrap_content"> - - - - - - - - - - - - - + android:layout_alignBottom="@+id/content" + android:layout_alignParentEnd="true"> - + - + - - - + + android:id="@+id/content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentStart="true" + android:orientation="vertical" + android:paddingStart="0dp" + android:paddingTop="8dp" + android:paddingEnd="144dp"> - + - + - + - + + + + + + + + + + + + + + + + + + - \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 36be3533..66325418 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -18,7 +18,7 @@ 20sp - 134dp + 112dp