Merge remote-tracking branch 'origin/dev' into dev-alpha

# Conflicts:
#	app/build.gradle
#	app/src/main/assets/contributors.json
#	build.gradle
This commit is contained in:
Prathamesh More 2022-08-06 11:21:08 +05:30
commit 6c0f1941af
41 changed files with 333 additions and 305 deletions

View file

@ -1,11 +1,13 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.devtools.ksp'
apply plugin: "androidx.navigation.safeargs.kotlin"
apply plugin: 'kotlin-parcelize'
android {
compileSdk 32
namespace "code.name.monkey.retromusic"
defaultConfig {
minSdk 21
@ -13,29 +15,33 @@ android {
vectorDrawables.useSupportLibrary = true
applicationId "code.name.monkey.retromusic"
versionCode 10598
versionName '6.0.3-beta'
applicationId namespace
versionCode 10597
versionName '6.0.2-beta'
buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"")
}
signingConfigs {
release {
Properties properties = getProperties('retro.properties')
storeFile file(getProperty(properties, 'storeFile'))
keyAlias getProperty(properties, 'keyAlias')
storePassword getProperty(properties, 'storePassword')
keyPassword getProperty(properties, 'keyPassword')
def signingProperties = getProperties('retro.properties')
def releaseSigning
if (signingProperties != null) {
releaseSigning = signingConfigs.create("release") {
storeFile file(getProperty(signingProperties, 'storeFile'))
keyAlias getProperty(signingProperties, 'keyAlias')
storePassword getProperty(signingProperties, 'storePassword')
keyPassword getProperty(signingProperties, 'keyPassword')
}
} else {
releaseSigning = signingConfigs.debug
}
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
signingConfig releaseSigning
}
debug {
signingConfig releaseSigning
applicationIdSuffix '.debug'
versionNameSuffix ' DEBUG'
}
@ -50,7 +56,7 @@ android {
}
}
buildFeatures{
buildFeatures {
viewBinding true
}
packagingOptions {
@ -59,6 +65,7 @@ android {
}
}
lint {
abortOnError true
warning 'ImpliedQuantity', 'Instantiatable', 'MissingQuantity', 'MissingTranslation'
}
compileOptions {
@ -68,23 +75,28 @@ android {
kotlinOptions {
jvmTarget = "1.8"
}
dependenciesInfo {
includeInApk = false
includeInBundle = false
}
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
}
}
def getProperties(String fileName) {
final Properties properties = new Properties()
Properties properties = new Properties()
def file = rootProject.file(fileName)
if (file.exists()) {
file.withInputStream { stream -> properties.load(stream) }
} else {
properties = null
}
return properties
}
static def getProperty(Properties properties, String name) {
return properties.getProperty(name) ?: "$name missing"
return properties?.getProperty(name) ?: "$name missing"
}
dependencies {
@ -94,12 +106,12 @@ dependencies {
implementation "androidx.appcompat:appcompat:$appcompat_version"
implementation 'androidx.annotation:annotation:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.recyclerview:recyclerview:1.3.0-beta01'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation "androidx.preference:preference-ktx:$preference_version"
implementation "androidx.core:core-ktx:$core_version"
implementation 'androidx.palette:palette-ktx:1.0.0'
implementation 'androidx.mediarouter:mediarouter:1.3.1'
implementation 'androidx.mediarouter:mediarouter:1.3.0'
//Cast Dependencies
normalImplementation 'com.google.android.gms:play-services-cast-framework:21.0.1'
//WebServer by NanoHttpd
@ -112,13 +124,13 @@ dependencies {
def room_version = '2.5.0-alpha02'
implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version"
ksp "androidx.room:room-compiler:$room_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
implementation "androidx.core:core-splashscreen:1.0.0"
implementation "androidx.core:core-splashscreen:1.0.0-rc01"
normalImplementation 'com.google.android.play:feature-delivery:2.0.0'
normalImplementation 'com.google.android.play:review:2.0.0'
@ -135,11 +147,9 @@ dependencies {
implementation "com.afollestad.material-dialogs:input:$material_dialog_version"
implementation "com.afollestad.material-dialogs:color:$material_dialog_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'com.afollestad:material-cab:2.0.1'
def kotlin_coroutines_version = '1.6.4'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
def koin_version = '3.2.0'
implementation "io.insert-koin:koin-core:$koin_version"
@ -159,6 +169,7 @@ dependencies {
implementation "dev.chrisbanes.insetter:insetter:0.6.1"
implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5'
implementation 'com.github.Adonai:jaudiotagger:2.3.15'
normalImplementation 'com.anjlab.android.iab.v3:library:2.0.3'
implementation 'com.r0adkll:slidableactivity:2.1.0'

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="code.name.monkey.retromusic">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission
android:name="android.permission.BLUETOOTH"

View file

@ -20,7 +20,7 @@
{
"name": "Milind Goel",
"summary": "Support Representative & Moderator",
"link": "https://milindgoel15.github.io",
"link": "https://milindgoel.vercel.app",
"image": "milind.png"
},
{

View file

@ -43,7 +43,7 @@ class App : Application() {
// default theme
if (!ThemeStore.isConfigured(this, 3)) {
ThemeStore.editTheme(this)
.accentColorRes(R.color.md_deep_purple_A200)
.accentColorRes(code.name.monkey.appthemehelper.R.color.md_deep_purple_A200)
.coloredNavigationBar(true)
.commit()
}

View file

@ -18,17 +18,17 @@ class ErrorActivity : AppCompatActivity() {
private val reportPrefix = "bug_report-"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.customactivityoncrash_default_error_activity)
setContentView(cat.ereza.customactivityoncrash.R.layout.customactivityoncrash_default_error_activity)
val restartButton =
findViewById<Button>(R.id.customactivityoncrash_error_activity_restart_button)
findViewById<Button>(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_restart_button)
val config = CustomActivityOnCrash.getConfigFromIntent(intent)
if (config == null) {
finish()
return
}
restartButton.setText(R.string.customactivityoncrash_error_activity_restart_app)
restartButton.setText(cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_restart_app)
restartButton.setOnClickListener {
CustomActivityOnCrash.restartApplication(
this@ErrorActivity,
@ -36,11 +36,11 @@ class ErrorActivity : AppCompatActivity() {
)
}
val moreInfoButton =
findViewById<Button>(R.id.customactivityoncrash_error_activity_more_info_button)
findViewById<Button>(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_more_info_button)
moreInfoButton.setOnClickListener { //We retrieve all the error data and show it
MaterialAlertDialogBuilder(this@ErrorActivity)
.setTitle(R.string.customactivityoncrash_error_activity_error_details_title)
.setTitle(cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_error_details_title)
.setMessage(
CustomActivityOnCrash.getAllErrorDetailsFromIntent(
this@ErrorActivity,
@ -48,7 +48,7 @@ class ErrorActivity : AppCompatActivity() {
)
)
.setPositiveButton(
R.string.customactivityoncrash_error_activity_error_details_close,
cat.ereza.customactivityoncrash.R.string.customactivityoncrash_error_activity_error_details_close,
null
)
.setNeutralButton(
@ -70,7 +70,7 @@ class ErrorActivity : AppCompatActivity() {
}
val errorActivityDrawableId = config.errorDrawable
val errorImageView =
findViewById<ImageView>(R.id.customactivityoncrash_error_activity_image)
findViewById<ImageView>(cat.ereza.customactivityoncrash.R.id.customactivityoncrash_error_activity_image)
if (errorActivityDrawableId != null) {
errorImageView.setImageResource(
errorActivityDrawableId

View file

@ -50,8 +50,8 @@ public class SAFGuideActivity extends IntroActivity {
? R.string.saf_guide_slide1_description_before_o
: R.string.saf_guide_slide1_description)
.image(R.drawable.saf_guide_1)
.background(R.color.md_deep_purple_300)
.backgroundDark(R.color.md_deep_purple_400)
.background(code.name.monkey.appthemehelper.R.color.md_deep_purple_300)
.backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_400)
.layout(R.layout.fragment_simple_slide_large_image)
.build());
addSlide(
@ -59,8 +59,8 @@ public class SAFGuideActivity extends IntroActivity {
.title(R.string.saf_guide_slide2_title)
.description(R.string.saf_guide_slide2_description)
.image(R.drawable.saf_guide_2)
.background(R.color.md_deep_purple_500)
.backgroundDark(R.color.md_deep_purple_600)
.background(code.name.monkey.appthemehelper.R.color.md_deep_purple_500)
.backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_600)
.layout(R.layout.fragment_simple_slide_large_image)
.build());
addSlide(
@ -68,8 +68,8 @@ public class SAFGuideActivity extends IntroActivity {
.title(R.string.saf_guide_slide3_title)
.description(R.string.saf_guide_slide3_description)
.image(R.drawable.saf_guide_3)
.background(R.color.md_deep_purple_700)
.backgroundDark(R.color.md_deep_purple_800)
.background(code.name.monkey.appthemehelper.R.color.md_deep_purple_700)
.backgroundDark(code.name.monkey.appthemehelper.R.color.md_deep_purple_800)
.layout(R.layout.fragment_simple_slide_large_image)
.build());
}

View file

@ -95,7 +95,7 @@ class SongFileAdapter(
}
private fun loadFileImage(file: File, holder: ViewHolder) {
val iconColor = ATHUtil.resolveColor(activity, R.attr.colorControlNormal)
val iconColor = ATHUtil.resolveColor(activity, androidx.appcompat.R.attr.colorControlNormal)
if (file.isDirectory) {
holder.image?.let {
it.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN)
@ -104,7 +104,7 @@ class SongFileAdapter(
holder.imageTextContainer?.setCardBackgroundColor(
ATHUtil.resolveColor(
activity,
R.attr.colorSurface
com.google.android.material.R.attr.colorSurface
)
)
} else {

View file

@ -119,7 +119,7 @@ class AlbumCoverPagerAdapter(
withContext(Dispatchers.Main) {
MaterialAlertDialogBuilder(
requireContext(),
R.style.ThemeOverlay_MaterialComponents_Dialog_Alert
com.google.android.material.R.style.ThemeOverlay_MaterialComponents_Dialog_Alert
).apply {
setTitle(song.title)
setMessage(if (data.isNullOrEmpty()) "No lyrics found" else data)

View file

@ -40,29 +40,29 @@ class AppWidgetText : BaseAppWidget() {
appWidgetView.setImageViewBitmap(
R.id.button_next,
context.getTintedDrawable(R.drawable.ic_skip_next, ContextCompat.getColor(
context, R.color.md_white_1000
context, code.name.monkey.appthemehelper.R.color.md_white_1000
)).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev,
context.getTintedDrawable(R.drawable.ic_skip_previous, ContextCompat.getColor(
context, R.color.md_white_1000
context, code.name.monkey.appthemehelper.R.color.md_white_1000
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause,
context.getTintedDrawable(R.drawable.ic_play_arrow_white_32dp, ContextCompat.getColor(
context, R.color.md_white_1000
context, code.name.monkey.appthemehelper.R.color.md_white_1000
)
).toBitmap()
)
appWidgetView.setTextColor(
R.id.title, ContextCompat.getColor(context, R.color.md_white_1000)
R.id.title, ContextCompat.getColor(context, code.name.monkey.appthemehelper.R.color.md_white_1000)
)
appWidgetView.setTextColor(
R.id.text, ContextCompat.getColor(context, R.color.md_white_1000)
R.id.text, ContextCompat.getColor(context, code.name.monkey.appthemehelper.R.color.md_white_1000)
)
linkButtons(context, appWidgetView)
@ -127,7 +127,7 @@ class AppWidgetText : BaseAppWidget() {
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause,
service.getTintedDrawable(playPauseRes, ContextCompat.getColor(
service, R.color.md_white_1000)
service, code.name.monkey.appthemehelper.R.color.md_white_1000)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
@ -136,7 +136,7 @@ class AppWidgetText : BaseAppWidget() {
R.drawable.ic_skip_next,
ContextCompat.getColor(
service,
R.color.md_white_1000
code.name.monkey.appthemehelper.R.color.md_white_1000
)
).toBitmap()
)
@ -145,7 +145,7 @@ class AppWidgetText : BaseAppWidget() {
service.getTintedDrawable(
R.drawable.ic_skip_previous,
ContextCompat.getColor(
service, R.color.md_white_1000
service, code.name.monkey.appthemehelper.R.color.md_white_1000
)
).toBitmap()
)

View file

@ -52,7 +52,7 @@ fun Int.ripAlpha(): Int {
fun Dialog.colorControlNormal() = resolveColor(android.R.attr.colorControlNormal)
fun Toolbar.backgroundTintList() {
val surfaceColor = ATHUtil.resolveColor(context, R.attr.colorSurface, Color.BLACK)
val surfaceColor = ATHUtil.resolveColor(context, com.google.android.material.R.attr.colorSurface, Color.BLACK)
val colorStateList = ColorStateList.valueOf(surfaceColor)
backgroundTintList = colorStateList
}
@ -61,13 +61,13 @@ fun Context.accentColor() = ThemeStore.accentColor(this)
fun Fragment.accentColor() = ThemeStore.accentColor(requireContext())
fun Context.surfaceColor() = resolveColor(R.attr.colorSurface, Color.WHITE)
fun Context.surfaceColor() = resolveColor(com.google.android.material.R.attr.colorSurface, Color.WHITE)
fun Fragment.surfaceColor() = resolveColor(R.attr.colorSurface, Color.WHITE)
fun Fragment.surfaceColor() = resolveColor(com.google.android.material.R.attr.colorSurface, Color.WHITE)
fun Context.surfaceColor(fallBackColor: Int) = resolveColor(R.attr.colorSurface, fallBackColor)
fun Context.surfaceColor(fallBackColor: Int) = resolveColor(com.google.android.material.R.attr.colorSurface, fallBackColor)
fun Fragment.surfaceColor(fallBackColor: Int) = resolveColor(R.attr.colorSurface, fallBackColor)
fun Fragment.surfaceColor(fallBackColor: Int) = resolveColor(com.google.android.material.R.attr.colorSurface, fallBackColor)
fun Context.textColorSecondary() = resolveColor(android.R.attr.textColorSecondary)

View file

@ -71,7 +71,7 @@ class RestoreActivity : AppCompatActivity() {
DynamicColors.applyToActivityIfAvailable(
this,
DynamicColorsOptions.Builder()
.setThemeOverlay(R.style.ThemeOverlay_Material3_DynamicColors_DayNight)
.setThemeOverlay(com.google.android.material.R.style.ThemeOverlay_Material3_DynamicColors_DayNight)
.build()
)
}

View file

@ -118,7 +118,7 @@ class BlurPlaybackControlsFragment :
override fun setColor(color: MediaNotificationProcessor) {
lastPlaybackControlsColor = Color.WHITE
lastDisabledPlaybackControlsColor =
ContextCompat.getColor(requireContext(), R.color.md_grey_500)
ContextCompat.getColor(requireContext(), code.name.monkey.appthemehelper.R.color.md_grey_500)
binding.title.setTextColor(lastPlaybackControlsColor)

View file

@ -53,7 +53,7 @@ class MD3PlayerFragment : AbsPlayerFragment(R.layout.fragment_md3_player) {
}
override fun toolbarIconColor(): Int {
return ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal)
return ATHUtil.resolveColor(requireContext(), androidx.appcompat.R.attr.colorControlNormal)
}
override fun onColorChanged(color: MediaNotificationProcessor) {
@ -63,7 +63,7 @@ class MD3PlayerFragment : AbsPlayerFragment(R.layout.fragment_md3_player) {
ToolbarContentTintHelper.colorizeToolbar(
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
ATHUtil.resolveColor(requireContext(), androidx.appcompat.R.attr.colorControlNormal),
requireActivity()
)
}
@ -108,7 +108,7 @@ class MD3PlayerFragment : AbsPlayerFragment(R.layout.fragment_md3_player) {
ToolbarContentTintHelper.colorizeToolbar(
binding.playerToolbar,
ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal),
ATHUtil.resolveColor(requireContext(), androidx.appcompat.R.attr.colorControlNormal),
requireActivity()
)
}

View file

@ -26,7 +26,7 @@ import com.bumptech.glide.request.transition.Transition
abstract class SingleColorTarget(view: ImageView) : BitmapPaletteTarget(view) {
private val defaultFooterColor: Int
get() = ATHUtil.resolveColor(view.context, R.attr.colorControlNormal)
get() = ATHUtil.resolveColor(view.context, androidx.appcompat.R.attr.colorControlNormal)
abstract fun onColorReady(color: Int)
@ -43,7 +43,7 @@ abstract class SingleColorTarget(view: ImageView) : BitmapPaletteTarget(view) {
onColorReady(
ColorUtil.getColor(
resource.palette,
ATHUtil.resolveColor(view.context, R.attr.colorPrimary)
ATHUtil.resolveColor(view.context, androidx.appcompat.R.attr.colorPrimary)
)
)
}

View file

@ -124,14 +124,14 @@ class PlayingNotificationClassic(
super.onLoadFailed(errorDrawable)
update(
null,
resolveColor(context, R.attr.colorSurface, Color.WHITE)
resolveColor(context, com.google.android.material.R.attr.colorSurface, Color.WHITE)
)
}
override fun onLoadCleared(placeholder: Drawable?) {
update(
null,
resolveColor(context, R.attr.colorSurface, Color.WHITE)
resolveColor(context, com.google.android.material.R.attr.colorSurface, Color.WHITE)
)
}
@ -157,7 +157,7 @@ class PlayingNotificationClassic(
if (!VersionUtils.hasS()) {
if (!PreferenceUtil.isColoredNotification) {
bgColorFinal =
resolveColor(context, R.attr.colorSurface, Color.WHITE)
resolveColor(context, com.google.android.material.R.attr.colorSurface, Color.WHITE)
}
setBackgroundColor(bgColorFinal)
setNotificationContent(ColorUtil.isColorLight(bgColorFinal))

View file

@ -35,7 +35,6 @@ import java.util.List;
import code.name.monkey.appthemehelper.ThemeStore;
import code.name.monkey.appthemehelper.util.ColorUtil;
import code.name.monkey.appthemehelper.util.VersionUtils;
import code.name.monkey.retromusic.R;
public class RetroColorUtil {
public static int desaturateColor(int color, float ratio) {
@ -224,7 +223,7 @@ public class RetroColorUtil {
public static int getMD3AccentColor(@NotNull Context context) {
if (VersionUtils.hasS()) {
return ContextCompat.getColor(context, R.color.m3_accent_color);
return ContextCompat.getColor(context, code.name.monkey.appthemehelper.R.color.m3_accent_color);
} else {
return ThemeStore.Companion.accentColor(context);
}

View file

@ -35,7 +35,6 @@ import java.util.List;
import code.name.monkey.appthemehelper.util.ATHUtil;
import code.name.monkey.appthemehelper.util.ColorUtil;
import code.name.monkey.retromusic.R;
/** A class the processes media notifications and extracts the right text and background colors. */
public class MediaNotificationProcessor {
@ -454,7 +453,7 @@ public class MediaNotificationProcessor {
public int getMightyColor() {
boolean isDarkBg =
ColorUtil.INSTANCE.isColorLight(
ATHUtil.INSTANCE.resolveColor(context, R.attr.colorSurface));
ATHUtil.INSTANCE.resolveColor(context, com.google.android.material.R.attr.colorSurface));
if (isDarkBg) {
if (isColorLight(backgroundColor)) {
return primaryTextColor;

View file

@ -38,8 +38,6 @@ import androidx.core.content.ContextCompat;
import java.util.Locale;
import java.util.WeakHashMap;
import code.name.monkey.retromusic.R;
/**
* Helper class to process legacy (Holo) notifications to make them look like material
* notifications.
@ -62,7 +60,7 @@ public class NotificationColorUtil {
private NotificationColorUtil(Context context) {
mGrayscaleIconMaxSize =
context.getResources().getDimensionPixelSize(R.dimen.notification_large_icon_width);
context.getResources().getDimensionPixelSize(androidx.core.R.dimen.notification_large_icon_width);
}
public static NotificationColorUtil getInstance(Context context) {

View file

@ -51,7 +51,7 @@ class ColorIconsImageView @JvmOverloads constructor(
val desaturatedColor = RetroColorUtil.desaturateColor(color, 0.4f)
backgroundTintList = ColorStateList.valueOf(desaturatedColor)
imageTintList =
ColorStateList.valueOf(ATHUtil.resolveColor(context, R.attr.colorSurface))
ColorStateList.valueOf(ATHUtil.resolveColor(context, com.google.android.material.R.attr.colorSurface))
} else {
val finalColor = MaterialColors.harmonize(
color,

View file

@ -32,8 +32,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.drawable.DrawableCompat;
import code.name.monkey.retromusic.R;
public class PopupBackground extends Drawable {
private final int mPaddingEnd;
@ -52,8 +50,8 @@ public class PopupBackground extends Drawable {
mPaint.setColor(color);
mPaint.setStyle(Paint.Style.FILL);
Resources resources = context.getResources();
mPaddingStart = resources.getDimensionPixelOffset(R.dimen.afs_md2_popup_padding_start);
mPaddingEnd = resources.getDimensionPixelOffset(R.dimen.afs_md2_popup_padding_end);
mPaddingStart = resources.getDimensionPixelOffset(me.zhanghai.android.fastscroll.R.dimen.afs_md2_popup_padding_start);
mPaddingEnd = resources.getDimensionPixelOffset(me.zhanghai.android.fastscroll.R.dimen.afs_md2_popup_padding_end);
}
private static void pathArcTo(

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="code.name.monkey.retromusic">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="com.android.vending.BILLING" />