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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + + +