commit 0519aba5d96fb6ff159c1bc6c6899a58f5e9567c
Author: Aurailus <100Toby1@gmail.com>
Date: Tue May 9 19:27:25 2017 -0700
Laptop push
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..39fb081
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
new file mode 100644
index 0000000..719bb8b
--- /dev/null
+++ b/.idea/codeStyleSettings.xml
@@ -0,0 +1,228 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..96cc43e
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..e7bedf3
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..7ac24c7
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc-DESKTOP-GJ9PABQ.xml b/.idea/misc-DESKTOP-GJ9PABQ.xml
new file mode 100644
index 0000000..5d19981
--- /dev/null
+++ b/.idea/misc-DESKTOP-GJ9PABQ.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..973695b
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..3bb457e
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..7f68460
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace-DESKTOP-GJ9PABQ-2.xml b/.idea/workspace-DESKTOP-GJ9PABQ-2.xml
new file mode 100644
index 0000000..7246585
--- /dev/null
+++ b/.idea/workspace-DESKTOP-GJ9PABQ-2.xml
@@ -0,0 +1,3252 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1493249228276
+
+
+ 1493249228276
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace-DESKTOP-GJ9PABQ.xml b/.idea/workspace-DESKTOP-GJ9PABQ.xml
new file mode 100644
index 0000000..e7e50c1
--- /dev/null
+++ b/.idea/workspace-DESKTOP-GJ9PABQ.xml
@@ -0,0 +1,3108 @@
+
+
+
+
+
+
+
+
+
+ android-25
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Android > Lint > Correctness
+
+
+
+
+ AndroidLintMissingConstraints
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1492559147521
+
+
+ 1492559147521
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..bdaacf0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,27 @@
+# [Canine Music Player](http://canine.woofbark.dog)
+[![Canine Music Logo](https://github.com/Aurailus/CanineMusic/blob/master/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png)](http://canine.woofbark.dog)
+
+A clean, lightweight Music Player for Android.
+
+## What is Canine Music?
+Canine Music is a Java App made by [@Aurailus](https://github.com/Aurailus) for Android Devices, with help from [@delta1512](https://github.com/delta1512). The app aims to achieve everything that we've wanted that other music apps have omitted. The app is being built in Android Studio for API 21 (Android Lollipop) and up.
+
+## What needs to be done:
+- [x] Music Playback
+- [ ] Album Arts
+- [ ] Shuffle
+- [ ] Jumble
+- [ ] Playlists
+- [ ] Web integration (Soundcloud, Youtube??)
+- [ ] ID3 Editor
+- [ ] Volume button jacking
+
+## Will it cost money?
+No, Canine Music will be provided free of charge.
+
+## How can I help?
+I don't know how Github works, Don't ask me!
+
+## Credit where Credit is due
+- [@delta1512](https://github.com/Aurailus) - Icon Design \([link](https://github.com/delta1512/open_icon_set)\)
+- [@Aurailus](https://github.com/delta1512) - Programming and Design
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..2d6d510
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,36 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+ defaultConfig {
+ applicationId "com.aurailus.caninemusic"
+ minSdkVersion 21
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ vectorDrawables.useSupportLibrary = true
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ productFlavors {
+ }
+}
+
+dependencies {
+ compile fileTree(include: ['*.jar'], dir: 'libs')
+ androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+ compile 'com.android.support:appcompat-v7:25.3.1'
+ compile 'com.android.support.constraint:constraint-layout:1.0.2'
+ compile 'com.android.support:design:25.3.1'
+ compile 'com.android.support:support-vector-drawable:25.3.1'
+ compile 'com.android.support:support-v4:25.3.1'
+ testCompile 'junit:junit:4.12'
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..3d4cee2
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in C:\Users\ben\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/src/androidTest/java/com/aurailus/caninemusic/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/aurailus/caninemusic/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..a20a946
--- /dev/null
+++ b/app/src/androidTest/java/com/aurailus/caninemusic/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.aurailus.caninemusic;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.aurailus.caninemusic", appContext.getPackageName());
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e702089
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png
new file mode 100644
index 0000000..ab16509
Binary files /dev/null and b/app/src/main/ic_launcher-web.png differ
diff --git a/app/src/main/ic_launcher_round-web.png b/app/src/main/ic_launcher_round-web.png
new file mode 100644
index 0000000..ab16509
Binary files /dev/null and b/app/src/main/ic_launcher_round-web.png differ
diff --git a/app/src/main/ic_overflow-web.png b/app/src/main/ic_overflow-web.png
new file mode 100644
index 0000000..e47e1e2
Binary files /dev/null and b/app/src/main/ic_overflow-web.png differ
diff --git a/app/src/main/ic_repeat-web.png b/app/src/main/ic_repeat-web.png
new file mode 100644
index 0000000..2a1d779
Binary files /dev/null and b/app/src/main/ic_repeat-web.png differ
diff --git a/app/src/main/ic_shuffle-web.png b/app/src/main/ic_shuffle-web.png
new file mode 100644
index 0000000..5c93e33
Binary files /dev/null and b/app/src/main/ic_shuffle-web.png differ
diff --git a/app/src/main/java/com/aurailus/caninemusic/Album.java b/app/src/main/java/com/aurailus/caninemusic/Album.java
new file mode 100644
index 0000000..7728538
--- /dev/null
+++ b/app/src/main/java/com/aurailus/caninemusic/Album.java
@@ -0,0 +1,73 @@
+package com.aurailus.caninemusic;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.provider.MediaStore;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import java.io.File;
+
+public class Album {
+ private String id, title, artist;
+ private RoundedBitmapDrawable albumArt;
+ private boolean empty = false;
+
+ public Album(String id, String title, String artist, Context context) {
+ this.id = id;
+ this.title = title;
+ this.artist = artist;
+
+ getAlbumArt(context);
+ }
+ public Album(String id, Context context) {
+ this.id = id;
+
+ getAlbumArt(context);
+ }
+
+ public void getAlbumArt(Context context) {
+ ContentResolver albumResolver = context.getContentResolver();
+ Cursor albumCursor = albumResolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, //Location to grab from
+ new String[] {MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART}, //Columns to grab
+ MediaStore.Audio.Albums._ID+ "=?", //Selection filter... question marks substitute 4th row args
+ new String[] {String.valueOf(id)}, //Args for filter
+ null);
+
+ if (albumCursor.moveToFirst()) {
+ String albumString = albumCursor.getString(albumCursor.getColumnIndex(android.provider.MediaStore.Audio.Albums.ALBUM_ART));
+ File file = new File(albumString);
+
+ if (file.exists()) {
+
+ Bitmap albumBmp = Bitmap.createScaledBitmap(BitmapFactory.decodeFile(albumString), 128, 128, false);
+ albumArt = RoundedBitmapDrawableFactory.create(null, albumBmp);
+
+ albumArt.setCornerRadius(1000.0f);
+ albumArt.setAntiAlias(true);
+ }
+ else empty = true;
+
+ }
+ else empty = true;
+ }
+
+ /*Getters and setters*/
+ public String getId() {
+ return id;
+ }
+ public String getTitle() {
+ return title;
+ }
+ public String getArtist() {
+ return artist;
+ }
+ public Drawable getImage() {
+ return albumArt;
+ }
+ public boolean getEmpty() { return empty; }
+}
diff --git a/app/src/main/java/com/aurailus/caninemusic/AlbumAdapter.java b/app/src/main/java/com/aurailus/caninemusic/AlbumAdapter.java
new file mode 100644
index 0000000..57f3f6a
--- /dev/null
+++ b/app/src/main/java/com/aurailus/caninemusic/AlbumAdapter.java
@@ -0,0 +1,71 @@
+package com.aurailus.caninemusic;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.constraint.ConstraintLayout;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+public class AlbumAdapter extends BaseAdapter {
+ private ArrayList albums;
+ private LayoutInflater albumInf;
+ private boolean moredetails;
+ private ConstraintLayout albumLay;
+
+ @Override
+ public int getCount() {
+ return albums.size();
+ }
+
+ @Override
+ public Object getItem(int arg0) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int arg0) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int ind, View convertView, ViewGroup parent) {
+
+ if (!moredetails) albumLay = (ConstraintLayout)albumInf.inflate(R.layout.album_grid, parent, false);
+ else albumLay = (ConstraintLayout)albumInf.inflate(R.layout.album_list, parent, false);
+
+ TextView albumView = (TextView)albumLay.findViewById(R.id.album_title);
+ TextView artistView = (TextView)albumLay.findViewById(R.id.album_artist);
+ ImageView albumArtView = (ImageView) albumLay.findViewById(R.id.album_art);
+
+ Album curAlbum = albums.get(ind);
+ albumView.setText(curAlbum.getTitle());
+ if (!curAlbum.getEmpty()) {
+ Drawable img = curAlbum.getImage();
+ albumArtView.setImageDrawable(img);
+ }
+
+ if (moredetails) {
+ TextView playsView = (TextView) albumLay.findViewById(R.id.album_plays);
+ TextView lengthView = (TextView) albumLay.findViewById(R.id.album_length);
+
+ artistView.setText(curAlbum.getArtist());
+ playsView.setText(" Plays");
+ //lengthView.setText(curAlbum.getLength());
+ }
+
+ albumLay.setTag(curAlbum.getId());
+ return albumLay;
+ }
+
+ public AlbumAdapter(Context c, ArrayList albums, boolean list) {
+ this.albums = albums;
+ this.moredetails = list;
+ albumInf = LayoutInflater.from(c);
+ }
+}
diff --git a/app/src/main/java/com/aurailus/caninemusic/MainActivity.java b/app/src/main/java/com/aurailus/caninemusic/MainActivity.java
new file mode 100644
index 0000000..8244134
--- /dev/null
+++ b/app/src/main/java/com/aurailus/caninemusic/MainActivity.java
@@ -0,0 +1,415 @@
+package com.aurailus.caninemusic;
+
+import android.Manifest;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.Image;
+import android.os.Build;
+import android.os.IBinder;
+import android.provider.MediaStore;
+import android.support.annotation.NonNull;
+import android.support.constraint.ConstraintLayout;
+import android.support.design.widget.BottomNavigationView;
+import android.support.design.widget.NavigationView;
+import android.support.v4.content.LocalBroadcastManager;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.GridView;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.net.Uri;
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.widget.TextView;
+import android.widget.ViewFlipper;
+import android.widget.ViewSwitcher;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import com.aurailus.caninemusic.MusicService.*;
+
+public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
+
+ private ArrayList songList;
+ private ArrayList playList;
+ private ArrayList albumList;
+ private GridView albumGridView;
+ private ListView albumListView;
+ private ViewSwitcher albumSwitcher;
+ private MusicService musicSrv;
+ private Intent playIntent;
+ private boolean playbackPaused = false;
+ private boolean albumIsGrid = true;
+ private boolean musicBound = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+
+ //Basic stuffs
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ //Request Permission at Runtime because Android Sucks
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
+ return;
+ }
+ }
+
+ //Initialize Songs
+ songList = new ArrayList<>();
+ playList = new ArrayList<>();
+ getSongs();
+ Collections.sort(songList, new Comparator() {
+ public int compare(Song a, Song b) {
+ return a.getTitle().toLowerCase().compareTo(b.getTitle().toLowerCase());
+ }
+ });
+ playList.addAll(songList);
+
+ ListView songView = (ListView)findViewById(R.id.song_list);
+ SongAdapter songAdt = new SongAdapter(this, songList);
+ songView.setAdapter(songAdt);
+
+ //Initialize Albums
+ albumList = new ArrayList<>();
+ getAlbums();
+ Collections.sort(albumList, new Comparator() {
+ public int compare(Album a, Album b) {
+ return a.getTitle().toLowerCase().compareTo(b.getTitle().toLowerCase());
+ }
+ });
+
+ albumGridView = (GridView)findViewById(R.id.album_grid);
+ AlbumAdapter albumAdt = new AlbumAdapter(this, albumList, false);
+ albumGridView.setAdapter(albumAdt);
+
+ albumListView = (ListView)findViewById(R.id.album_list);
+ albumAdt = new AlbumAdapter(this, albumList, true);
+ albumListView.setAdapter(albumAdt);
+
+ albumSwitcher = (ViewSwitcher)findViewById(R.id.album_switcher);
+
+ //Navigation
+ NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
+ navigationView.setNavigationItemSelectedListener(this);
+
+ BottomNavigationView bottomNav = (BottomNavigationView) findViewById(R.id.navigation);
+ bottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
+ @Override
+ public boolean onNavigationItemSelected(@NonNull MenuItem item) {
+ selectSection(item);
+ return true;
+ }
+ });
+
+ //Receive Broadcasts for Toolbar Song Details
+ LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter("musicPrepared"));
+ }
+
+ void selectSection(MenuItem item) {
+ ViewFlipper flipper = (ViewFlipper)findViewById(R.id.flipper);
+ switch (item.getItemId()) {
+ case (R.id.nav_album):
+ flipper.setDisplayedChild(0);
+ break;
+ case (R.id.nav_playlist):
+ flipper.setDisplayedChild(1);
+ break;
+ case (R.id.nav_track):
+ flipper.setDisplayedChild(2);
+ break;
+ case (R.id.nav_artist):
+ flipper.setDisplayedChild(3);
+ break;
+ case (R.id.nav_genre):
+ flipper.setDisplayedChild(4);
+ break;
+ }
+ }
+
+ private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ TextView appTitle = (TextView)findViewById(R.id.app_title);
+ ConstraintLayout songDetails = (ConstraintLayout)findViewById(R.id.playing_details);
+
+ appTitle.setVisibility(View.INVISIBLE);
+ songDetails.setVisibility(View.VISIBLE);
+
+ TextView mainTitle = (TextView)findViewById(R.id.current_title);
+ TextView mainArtist = (TextView)findViewById(R.id.current_artist);
+
+ mainTitle.setText(musicSrv.getTitle());
+ mainArtist.setText(musicSrv.getArtist());
+
+ ImageView albumView = (ImageView)findViewById(R.id.current_albumart);
+ String albumId = musicSrv.getAlbumId();
+ ContentResolver albumResolver = getContentResolver();
+ Cursor albumCursor = albumResolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, //Location to grab from
+ new String[] {MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART}, //Columns to grab
+ MediaStore.Audio.Albums._ID + "=?", //Selection filter... question marks substitute 4th row args
+ new String[] {String.valueOf(albumId)}, //Args for filter
+ null);
+
+ if (albumCursor.moveToFirst()) {
+ String albumString = albumCursor.getString(albumCursor.getColumnIndex(android.provider.MediaStore.Audio.Albums.ALBUM_ART));
+
+ File file = new File(albumString);
+
+ if (file.exists()) {
+
+ Bitmap albumBmp = Bitmap.createScaledBitmap(BitmapFactory.decodeFile(albumString), 128, 128, false);
+ RoundedBitmapDrawable albumArt = RoundedBitmapDrawableFactory.create(null, albumBmp);
+
+ albumArt.setCornerRadius(1000.0f);
+ albumArt.setAntiAlias(true);
+
+ albumView.setImageDrawable(albumArt);
+ }
+ }
+ }
+ };
+
+ //Set the musicBound variable
+ private ServiceConnection musicConnection = new ServiceConnection() {
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ MusicBinder binder = (MusicBinder)service;
+ musicSrv = binder.getService();
+ musicSrv.setList(playList);
+ musicBound = true;
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ musicBound = false;
+ }
+ };
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ if (playIntent == null) {
+ playIntent = new Intent(this, MusicService.class);
+ bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
+ startService(playIntent);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ //finish();
+ //stopService(playIntent);
+ //musicSrv = null;
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
+ super.onDestroy();
+ }
+
+ public void getSongs() {
+ ContentResolver musicResolver = getContentResolver();
+ Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+ Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
+
+ if (musicCursor != null && musicCursor.moveToFirst()) {
+ int idList = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
+ int titleList = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
+ int artistList = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.ARTIST);
+ int albumList = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.ALBUM_ID);
+ int durationList = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.DURATION);
+
+ boolean next = true;
+ while (next) {
+ long thisId = musicCursor.getLong(idList);
+ String thisTitle = musicCursor.getString(titleList);
+ String thisArtist = musicCursor.getString(artistList);
+ String albumId = musicCursor.getString(albumList);
+ long thisDuration = musicCursor.getLong(durationList);
+
+ songList.add(new Song(thisId, thisTitle, thisArtist, albumId, thisDuration));
+ next = musicCursor.moveToNext();
+ }
+ musicCursor.close();
+ }
+ }
+
+ public void getAlbums() {
+ ContentResolver albumResolver = getContentResolver();
+ Uri albumUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+ String[]columns = {android.provider.MediaStore.Audio.Albums._ID, android.provider.MediaStore.Audio.Albums.ALBUM_ID,
+ android.provider.MediaStore.Audio.Albums.ALBUM, android.provider.MediaStore.Audio.Albums.ARTIST};
+
+ Cursor albumCursor = albumResolver.query(albumUri, columns, null, null, null);
+
+ if (albumCursor != null && albumCursor.moveToFirst()) {
+ int titleList = albumCursor.getColumnIndex(android.provider.MediaStore.Audio.Albums.ALBUM);
+ int albumIdList = albumCursor.getColumnIndex(android.provider.MediaStore.Audio.Albums.ALBUM_ID);
+ int artistList = albumCursor.getColumnIndex(android.provider.MediaStore.Audio.Albums.ARTIST);
+
+ boolean next = true;
+ while (next) {
+ String albumId = albumCursor.getString(albumIdList);
+ String thisTitle = albumCursor.getString(titleList);
+ String thisArtist = albumCursor.getString(artistList);
+
+ boolean exists = false;
+ for (Album album : albumList) {
+ if (album.getId().equals(albumId)) {
+ exists = true;
+ break;
+ }
+ }
+ if (!exists) albumList.add(new Album(albumId, thisTitle, thisArtist, this.getBaseContext()));
+ next = albumCursor.moveToNext();
+ }
+ albumCursor.close();
+ }
+ }
+
+ public void chooseSong(View view) {
+ musicSrv.setSong(Integer.parseInt(view.getTag().toString()));
+ musicSrv.playSong();
+ if (playbackPaused) {
+ playbackPaused = false;
+ }
+ openPlayer();
+ }
+
+ public void chooseAlbum(View view) {
+ if (musicBound) {
+ if (playbackPaused) {
+ playbackPaused = false;
+ }
+
+ playList.clear();
+ System.out.println(view.getTag());
+ for (Song song : songList) {
+ if (song.getAlbumId().equals(view.getTag())) {
+ playList.add(song);
+ }
+ }
+ musicSrv.setList(playList);
+ musicSrv.setSong((int) Math.floor(Math.random() * playList.size()));
+ musicSrv.playSong();
+ openPlayer();
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
+ if (drawer.isDrawerOpen(GravityCompat.START)) {
+ drawer.closeDrawer(GravityCompat.START);
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ public boolean onNavigationItemSelected(@NonNull MenuItem item) {
+ switch(item.getItemId()) {
+ case (R.id.add_pin):
+ NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
+ MenuItem it = navigationView.getMenu().findItem(R.id.pinned_items);
+ it.getSubMenu().add(0, 0, 0, "C418").setIcon(R.drawable.ic_jumble);
+ break;
+ case (R.id.nav_rate):
+ String appPck = getPackageName();
+ try {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPck)));
+ } catch (android.content.ActivityNotFoundException anfe) {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPck)));
+ }
+ break;
+ case (R.id.nav_about):
+ //go to about page
+ break;
+ default:
+ break;
+ }
+
+ DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
+ drawer.closeDrawer(GravityCompat.START);
+ return true;
+ }
+
+ public void switchAlbumView(View view) {
+ if (albumIsGrid) {
+ albumListView.setSelection(0);
+ albumSwitcher.setDisplayedChild(1);
+ TextView v = (TextView)findViewById(R.id.album_view_mode);
+ v.setText(R.string.list_mode);
+ albumIsGrid = false;
+ }
+ else {
+ albumGridView.setSelection(0);
+ TextView v = (TextView)findViewById(R.id.album_view_mode);
+ v.setText(R.string.grid_mode);
+ albumSwitcher.setDisplayedChild(0);
+ albumIsGrid = true;
+ }
+ }
+
+ public void openDrawer(View view) {
+ DrawerLayout nav = (DrawerLayout)findViewById(R.id.drawer_layout);
+ nav.openDrawer(Gravity.START);
+ }
+
+ public void shuffleAll(View view) {
+ if (musicBound) {
+ musicSrv.setShuffle(true);
+ playList.addAll(songList);
+ musicSrv.setList(playList);
+ musicSrv.setSong((int) Math.floor(Math.random() * playList.size()));
+ musicSrv.playSong();
+ if (playbackPaused) {
+ playbackPaused = false;
+ }
+ openPlayer();
+ }
+ }
+
+ public void shuffleAll() {
+ if (musicBound) {
+ musicSrv.setShuffle(true);
+ playList.addAll(songList);
+ musicSrv.setList(playList);
+ musicSrv.setSong((int) Math.floor(Math.random() * playList.size()));
+ musicSrv.playSong();
+ if (playbackPaused) {
+ playbackPaused = false;
+ }
+ openPlayer();
+ }
+ }
+
+ public void openPlayer() {
+ Intent intent = new Intent(MainActivity.this, PlayerActivity.class);
+ startActivity(intent);
+ }
+ public void openPlayer(View view) {
+ Intent intent = new Intent(MainActivity.this, PlayerActivity.class);
+ startActivity(intent);
+ }
+}
diff --git a/app/src/main/java/com/aurailus/caninemusic/MusicController.java b/app/src/main/java/com/aurailus/caninemusic/MusicController.java
new file mode 100644
index 0000000..892860f
--- /dev/null
+++ b/app/src/main/java/com/aurailus/caninemusic/MusicController.java
@@ -0,0 +1,15 @@
+package com.aurailus.caninemusic;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.MediaController;
+
+public class MusicController extends MediaController {
+
+ public MusicController(Context c) {
+ super(c);
+ }
+ public void hide() {
+ //prevent popup from hiding
+ }
+}
diff --git a/app/src/main/java/com/aurailus/caninemusic/MusicService.java b/app/src/main/java/com/aurailus/caninemusic/MusicService.java
new file mode 100644
index 0000000..0597d61
--- /dev/null
+++ b/app/src/main/java/com/aurailus/caninemusic/MusicService.java
@@ -0,0 +1,195 @@
+package com.aurailus.caninemusic;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.ContentUris;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+public class MusicService extends Service implements
+ MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, AudioManager.OnAudioFocusChangeListener {
+
+ private MediaPlayer player;
+ private ArrayList songs;
+ private int ind;
+ private final IBinder musicBind = new MusicBinder();
+ private String songTitle, songArtist;
+ private static final int NOTIFY_ID = 1;
+ private boolean shuffle = true;
+ private Random rand;
+ private Runnable playerStart;
+ private Handler h;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ ind = 0;
+ player = new MediaPlayer();
+ rand = new Random();
+
+ initMusicPlayer();
+
+ h = new Handler();
+ playerStart = new Runnable(){
+ public void run(){
+ System.out.println("Playback started");
+ player.start();
+ }
+ };
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return musicBind;
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent){
+ player.stop();
+ player.release();
+ return false;
+ }
+
+ @Override
+ public void onCompletion(MediaPlayer player) {
+ playNext();
+ }
+
+ @Override
+ public void onDestroy() {
+ stopForeground(true);
+ }
+
+ @Override
+ public boolean onError(MediaPlayer player, int what, int extra) {
+ player.reset();
+ return false;
+ }
+
+ @Override
+ public void onPrepared(MediaPlayer player) {
+ h.removeCallbacks(playerStart);
+ int delay = 250;
+ h.postDelayed(playerStart, delay);
+
+ Intent notIntent = new Intent(this, MainActivity.class);
+ notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ PendingIntent pendInt = PendingIntent.getActivity(this, 0, notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ Notification.Builder builder = new Notification.Builder(this);
+
+ builder.setContentIntent(pendInt)
+ .setSmallIcon(R.drawable.play)
+ .setTicker(songTitle)
+ .setOngoing(true)
+ .setContentTitle("Playing")
+ .setContentText(songTitle);
+ Notification not = builder.build();
+ startForeground(NOTIFY_ID, not);
+
+ Intent intent = new Intent("musicPrepared");
+ LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
+ }
+
+ public void setList(ArrayList songs) {
+ this.songs = songs;
+ }
+
+ public void initMusicPlayer() {
+ player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
+ player.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ player.setOnPreparedListener(this);
+ player.setOnCompletionListener(this);
+ player.setOnErrorListener(this);
+ }
+
+ @Override
+ public void onAudioFocusChange(int focusChange) {
+
+ }
+
+ public class MusicBinder extends Binder {
+ MusicService getService() {
+ return MusicService.this;
+ }
+ }
+
+ public void playSong(){
+ player.reset();
+ Song playSong = songs.get(ind);
+ songTitle = playSong.getTitle();
+ songArtist = playSong.getArtist();
+ long curSong = playSong.getId();
+ Uri trackUri = ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, curSong);
+
+ try {
+ player.setDataSource(getApplicationContext(), trackUri);
+ }
+ catch(Exception e) {
+ Log.e("MUSIC SERVICE", "Error setting data source", e);
+ }
+ player.prepareAsync();
+ }
+
+ public void playPrev() {
+ ind--;
+ if (ind < 0) ind = songs.size() - 1;
+ playSong();
+ }
+
+ public void playNext() {
+ if (shuffle) {
+ ind = rand.nextInt(songs.size());
+ }
+ else {
+ ind++;
+ if (ind >= songs.size()) ind = 0;
+ }
+ playSong();
+ }
+
+ public void setSong(int songInd) {
+ ind = songInd;
+ }
+
+ public int getTime() {
+ return player.getCurrentPosition();
+ }
+ public int getLength() {
+ return player.getDuration();
+ }
+ public String getTitle() { return songTitle; }
+ public String getArtist() { return songArtist; }
+ public String getAlbumId() { return songs.get(ind).getAlbumId(); }
+ public boolean getShuffle() {
+ return shuffle;
+ }
+
+ public boolean isPlaying() {
+ return player.isPlaying();
+ }
+ public void pausePlayer() {
+ player.pause();
+ }
+ public void seek(int pos) {
+ player.seekTo(pos);
+ }
+ public void go() {
+ player.start();
+ }
+
+ public void setShuffle(boolean shuffle) {
+ this.shuffle = shuffle;
+ }
+}
diff --git a/app/src/main/java/com/aurailus/caninemusic/PlayerActivity.java b/app/src/main/java/com/aurailus/caninemusic/PlayerActivity.java
new file mode 100644
index 0000000..efc8ff7
--- /dev/null
+++ b/app/src/main/java/com/aurailus/caninemusic/PlayerActivity.java
@@ -0,0 +1,226 @@
+package com.aurailus.caninemusic;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.provider.MediaStore;
+import android.support.v4.content.LocalBroadcastManager;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import java.io.File;
+import java.util.Locale;
+
+public class PlayerActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener {
+
+ private SeekBar seek;
+ private TextView titleView;
+ private TextView artistView;
+ private TextView lengthView;
+ private TextView timeView;
+ private Bitmap albumArt;
+ private ImageView albumView;
+ private ImageButton playPauseButton;
+ private boolean seekInteracting = false;
+ private MusicService musicSrv;
+ private boolean musicBound = false;
+ private Intent playIntent;
+ private Handler h;
+ private Runnable r;
+ private int updateDelay;
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (isFinishing()) {
+ h.removeCallbacks(r);
+ System.out.println("destroy");
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
+ stopService(playIntent);
+ unbindService(musicConnection);
+ musicSrv = null;
+ }
+ }
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.activity_player);
+
+ seek = (SeekBar) findViewById(R.id.song_seekbar);
+ titleView = (TextView) findViewById(R.id.song_title);
+ artistView = (TextView) findViewById(R.id.song_artist);
+ timeView = (TextView) findViewById(R.id.current_time);
+ lengthView = (TextView) findViewById(R.id.song_duration);
+ albumView = (ImageView) findViewById(R.id.album_cover);
+ playPauseButton = (ImageButton) findViewById(R.id.button_playpause);
+
+ seek.setOnSeekBarChangeListener(this);
+
+ if (playIntent == null) {
+ playIntent = new Intent(this, MusicService.class);
+ bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
+ startService(playIntent);
+ }
+
+ LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
+ new IntentFilter("musicPrepared"));
+
+ h = new Handler();
+ r = new Runnable(){
+ public void run(){
+ updatePlayer();
+ h.postDelayed(this, updateDelay);
+ }
+ };
+ }
+
+
+ private ServiceConnection musicConnection = new ServiceConnection() {
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ MusicService.MusicBinder binder = (MusicService.MusicBinder)service;
+ musicSrv = binder.getService();
+ musicBound = true;
+
+ initPlayer();
+ updatePlayer();
+
+ if (!musicSrv.isPlaying()) {
+ playPauseButton.setBackgroundResource(R.drawable.ic_playcircle);
+ }
+
+ updateDelay = 250;
+ h.postDelayed(r, updateDelay);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ musicBound = false;
+ }
+ };
+
+ private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ initPlayer();
+ }
+ };
+
+ private void initPlayer() {
+ seek.setMax(Math.round(musicSrv.getLength()));
+
+ int x = musicSrv.getLength() / 1000;
+ int seconds = x % 60;
+ x /= 60;
+ int minutes = x % 60;
+
+ lengthView.setText(minutes + ":" + String.format(Locale.CANADA, "%02d", seconds));
+
+ titleView.setText(musicSrv.getTitle());
+ artistView.setText(musicSrv.getArtist());
+
+ String albumId = musicSrv.getAlbumId();
+ ContentResolver albumResolver = getContentResolver();
+ Cursor albumCursor = albumResolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, //Location to grab from
+ new String[] {MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART}, //Columns to grab
+ MediaStore.Audio.Albums._ID+ "=?", //Selection filter... question marks substitute 4th row args
+ new String[] {String.valueOf(albumId)}, //Args for filter
+ null);
+
+ if (albumCursor.moveToFirst()) {
+ String albumString = albumCursor.getString(albumCursor.getColumnIndex(android.provider.MediaStore.Audio.Albums.ALBUM_ART));
+
+ File file = new File(albumString);
+
+ if (file.exists()) {
+ albumArt = Bitmap.createBitmap(BitmapFactory.decodeFile(albumString));
+ albumView.setImageBitmap(albumArt);
+ }
+ }
+ }
+ private void updatePlayer() {
+ if (musicBound) {
+ if (!seekInteracting) {
+ seek.setProgress(Math.round(musicSrv.getTime()));
+
+ int x = musicSrv.getTime() / 1000;
+ int seconds = x % 60;
+ x /= 60;
+ int minutes = x % 60;
+
+ timeView.setText(minutes + ":" + String.format(Locale.CANADA, "%02d", seconds));
+ }
+ }
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seek, int progress, boolean fromUser) {
+ if (seekInteracting && fromUser) {
+ int x = seek.getProgress() / 1000;
+ int seconds = x % 60;
+ x /= 60;
+ int minutes = x % 60;
+
+ timeView.setText(minutes + ":" + String.format(Locale.CANADA, "%02d", seconds));
+ }
+ }
+
+ public void togglePlaying(View view) {
+ if (musicSrv.isPlaying()) {
+ musicSrv.pausePlayer();
+ view.setBackgroundResource(R.drawable.ic_playcircle);
+ }
+ else {
+ musicSrv.go();
+ view.setBackgroundResource(R.drawable.ic_pausecircle);
+ }
+ }
+
+ public void nextSong(View view) {
+ musicSrv.playNext();
+ playPauseButton.setBackgroundResource(R.drawable.ic_pausecircle);
+ }
+
+ public void previousSong(View view) {
+ if (musicSrv.getTime() > 3000) {
+ musicSrv.seek(0);
+ }
+ else {
+ musicSrv.playPrev();
+ playPauseButton.setBackgroundResource(R.drawable.ic_pausecircle);
+ }
+ }
+
+ public void back(View view) {
+ this.finish();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seek) {
+ seekInteracting = true;
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seek) {
+ musicSrv.seek(seek.getProgress());
+ seekInteracting = false;
+ }
+}
diff --git a/app/src/main/java/com/aurailus/caninemusic/QueueActivity.java b/app/src/main/java/com/aurailus/caninemusic/QueueActivity.java
new file mode 100644
index 0000000..6ac97a4
--- /dev/null
+++ b/app/src/main/java/com/aurailus/caninemusic/QueueActivity.java
@@ -0,0 +1,24 @@
+package com.aurailus.caninemusic;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+
+public class QueueActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_queue);
+ }
+
+ public void back(View view) {
+ this.finish();
+ }
+
+ @Override
+ public void onBackPressed() {
+ this.finish();
+ }
+
+}
diff --git a/app/src/main/java/com/aurailus/caninemusic/Song.java b/app/src/main/java/com/aurailus/caninemusic/Song.java
new file mode 100644
index 0000000..4f8e8bc
--- /dev/null
+++ b/app/src/main/java/com/aurailus/caninemusic/Song.java
@@ -0,0 +1,47 @@
+package com.aurailus.caninemusic;
+
+import java.util.Locale;
+
+public class Song {
+ private long id, duration;
+ private String title, artist, albumId, humanLength;
+
+ public Song(long id, String title, String artist, String albumId, long duration) {
+ this.id = id;
+ this.title = title;
+ this.artist = artist;
+ this.albumId = albumId;
+ this.duration = duration;
+
+ int x = (int)this.duration/1000;
+ int seconds = x % 60;
+ x /= 60;
+ int minutes = x % 60;
+ this.humanLength = minutes + ":" + String.format(Locale.CANADA, "%02d", seconds);
+ }
+
+ /*Getters and setters*/
+ public long getId() {
+ return id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getArtist() {
+ return artist;
+ }
+
+ public String getAlbumId() {
+ return albumId;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public String getHumanLength() {
+ return humanLength;
+ }
+}
diff --git a/app/src/main/java/com/aurailus/caninemusic/SongAdapter.java b/app/src/main/java/com/aurailus/caninemusic/SongAdapter.java
new file mode 100644
index 0000000..2eb47f1
--- /dev/null
+++ b/app/src/main/java/com/aurailus/caninemusic/SongAdapter.java
@@ -0,0 +1,84 @@
+package com.aurailus.caninemusic;
+
+import android.graphics.drawable.Drawable;
+import android.support.constraint.ConstraintLayout;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import java.util.ArrayList;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class SongAdapter extends BaseAdapter {
+ private ArrayList songs;
+ private ArrayList albumart;
+ private LayoutInflater songInf;
+
+ @Override
+ public int getCount() {
+ return songs.size();
+ }
+
+ @Override
+ public Object getItem(int arg0) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int arg0) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int ind, View convertView, ViewGroup parent) {
+
+ ConstraintLayout songLay = (ConstraintLayout)songInf.inflate(R.layout.song, parent, false);
+ TextView songView = (TextView)songLay.findViewById(R.id.song_title);
+ TextView artistView = (TextView)songLay.findViewById(R.id.song_artist);
+ ImageView albumArtView = (ImageView)songLay.findViewById(R.id.album_art);
+ TextView songDuration = (TextView)songLay.findViewById(R.id.song_duration);
+
+ Song curSong = songs.get(ind);
+ songView.setText(curSong.getTitle());
+ artistView.setText(curSong.getArtist());
+ songDuration.setText(curSong.getHumanLength());
+
+ for(Album curAlbum : albumart) {
+ if (curAlbum.getId().equals(curSong.getAlbumId())) {
+ if (!curAlbum.getEmpty()) {
+ Drawable img = curAlbum.getImage();
+ albumArtView.setImageDrawable(img);
+ break;
+ }
+ }
+ }
+
+ songLay.setTag(ind);
+ return songLay;
+ }
+
+ public SongAdapter(Context c, ArrayList songs) {
+ this.songs = songs;
+ albumart = new ArrayList<>();
+
+ for(int i = 0; i < songs.size(); i++) {
+
+ Song curSong = songs.get(i);
+ boolean exists = false;
+ for(int j = 0; j < albumart.size(); j++) {
+ Album curAlbum = albumart.get(j);
+ if (curSong.getAlbumId().equals(curAlbum.getId())) {
+ exists = true;
+ break;
+ }
+ }
+ if (!exists) {
+ albumart.add(new Album(curSong.getAlbumId(), c));
+ }
+ }
+
+ songInf = LayoutInflater.from(c);
+ }
+}
diff --git a/app/src/main/res/drawable/cross.png b/app/src/main/res/drawable/cross.png
new file mode 100644
index 0000000..a26f1eb
Binary files /dev/null and b/app/src/main/res/drawable/cross.png differ
diff --git a/app/src/main/res/drawable/ic_add_circle.xml b/app/src/main/res/drawable/ic_add_circle.xml
new file mode 100644
index 0000000..db4e035
--- /dev/null
+++ b/app/src/main/res/drawable/ic_add_circle.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_album.xml b/app/src/main/res/drawable/ic_album.xml
new file mode 100644
index 0000000..8728c36
--- /dev/null
+++ b/app/src/main/res/drawable/ic_album.xml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml
new file mode 100644
index 0000000..eaec811
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_back.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_arrow_right.xml b/app/src/main/res/drawable/ic_arrow_right.xml
new file mode 100644
index 0000000..54554cf
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_right.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_artist.xml b/app/src/main/res/drawable/ic_artist.xml
new file mode 100644
index 0000000..1336a3b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_artist.xml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_genre.xml b/app/src/main/res/drawable/ic_genre.xml
new file mode 100644
index 0000000..e531187
--- /dev/null
+++ b/app/src/main/res/drawable/ic_genre.xml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_hamburger.xml b/app/src/main/res/drawable/ic_hamburger.xml
new file mode 100644
index 0000000..cf37e2a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_hamburger.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_jumble.xml b/app/src/main/res/drawable/ic_jumble.xml
new file mode 100644
index 0000000..4ad501f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_jumble.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_menu_edit.xml b/app/src/main/res/drawable/ic_menu_edit.xml
new file mode 100644
index 0000000..2ab2fb7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_menu_edit.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_menu_rate.xml b/app/src/main/res/drawable/ic_menu_rate.xml
new file mode 100644
index 0000000..cfba5d8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_menu_rate.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_menu_ringtone.xml b/app/src/main/res/drawable/ic_menu_ringtone.xml
new file mode 100644
index 0000000..ebf9de6
--- /dev/null
+++ b/app/src/main/res/drawable/ic_menu_ringtone.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_menu_settings.xml b/app/src/main/res/drawable/ic_menu_settings.xml
new file mode 100644
index 0000000..ace746c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_menu_settings.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_menu_share.xml b/app/src/main/res/drawable/ic_menu_share.xml
new file mode 100644
index 0000000..a28fb9e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_menu_share.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_pause.xml b/app/src/main/res/drawable/ic_pause.xml
new file mode 100644
index 0000000..72309d7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_pause.xml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_pausecircle.xml b/app/src/main/res/drawable/ic_pausecircle.xml
new file mode 100644
index 0000000..305c51f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_pausecircle.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_play.xml b/app/src/main/res/drawable/ic_play.xml
new file mode 100644
index 0000000..f8f4149
--- /dev/null
+++ b/app/src/main/res/drawable/ic_play.xml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_play_next.xml b/app/src/main/res/drawable/ic_play_next.xml
new file mode 100644
index 0000000..c56d39b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_play_next.xml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_play_prev.xml b/app/src/main/res/drawable/ic_play_prev.xml
new file mode 100644
index 0000000..49b99eb
--- /dev/null
+++ b/app/src/main/res/drawable/ic_play_prev.xml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_playcircle.xml b/app/src/main/res/drawable/ic_playcircle.xml
new file mode 100644
index 0000000..6bba2c4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_playcircle.xml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_playlist.xml b/app/src/main/res/drawable/ic_playlist.xml
new file mode 100644
index 0000000..174eaf5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_playlist.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_shuffle_flat.xml b/app/src/main/res/drawable/ic_shuffle_flat.xml
new file mode 100644
index 0000000..cd7f32f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_shuffle_flat.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_shuffle_white.xml b/app/src/main/res/drawable/ic_shuffle_white.xml
new file mode 100644
index 0000000..6144dd5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_shuffle_white.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_switchviews.xml b/app/src/main/res/drawable/ic_switchviews.xml
new file mode 100644
index 0000000..f9789ae
--- /dev/null
+++ b/app/src/main/res/drawable/ic_switchviews.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_track.xml b/app/src/main/res/drawable/ic_track.xml
new file mode 100644
index 0000000..d839c46
--- /dev/null
+++ b/app/src/main/res/drawable/ic_track.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/logo_hires.png b/app/src/main/res/drawable/logo_hires.png
new file mode 100644
index 0000000..7b07c0b
Binary files /dev/null and b/app/src/main/res/drawable/logo_hires.png differ
diff --git a/app/src/main/res/drawable/play.png b/app/src/main/res/drawable/play.png
new file mode 100644
index 0000000..4d24f56
Binary files /dev/null and b/app/src/main/res/drawable/play.png differ
diff --git a/app/src/main/res/drawable/ripple_oval.xml b/app/src/main/res/drawable/ripple_oval.xml
new file mode 100644
index 0000000..d7c74f9
--- /dev/null
+++ b/app/src/main/res/drawable/ripple_oval.xml
@@ -0,0 +1,9 @@
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ripple_oval_dark.xml b/app/src/main/res/drawable/ripple_oval_dark.xml
new file mode 100644
index 0000000..b1af649
--- /dev/null
+++ b/app/src/main/res/drawable/ripple_oval_dark.xml
@@ -0,0 +1,9 @@
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ripple_rectangle.xml b/app/src/main/res/drawable/ripple_rectangle.xml
new file mode 100644
index 0000000..002228a
--- /dev/null
+++ b/app/src/main/res/drawable/ripple_rectangle.xml
@@ -0,0 +1,9 @@
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ripple_rectangle_light.xml b/app/src/main/res/drawable/ripple_rectangle_light.xml
new file mode 100644
index 0000000..a0e9b79
--- /dev/null
+++ b/app/src/main/res/drawable/ripple_rectangle_light.xml
@@ -0,0 +1,9 @@
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/side_nav_bar.xml b/app/src/main/res/drawable/side_nav_bar.xml
new file mode 100644
index 0000000..16f9163
--- /dev/null
+++ b/app/src/main/res/drawable/side_nav_bar.xml
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..bbca0b9
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main_drawer_header.xml b/app/src/main/res/layout/activity_main_drawer_header.xml
new file mode 100644
index 0000000..a17ec77
--- /dev/null
+++ b/app/src/main/res/layout/activity_main_drawer_header.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_player.xml b/app/src/main/res/layout/activity_player.xml
new file mode 100644
index 0000000..839bc4d
--- /dev/null
+++ b/app/src/main/res/layout/activity_player.xml
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_queue.xml b/app/src/main/res/layout/activity_queue.xml
new file mode 100644
index 0000000..263a14f
--- /dev/null
+++ b/app/src/main/res/layout/activity_queue.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/album_grid.xml b/app/src/main/res/layout/album_grid.xml
new file mode 100644
index 0000000..cc5cd61
--- /dev/null
+++ b/app/src/main/res/layout/album_grid.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/album_list.xml b/app/src/main/res/layout/album_list.xml
new file mode 100644
index 0000000..e46e611
--- /dev/null
+++ b/app/src/main/res/layout/album_list.xml
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/main_toolbar.xml b/app/src/main/res/layout/main_toolbar.xml
new file mode 100644
index 0000000..6de30ab
--- /dev/null
+++ b/app/src/main/res/layout/main_toolbar.xml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/player_toolbar.xml b/app/src/main/res/layout/player_toolbar.xml
new file mode 100644
index 0000000..5a4e1fa
--- /dev/null
+++ b/app/src/main/res/layout/player_toolbar.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/queue_toolbar.xml b/app/src/main/res/layout/queue_toolbar.xml
new file mode 100644
index 0000000..fbe71f0
--- /dev/null
+++ b/app/src/main/res/layout/queue_toolbar.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/song.xml b/app/src/main/res/layout/song.xml
new file mode 100644
index 0000000..eef2dec
--- /dev/null
+++ b/app/src/main/res/layout/song.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_albums.xml b/app/src/main/res/layout/view_albums.xml
new file mode 100644
index 0000000..516028d
--- /dev/null
+++ b/app/src/main/res/layout/view_albums.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_artists.xml b/app/src/main/res/layout/view_artists.xml
new file mode 100644
index 0000000..add6675
--- /dev/null
+++ b/app/src/main/res/layout/view_artists.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_genres.xml b/app/src/main/res/layout/view_genres.xml
new file mode 100644
index 0000000..a017e28
--- /dev/null
+++ b/app/src/main/res/layout/view_genres.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_playlists.xml b/app/src/main/res/layout/view_playlists.xml
new file mode 100644
index 0000000..eb0e1eb
--- /dev/null
+++ b/app/src/main/res/layout/view_playlists.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_tracks.xml b/app/src/main/res/layout/view_tracks.xml
new file mode 100644
index 0000000..0debc06
--- /dev/null
+++ b/app/src/main/res/layout/view_tracks.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml
new file mode 100644
index 0000000..573b640
--- /dev/null
+++ b/app/src/main/res/menu/activity_main_drawer.xml
@@ -0,0 +1,45 @@
+
+
diff --git a/app/src/main/res/menu/menu_queue.xml b/app/src/main/res/menu/menu_queue.xml
new file mode 100644
index 0000000..a267c5c
--- /dev/null
+++ b/app/src/main/res/menu/menu_queue.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/menu/navigation.xml b/app/src/main/res/menu/navigation.xml
new file mode 100644
index 0000000..0b3ee0f
--- /dev/null
+++ b/app/src/main/res/menu/navigation.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..be4736d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..be4736d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_overflow.png b/app/src/main/res/mipmap-hdpi/ic_overflow.png
new file mode 100644
index 0000000..4631535
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_overflow.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_repeat.png b/app/src/main/res/mipmap-hdpi/ic_repeat.png
new file mode 100644
index 0000000..b32d8d9
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_repeat.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..4f3d4e8
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..4f3d4e8
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_overflow.png b/app/src/main/res/mipmap-mdpi/ic_overflow.png
new file mode 100644
index 0000000..fe17a73
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_overflow.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_repeat.png b/app/src/main/res/mipmap-mdpi/ic_repeat.png
new file mode 100644
index 0000000..4758bfe
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_repeat.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..f167797
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..f167797
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_overflow.png b/app/src/main/res/mipmap-xhdpi/ic_overflow.png
new file mode 100644
index 0000000..a46c0b0
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_overflow.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_repeat.png b/app/src/main/res/mipmap-xhdpi/ic_repeat.png
new file mode 100644
index 0000000..87f6a66
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_repeat.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b98f07a
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b98f07a
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_overflow.png b/app/src/main/res/mipmap-xxhdpi/ic_overflow.png
new file mode 100644
index 0000000..5cd2bcd
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_overflow.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_repeat.png b/app/src/main/res/mipmap-xxhdpi/ic_repeat.png
new file mode 100644
index 0000000..065c07a
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_repeat.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..a36f5ff
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..a36f5ff
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_overflow.png b/app/src/main/res/mipmap-xxxhdpi/ic_overflow.png
new file mode 100644
index 0000000..26644b2
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_overflow.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_repeat.png b/app/src/main/res/mipmap-xxxhdpi/ic_repeat.png
new file mode 100644
index 0000000..5680104
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_repeat.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..82ff28c
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,7 @@
+
+
+ #229999
+ #118888
+ #FF4081
+ #777777
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..8f830ee
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,8 @@
+
+
+ 16dp
+ 16dp
+ 16dp
+ 160dp
+ 16dp
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..a38de9b
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,41 @@
+
+ Canine
+ Canine Music
+ Back
+
+ Currently Playing
+ Player
+ 0:00
+ Previous Song
+ Next Song
+ Play / Pause
+ Album
+ <unknown>
+ Shuffle
+ Repeat
+ Overflow
+
+ ID3 Tagger
+ Settings
+ Ringtone
+ Import
+ Share
+ EXTRA STUFF
+ Rate
+ About us
+ PINNED ITEMS
+ Add Item
+
+ Albums
+ Playlists
+ Tracks
+ Artists
+ Genres
+
+ Grid View
+ List View
+ Settings
+
+ Queue
+
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..0feead1
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/test/java/com/aurailus/caninemusic/ExampleUnitTest.java b/app/src/test/java/com/aurailus/caninemusic/ExampleUnitTest.java
new file mode 100644
index 0000000..54fd21e
--- /dev/null
+++ b/app/src/test/java/com/aurailus/caninemusic/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.aurailus.caninemusic;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..b78a0b8
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,23 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.3.1'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..c50fdad
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Apr 18 16:45:49 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..9d82f78
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app'