kotlin conversion

This commit is contained in:
h4h13 2018-11-30 06:36:16 +05:30
parent 8e6ab40d93
commit b2c15ef186
316 changed files with 13055 additions and 22983 deletions

View file

@ -1,211 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project Licensed under the Apache
* License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
* or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
// Modified for Phonograph by Karim Abou Zeid (kabouzeid).
package code.name.monkey.retromusic.service;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.KeyEvent;
import code.name.monkey.retromusic.BuildConfig;
import static code.name.monkey.retromusic.Constants.ACTION_PAUSE;
import static code.name.monkey.retromusic.Constants.ACTION_PLAY;
import static code.name.monkey.retromusic.Constants.ACTION_REWIND;
import static code.name.monkey.retromusic.Constants.ACTION_SKIP;
import static code.name.monkey.retromusic.Constants.ACTION_STOP;
import static code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE;
/**
* Used to control headset playback.
* Single press: pause/resume
* Double press: next track
* Triple press: previous track
*/
public class MediaButtonIntentReceiver extends BroadcastReceiver {
public static final String TAG = MediaButtonIntentReceiver.class.getSimpleName();
private static final boolean DEBUG = BuildConfig.DEBUG;
private static final int MSG_HEADSET_DOUBLE_CLICK_TIMEOUT = 2;
private static final int DOUBLE_CLICK = 400;
private static WakeLock mWakeLock = null;
private static int mClickCounter = 0;
private static long mLastClickTime = 0;
@SuppressLint("HandlerLeak") // false alarm, handler is already static
private static Handler mHandler = new Handler() {
@Override
public void handleMessage(final Message msg) {
switch (msg.what) {
case MSG_HEADSET_DOUBLE_CLICK_TIMEOUT:
final int clickCount = msg.arg1;
final String command;
if (DEBUG) Log.v(TAG, "Handling headset click, count = " + clickCount);
switch (clickCount) {
case 1:
command = ACTION_TOGGLE_PAUSE;
break;
case 2:
command = ACTION_SKIP;
break;
case 3:
command = ACTION_REWIND;
break;
default:
command = null;
break;
}
if (command != null) {
final Context context = (Context) msg.obj;
startService(context, command);
}
break;
}
releaseWakeLockIfHandlerIdle();
}
};
public static boolean handleIntent(final Context context, final Intent intent) {
final String intentAction = intent.getAction();
if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event == null) {
return false;
}
final int keycode = event.getKeyCode();
final int action = event.getAction();
final long eventTime = event.getEventTime() != 0 ?
event.getEventTime() : System.currentTimeMillis();
String command = null;
switch (keycode) {
case KeyEvent.KEYCODE_MEDIA_STOP:
command = ACTION_STOP;
break;
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
command = ACTION_TOGGLE_PAUSE;
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
command = ACTION_SKIP;
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
command = ACTION_REWIND;
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
command = ACTION_PAUSE;
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
command = ACTION_PLAY;
break;
}
if (command != null) {
if (action == KeyEvent.ACTION_DOWN) {
if (event.getRepeatCount() == 0) {
// Only consider the first event in a sequence, not the repeat events,
// so that we don't trigger in cases where the first event went to
// a different app (e.g. when the user ends a phone call by
// long pressing the headset button)
// The service may or may not be running, but we need to send it
// a command.
if (keycode == KeyEvent.KEYCODE_HEADSETHOOK || keycode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (eventTime - mLastClickTime >= DOUBLE_CLICK) {
mClickCounter = 0;
}
mClickCounter++;
if (DEBUG) Log.v(TAG, "Got headset click, count = " + mClickCounter);
mHandler.removeMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT);
Message msg = mHandler.obtainMessage(
MSG_HEADSET_DOUBLE_CLICK_TIMEOUT, mClickCounter, 0, context);
long delay = mClickCounter < 3 ? DOUBLE_CLICK : 0;
if (mClickCounter >= 3) {
mClickCounter = 0;
}
mLastClickTime = eventTime;
acquireWakeLockAndSendMessage(context, msg, delay);
} else {
startService(context, command);
}
return true;
}
}
}
}
return false;
}
private static void startService(Context context, String command) {
final Intent intent = new Intent(context, MusicService.class);
intent.setAction(command);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
}
private static void acquireWakeLockAndSendMessage(Context context, Message msg, long delay) {
if (mWakeLock == null) {
Context appContext = context.getApplicationContext();
PowerManager pm = (PowerManager) appContext.getSystemService(Context.POWER_SERVICE);
if (pm != null) {
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"RetroMusicApp:Wakelock headset button");
}
mWakeLock.setReferenceCounted(false);
}
if (DEBUG) Log.v(TAG, "Acquiring wake lock and sending " + msg.what);
// Make sure we don't indefinitely hold the wake lock under any circumstances
mWakeLock.acquire(10000);
mHandler.sendMessageDelayed(msg, delay);
}
private static void releaseWakeLockIfHandlerIdle() {
if (mHandler.hasMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT)) {
if (DEBUG) Log.v(TAG, "Handler still has messages pending, not releasing wake lock");
return;
}
if (mWakeLock != null) {
if (DEBUG) Log.v(TAG, "Releasing wake lock");
mWakeLock.release();
mWakeLock = null;
}
}
@Override
public void onReceive(final Context context, final Intent intent) {
if (DEBUG) Log.v(TAG, "Received intent: " + intent);
if (handleIntent(context, intent) && isOrderedBroadcast()) {
abortBroadcast();
}
}
}

View file

@ -0,0 +1,186 @@
/*
* Copyright (C) 2007 The Android Open Source Project Licensed under the Apache
* License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
* or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package code.name.monkey.retromusic.service
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Handler
import android.os.Message
import android.os.PowerManager
import android.os.PowerManager.WakeLock
import android.util.Log
import android.view.KeyEvent
import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.Constants.ACTION_PAUSE
import code.name.monkey.retromusic.Constants.ACTION_PLAY
import code.name.monkey.retromusic.Constants.ACTION_REWIND
import code.name.monkey.retromusic.Constants.ACTION_SKIP
import code.name.monkey.retromusic.Constants.ACTION_STOP
import code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE
/**
* Used to control headset playback.
* Single press: pause/resume
* Double press: actionNext track
* Triple press: previous track
*/
class MediaButtonIntentReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (DEBUG) Log.v(TAG, "Received intent: $intent")
if (handleIntent(context, intent) && isOrderedBroadcast) {
abortBroadcast()
}
}
companion object {
val TAG = MediaButtonIntentReceiver::class.java.simpleName
private val DEBUG = BuildConfig.DEBUG
private val MSG_HEADSET_DOUBLE_CLICK_TIMEOUT = 2
private val DOUBLE_CLICK = 400
private var wakeLock: WakeLock? = null
private var mClickCounter = 0
private var mLastClickTime: Long = 0
@SuppressLint("HandlerLeak") // false alarm, handler is already static
private val mHandler = object : Handler() {
override fun handleMessage(msg: Message) {
when (msg.what) {
MSG_HEADSET_DOUBLE_CLICK_TIMEOUT -> {
val clickCount = msg.arg1
val command: String?
if (DEBUG) Log.v(TAG, "Handling headset click, count = $clickCount")
when (clickCount) {
1 -> command = ACTION_TOGGLE_PAUSE
2 -> command = ACTION_SKIP
3 -> command = ACTION_REWIND
else -> command = null
}
if (command != null) {
val context = msg.obj as Context
startService(context, command)
}
}
}
releaseWakeLockIfHandlerIdle()
}
}
fun handleIntent(context: Context, intent: Intent): Boolean {
val intentAction = intent.action
if (Intent.ACTION_MEDIA_BUTTON == intentAction) {
val event = intent.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)
?: return false
val keycode = event.keyCode
val action = event.action
val eventTime = if (event.eventTime != 0L)
event.eventTime
else
System.currentTimeMillis()
var command: String? = null
when (keycode) {
KeyEvent.KEYCODE_MEDIA_STOP -> command = ACTION_STOP
KeyEvent.KEYCODE_HEADSETHOOK, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> command = ACTION_TOGGLE_PAUSE
KeyEvent.KEYCODE_MEDIA_NEXT -> command = ACTION_SKIP
KeyEvent.KEYCODE_MEDIA_PREVIOUS -> command = ACTION_REWIND
KeyEvent.KEYCODE_MEDIA_PAUSE -> command = ACTION_PAUSE
KeyEvent.KEYCODE_MEDIA_PLAY -> command = ACTION_PLAY
}
if (command != null) {
if (action == KeyEvent.ACTION_DOWN) {
if (event.repeatCount == 0) {
// Only consider the first event in a sequence, not the repeat events,
// so that we don't trigger in cases where the first event went to
// a different app (e.g. when the user ends a phone call by
// long pressing the headset button)
// The service may or may not be running, but we need to send it
// a command.
if (keycode == KeyEvent.KEYCODE_HEADSETHOOK || keycode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (eventTime - mLastClickTime >= DOUBLE_CLICK) {
mClickCounter = 0
}
mClickCounter++
if (DEBUG) Log.v(TAG, "Got headset click, count = $mClickCounter")
mHandler.removeMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT)
val msg = mHandler.obtainMessage(
MSG_HEADSET_DOUBLE_CLICK_TIMEOUT, mClickCounter, 0, context)
val delay = (if (mClickCounter < 3) DOUBLE_CLICK else 0).toLong()
if (mClickCounter >= 3) {
mClickCounter = 0
}
mLastClickTime = eventTime
acquireWakeLockAndSendMessage(context, msg, delay)
} else {
startService(context, command)
}
return true
}
}
}
}
return false
}
private fun startService(context: Context, command: String?) {
val intent = Intent(context, MusicService::class.java)
intent.action = command
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
}
private fun acquireWakeLockAndSendMessage(context: Context, msg: Message, delay: Long) {
if (wakeLock == null) {
val appContext = context.applicationContext
val pm = appContext.getSystemService(Context.POWER_SERVICE) as PowerManager
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "RetroMusicApp:Wakelock headset button")
wakeLock!!.setReferenceCounted(false)
}
if (DEBUG) Log.v(TAG, "Acquiring wake lock and sending " + msg.what)
// Make sure we don't indefinitely hold the wake lock under any circumstances
wakeLock!!.acquire(10000)
mHandler.sendMessageDelayed(msg, delay)
}
private fun releaseWakeLockIfHandlerIdle() {
if (mHandler.hasMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT)) {
if (DEBUG) Log.v(TAG, "Handler still has messages pending, not releasing wake lock")
return
}
if (wakeLock != null) {
if (DEBUG) Log.v(TAG, "Releasing wake lock")
wakeLock!!.release()
wakeLock = null
}
}
}
}

View file

@ -1,334 +0,0 @@
package code.name.monkey.retromusic.service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.audiofx.AudioEffect;
import android.net.Uri;
import android.os.PowerManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.service.playback.Playback;
import code.name.monkey.retromusic.util.PreferenceUtil;
/**
* @author Andrew Neal, Karim Abou Zeid (kabouzeid)
*/
public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
public static final String TAG = MultiPlayer.class.getSimpleName();
private MediaPlayer mCurrentMediaPlayer = new MediaPlayer();
private MediaPlayer mNextMediaPlayer;
private Context context;
@Nullable
private Playback.PlaybackCallbacks callbacks;
private boolean mIsInitialized = false;
/**
* Constructor of <code>MultiPlayer</code>
*/
MultiPlayer(final Context context) {
this.context = context;
mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK);
}
/**
* @param path The path of the file, or the http/rtsp URL of the stream
* you want to play
* @return True if the <code>player</code> has been prepared and is
* ready to play, false otherwise
*/
@Override
public boolean setDataSource(@NonNull final String path) {
mIsInitialized = false;
mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path);
if (mIsInitialized) {
setNextDataSource(null);
}
return mIsInitialized;
}
/**
* @param player The {@link MediaPlayer} to use
* @param path The path of the file, or the http/rtsp URL of the stream
* you want to play
* @return True if the <code>player</code> has been prepared and is
* ready to play, false otherwise
*/
private boolean setDataSourceImpl(@NonNull final MediaPlayer player, @NonNull final String path) {
if (context == null) {
return false;
}
try {
player.reset();
player.setOnPreparedListener(null);
if (path.startsWith("content://")) {
player.setDataSource(context, Uri.parse(path));
} else {
player.setDataSource(path);
}
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.prepare();
} catch (Exception e) {
return false;
}
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
final Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
intent.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC);
context.sendBroadcast(intent);
return true;
}
/**
* Set the MediaPlayer to start when this MediaPlayer finishes playback.
*
* @param path The path of the file, or the http/rtsp URL of the stream
* you want to play
*/
@Override
public void setNextDataSource(@Nullable final String path) {
if (context == null) {
return;
}
try {
mCurrentMediaPlayer.setNextMediaPlayer(null);
} catch (IllegalArgumentException e) {
Log.i(TAG, "Next media player is current one, continuing");
} catch (IllegalStateException e) {
Log.e(TAG, "Media player not initialized!");
return;
}
if (mNextMediaPlayer != null) {
mNextMediaPlayer.release();
mNextMediaPlayer = null;
}
if (path == null) {
return;
}
if (PreferenceUtil.getInstance().gaplessPlayback()) {
mNextMediaPlayer = new MediaPlayer();
mNextMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK);
mNextMediaPlayer.setAudioSessionId(getAudioSessionId());
if (setDataSourceImpl(mNextMediaPlayer, path)) {
try {
mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer);
} catch (@NonNull IllegalArgumentException | IllegalStateException e) {
Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e);
if (mNextMediaPlayer != null) {
mNextMediaPlayer.release();
mNextMediaPlayer = null;
}
}
} else {
if (mNextMediaPlayer != null) {
mNextMediaPlayer.release();
mNextMediaPlayer = null;
}
}
}
}
/**
* Sets the callbacks
*
* @param callbacks The callbacks to use
*/
@Override
public void setCallbacks(@Nullable final Playback.PlaybackCallbacks callbacks) {
this.callbacks = callbacks;
}
/**
* @return True if the player is ready to go, false otherwise
*/
@Override
public boolean isInitialized() {
return mIsInitialized;
}
/**
* Starts or resumes playback.
*/
@Override
public boolean start() {
try {
mCurrentMediaPlayer.start();
return true;
} catch (IllegalStateException e) {
return false;
}
}
/**
* Resets the MediaPlayer to its uninitialized state.
*/
@Override
public void stop() {
mCurrentMediaPlayer.reset();
mIsInitialized = false;
}
/**
* Releases resources associated with this MediaPlayer object.
*/
@Override
public void release() {
stop();
mCurrentMediaPlayer.release();
if (mNextMediaPlayer != null) {
mNextMediaPlayer.release();
}
}
/**
* Pauses playback. Call start() to resume.
*/
@Override
public boolean pause() {
try {
mCurrentMediaPlayer.pause();
return true;
} catch (IllegalStateException e) {
return false;
}
}
/**
* Checks whether the MultiPlayer is playing.
*/
@Override
public boolean isPlaying() {
return mIsInitialized && mCurrentMediaPlayer.isPlaying();
}
/**
* Gets the duration of the file.
*
* @return The duration in milliseconds
*/
@Override
public int duration() {
if (!mIsInitialized) {
return -1;
}
try {
return mCurrentMediaPlayer.getDuration();
} catch (IllegalStateException e) {
return -1;
}
}
/**
* Gets the current playback position.
*
* @return The current position in milliseconds
*/
@Override
public int position() {
if (!mIsInitialized) {
return -1;
}
try {
return mCurrentMediaPlayer.getCurrentPosition();
} catch (IllegalStateException e) {
return -1;
}
}
/**
* Gets the current playback position.
*
* @param whereto The offset in milliseconds from the start to seek to
* @return The offset in milliseconds from the start to seek to
*/
@Override
public int seek(final int whereto) {
try {
mCurrentMediaPlayer.seekTo(whereto);
return whereto;
} catch (IllegalStateException e) {
return -1;
}
}
@Override
public boolean setVolume(final float vol) {
try {
mCurrentMediaPlayer.setVolume(vol, vol);
return true;
} catch (IllegalStateException e) {
return false;
}
}
/**
* Sets the audio session ID.
*
* @param sessionId The audio session ID
*/
@Override
public boolean setAudioSessionId(final int sessionId) {
try {
mCurrentMediaPlayer.setAudioSessionId(sessionId);
return true;
} catch (@NonNull IllegalArgumentException | IllegalStateException e) {
return false;
}
}
/**
* Returns the audio session ID.
*
* @return The current audio session ID.
*/
@Override
public int getAudioSessionId() {
return mCurrentMediaPlayer.getAudioSessionId();
}
/**
* {@inheritDoc}
*/
@Override
public boolean onError(final MediaPlayer mp, final int what, final int extra) {
mIsInitialized = false;
mCurrentMediaPlayer.release();
mCurrentMediaPlayer = new MediaPlayer();
mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK);
if (context != null) {
Toast.makeText(context, context.getResources().getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show();
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public void onCompletion(final MediaPlayer mp) {
if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) {
mIsInitialized = false;
mCurrentMediaPlayer.release();
mCurrentMediaPlayer = mNextMediaPlayer;
mIsInitialized = true;
mNextMediaPlayer = null;
if (callbacks != null)
callbacks.onTrackWentToNext();
} else {
if (callbacks != null)
callbacks.onTrackEnded();
}
}
}

View file

@ -0,0 +1,333 @@
package code.name.monkey.retromusic.service
import android.content.Context
import android.content.Intent
import android.media.AudioManager
import android.media.MediaPlayer
import android.media.audiofx.AudioEffect
import android.net.Uri
import android.os.PowerManager
import android.util.Log
import android.widget.Toast
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.service.playback.Playback
import code.name.monkey.retromusic.util.PreferenceUtil
/**
* @author Andrew Neal, Karim Abou Zeid (kabouzeid)
*/
class MultiPlayer
/**
* Constructor of `MultiPlayer`
*/
internal constructor(private val context: Context?) : Playback, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
private var mCurrentMediaPlayer = MediaPlayer()
private var mNextMediaPlayer: MediaPlayer? = null
private var callbacks: Playback.PlaybackCallbacks? = null
private var mIsInitialized = false
init {
mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK)
}
/**
* @param path The path of the file, or the http/rtsp URL of the stream
* you want to play
* @return True if the `player` has been prepared and is
* ready to play, false otherwise
*/
override fun setDataSource(path: String): Boolean {
mIsInitialized = false
mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path)
if (mIsInitialized) {
setNextDataSource(null)
}
return mIsInitialized
}
/**
* @param player The [MediaPlayer] to use
* @param path The path of the file, or the http/rtsp URL of the stream
* you want to play
* @return True if the `player` has been prepared and is
* ready to play, false otherwise
*/
private fun setDataSourceImpl(player: MediaPlayer, path: String): Boolean {
if (context == null) {
return false
}
try {
player.reset()
player.setOnPreparedListener(null)
if (path.startsWith("content://")) {
player.setDataSource(context, Uri.parse(path))
} else {
player.setDataSource(path)
}
player.setAudioStreamType(AudioManager.STREAM_MUSIC)
player.prepare()
} catch (e: Exception) {
return false
}
player.setOnCompletionListener(this)
player.setOnErrorListener(this)
val intent = Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId)
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
intent.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC)
context.sendBroadcast(intent)
return true
}
/**
* Set the MediaPlayer to start when this MediaPlayer finishes playback.
*
* @param path The path of the file, or the http/rtsp URL of the stream
* you want to play
*/
override fun setNextDataSource(path: String?) {
if (context == null) {
return
}
try {
mCurrentMediaPlayer.setNextMediaPlayer(null)
} catch (e: IllegalArgumentException) {
Log.i(TAG, "Next media player is current one, continuing")
} catch (e: IllegalStateException) {
Log.e(TAG, "Media player not initialized!")
return
}
if (mNextMediaPlayer != null) {
mNextMediaPlayer!!.release()
mNextMediaPlayer = null
}
if (path == null) {
return
}
if (PreferenceUtil.getInstance().gaplessPlayback()) {
mNextMediaPlayer = MediaPlayer()
mNextMediaPlayer!!.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK)
mNextMediaPlayer!!.audioSessionId = audioSessionId
if (setDataSourceImpl(mNextMediaPlayer!!, path)) {
try {
mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer)
} catch (e: IllegalArgumentException) {
Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e)
if (mNextMediaPlayer != null) {
mNextMediaPlayer!!.release()
mNextMediaPlayer = null
}
} catch (e: IllegalStateException) {
Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e)
if (mNextMediaPlayer != null) {
mNextMediaPlayer!!.release()
mNextMediaPlayer = null
}
}
} else {
if (mNextMediaPlayer != null) {
mNextMediaPlayer!!.release()
mNextMediaPlayer = null
}
}
}
}
/**
* Sets the callbacks
*
* @param callbacks The callbacks to use
*/
override fun setCallbacks(callbacks: Playback.PlaybackCallbacks?) {
this.callbacks = callbacks
}
/**
* @return True if the player is ready to go, false otherwise
*/
override fun isInitialized(): Boolean {
return mIsInitialized
}
/**
* Starts or resumes playback.
*/
override fun start(): Boolean {
try {
mCurrentMediaPlayer.start()
return true
} catch (e: IllegalStateException) {
return false
}
}
/**
* Resets the MediaPlayer to its uninitialized state.
*/
override fun stop() {
mCurrentMediaPlayer.reset()
mIsInitialized = false
}
/**
* Releases resources associated with this MediaPlayer object.
*/
override fun release() {
stop()
mCurrentMediaPlayer.release()
if (mNextMediaPlayer != null) {
mNextMediaPlayer!!.release()
}
}
/**
* Pauses playback. Call start() to resume.
*/
override fun pause(): Boolean {
try {
mCurrentMediaPlayer.pause()
return true
} catch (e: IllegalStateException) {
return false
}
}
/**
* Checks whether the MultiPlayer is playing.
*/
override fun isPlaying(): Boolean {
return mIsInitialized && mCurrentMediaPlayer.isPlaying
}
/**
* Gets the duration of the file.
*
* @return The duration in milliseconds
*/
override fun duration(): Int {
if (!mIsInitialized) {
return -1
}
try {
return mCurrentMediaPlayer.duration
} catch (e: IllegalStateException) {
return -1
}
}
/**
* Gets the current playback position.
*
* @return The current position in milliseconds
*/
override fun position(): Int {
if (!mIsInitialized) {
return -1
}
try {
return mCurrentMediaPlayer.currentPosition
} catch (e: IllegalStateException) {
return -1
}
}
/**
* Gets the current playback position.
*
* @param whereto The offset in milliseconds from the start to seek to
* @return The offset in milliseconds from the start to seek to
*/
override fun seek(whereto: Int): Int {
try {
mCurrentMediaPlayer.seekTo(whereto)
return whereto
} catch (e: IllegalStateException) {
return -1
}
}
override fun setVolume(vol: Float): Boolean {
try {
mCurrentMediaPlayer.setVolume(vol, vol)
return true
} catch (e: IllegalStateException) {
return false
}
}
/**
* Sets the audio session ID.
*
* @param sessionId The audio session ID
*/
override fun setAudioSessionId(sessionId: Int): Boolean {
try {
mCurrentMediaPlayer.audioSessionId = sessionId
return true
} catch (e: IllegalArgumentException) {
return false
} catch (e: IllegalStateException) {
return false
}
}
/**
* Returns the audio session ID.
*
* @return The current audio session ID.
*/
override fun getAudioSessionId(): Int {
return mCurrentMediaPlayer.audioSessionId
}
/**
* {@inheritDoc}
*/
override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
mIsInitialized = false
mCurrentMediaPlayer.release()
mCurrentMediaPlayer = MediaPlayer()
mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK)
if (context != null) {
Toast.makeText(context, context.resources.getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show()
}
return false
}
/**
* {@inheritDoc}
*/
override fun onCompletion(mp: MediaPlayer) {
if (mp === mCurrentMediaPlayer && mNextMediaPlayer != null) {
mIsInitialized = false
mCurrentMediaPlayer.release()
mCurrentMediaPlayer = mNextMediaPlayer as MediaPlayer
mIsInitialized = true
mNextMediaPlayer = null
if (callbacks != null)
callbacks!!.onTrackWentToNext()
} else {
if (callbacks != null)
callbacks!!.onTrackEnded()
}
}
companion object {
val TAG: String = MultiPlayer::class.java.simpleName
}
}

File diff suppressed because it is too large Load diff

View file

@ -194,9 +194,9 @@ public class WearBrowserService extends MediaBrowserService {
} else {
switch (Integer.parseInt(Character.toString(parentId.charAt(0)))) {
case TYPE_ARTIST:
List<Artist> artistList = ArtistLoader.getAllArtists(mContext).blockingFirst();
List<Artist> artistList = ArtistLoader.INSTANCE.getAllArtists(mContext).blockingFirst();
for (Artist artist : artistList) {
String albumNmber = String.format("%d %s", artist.albums.size(), artist.albums.size() > 1 ? "Albums" : "Album");
String albumNmber = String.format("%d %s", artist.getAlbums().size(), artist.getAlbums().size() > 1 ? "Albums" : "Album");
String songCount = String.format("%d %s", artist.getSongs().size(), artist.getSongs().size() > 1 ? "Songs" : "Song");
fillMediaItems(mediaItems,
Integer.toString(TYPE_ARTIST_SONG_ALBUMS) + Long.toString(artist.getId()),
@ -215,9 +215,9 @@ public class WearBrowserService extends MediaBrowserService {
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_artist_art"),
MediaBrowser.MediaItem.FLAG_BROWSABLE);
List<Album> artistAlbums = ArtistLoader.getArtist(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst().albums; //ArtistAlbumLoader.getAlbumsForArtist(mContext, Long.parseLong(parentId.substring(1)));
List<Album> artistAlbums = ArtistLoader.INSTANCE.getArtist(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst().getAlbums(); //ArtistAlbumLoader.getAlbumsForArtist(mContext, Long.parseLong(parentId.substring(1)));
for (Album album : artistAlbums) {
String songCount = String.format("%d %s", album.songs.size(), album.songs.size() > 1 ? "Songs" : "Song");
String songCount = String.format("%d %s", album.getSongs().size(), album.getSongs().size() > 1 ? "Songs" : "Song");
fillMediaItems(mediaItems,
Integer.toString(TYPE_ALBUM_SONGS) + Long.toString(album.getId()),
album.getTitle(),
@ -227,7 +227,7 @@ public class WearBrowserService extends MediaBrowserService {
}
break;
case TYPE_ALBUM:
List<Album> albumList = AlbumLoader.getAllAlbums(mContext).blockingFirst();
List<Album> albumList = AlbumLoader.Companion.getAllAlbums(mContext).blockingFirst();
for (Album album : albumList) {
fillMediaItems(mediaItems,
Integer.toString(TYPE_ALBUM_SONGS) + Long.toString(album.getId()),
@ -238,43 +238,43 @@ public class WearBrowserService extends MediaBrowserService {
}
break;
case TYPE_SONG:
List<Song> songList = SongLoader.Companion.getAllSongs(mContext).blockingFirst();
List<Song> songList = SongLoader.INSTANCE.getAllSongs(mContext).blockingFirst();
for (Song song : songList) {
fillMediaItems(mediaItems,
String.valueOf(song.id),
song.title,
song.artistName,
String.valueOf(song.getId()),
song.getTitle(),
song.getArtistName(),
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_album_art"),
MediaBrowser.MediaItem.FLAG_PLAYABLE);
}
break;
case TYPE_ALBUM_SONGS:
List<Song> albumSongList = AlbumLoader.getAlbum(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst().songs;
List<Song> albumSongList = AlbumLoader.Companion.getAlbum(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst().getSongs();
for (Song song : albumSongList) {
fillMediaItems(mediaItems,
String.valueOf(song.id),
song.title,
song.artistName,
String.valueOf(song.getId()),
song.getTitle(),
song.getArtistName(),
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_album_art"),
MediaBrowser.MediaItem.FLAG_PLAYABLE);
}
break;
case TYPE_ARTIST_ALL_SONGS:
List<Song> artistSongs = ArtistLoader.getArtist(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst().getSongs();
List<Song> artistSongs = ArtistLoader.INSTANCE.getArtist(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst().getSongs();
for (Song song : artistSongs) {
fillMediaItems(mediaItems,
String.valueOf(song.id),
song.title,
song.albumName,
String.valueOf(song.getId()),
song.getTitle(),
song.getAlbumName(),
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_album_art"),
MediaBrowser.MediaItem.FLAG_PLAYABLE);
}
break;
case TYPE_PLAYLIST:
List<Playlist> playlistList = PlaylistLoader.getAllPlaylists(mContext).blockingFirst();
List<Playlist> playlistList = PlaylistLoader.INSTANCE.getAllPlaylists(mContext).blockingFirst();
for (Playlist playlist : playlistList) {
int size = PlaylistSongsLoader.getPlaylistSongList(mContext, playlist).blockingFirst().size();
int size = PlaylistSongsLoader.INSTANCE.getPlaylistSongList(mContext, playlist).blockingFirst().size();
String songCount = String.format("%d %s", size, size > 1 ? "Songs" : "Song");
fillMediaItems(mediaItems,
Integer.toString(TYPE_PLAYLIST_ALL_SONGS) + Long.toString(playlist.id),
@ -285,12 +285,12 @@ public class WearBrowserService extends MediaBrowserService {
}
break;
case TYPE_PLAYLIST_ALL_SONGS:
List<Song> playlistSongs = PlaylistSongsLoader.getPlaylistSongList(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst();
List<Song> playlistSongs = PlaylistSongsLoader.INSTANCE.getPlaylistSongList(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst();
for (Song song : playlistSongs) {
fillMediaItems(mediaItems,
String.valueOf(song.id),
song.title,
song.albumName,
String.valueOf(song.getId()),
song.getTitle(),
song.getAlbumName(),
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_album_art"),
MediaBrowser.MediaItem.FLAG_PLAYABLE);
}
@ -326,8 +326,8 @@ public class WearBrowserService extends MediaBrowserService {
long songId = Long.parseLong(mediaId);
setSessionActive();
ArrayList<Song> songs = new ArrayList<>();
songs.add(SongLoader.Companion.getSong(mContext, Integer.parseInt(mediaId)).blockingFirst());
MusicPlayerRemote.openQueue(songs, 0, true);
songs.add(SongLoader.INSTANCE.getSong(mContext, Integer.parseInt(mediaId)).blockingFirst());
MusicPlayerRemote.INSTANCE.openQueue(songs, 0, true);
}
@Override

View file

@ -1,186 +0,0 @@
package code.name.monkey.retromusic.service.daydream;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.service.dreams.DreamService;
import androidx.transition.TransitionManager;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import code.name.monkey.retromusic.loaders.SongLoader;
import code.name.monkey.retromusic.model.Song;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget;
import code.name.monkey.retromusic.glide.SongGlideRequest;
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
/**
* Created by hemanths on 25/09/17.
*/
public class RetroMusicAlbums extends DreamService {
@BindView(R.id.recycler_view)
RecyclerView mRecyclerView;
@BindView(R.id.title)
TextView mTitle;
@BindView(R.id.text)
TextView mText;
@BindView(R.id.title_container)
ViewGroup mViewGroup;
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
String artist = intent.getStringExtra("artist");
String track = intent.getStringExtra("track");
if (mViewGroup != null) {
mViewGroup.setVisibility(View.VISIBLE);
TransitionManager.beginDelayedTransition(mViewGroup);
if (mTitle != null) {
mTitle.setText(track);
}
if (mText != null) {
mText.setText(artist);
}
}
}
};
private Unbinder unbinder;
private CompositeDisposable mDisposable;
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
View view = LayoutInflater.from(this).inflate(R.layout.dream_service, null);
setContentView(view);
unbinder = ButterKnife.bind(this, view);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
GridLayoutManager layoutManager = new GridLayoutManager(this, 4, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mDisposable.add(getPlayingQueue()
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.flatMap((Function<ArrayList<Song>, ObservableSource<ArrayList<Song>>>) songs -> Observable.create(e -> {
if (songs.isEmpty()) {
e.onNext(SongLoader.Companion.getAllSongs(RetroMusicAlbums.this).blockingFirst());
} else {
e.onNext(songs);
}
e.onComplete();
}))
.subscribe(songs -> {
if (songs.size() > 0) {
ImagesAdapter imagesAdapter = new ImagesAdapter(songs);
mRecyclerView.setAdapter(imagesAdapter);
}
}));
}
@Override
public void onCreate() {
super.onCreate();
setInteractive(true);
setFullscreen(true);
mDisposable = new CompositeDisposable();
IntentFilter iF = new IntentFilter();
iF.addAction("com.android.music.musicservicecommand");
iF.addAction("com.android.music.metachanged");
registerReceiver(mBroadcastReceiver, iF);
}
@Override
public void onDestroy() {
super.onDestroy();
unbinder.unbind();
mDisposable.clear();
unregisterReceiver(mBroadcastReceiver);
}
private Observable<ArrayList<Song>> getPlayingQueue() {
return Observable.just(MusicPlayerRemote.getPlayingQueue());
}
class ImagesAdapter extends RecyclerView.Adapter<ImagesAdapter.ViewHolder> {
private final ArrayList<Song> list;
public ImagesAdapter(ArrayList<Song> songs) {
this.list = songs;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
return new ViewHolder(LayoutInflater.from(getApplicationContext())
.inflate(R.layout.image, viewGroup, false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int i) {
Song song = list.get(i);
SongGlideRequest.Builder.from(Glide.with(getApplicationContext()), song)
.checkIgnoreMediaStore(getApplicationContext())
.generatePalette(getApplicationContext()).build()
.override(400, 400)
.into(new RetroMusicColoredTarget(holder.image) {
@Override
public void onColorReady(int color) {
}
});
}
@Override
public int getItemCount() {
return list.size();
}
class ViewHolder extends MediaEntryViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
@Override
public void onClick(View v) {
super.onClick(v);
MusicPlayerRemote.openQueue(list, getAdapterPosition(), true);
}
}
}
}

View file

@ -0,0 +1,161 @@
package code.name.monkey.retromusic.service.daydream
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.service.dreams.DreamService
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.transition.TransitionManager
import butterknife.BindView
import butterknife.ButterKnife
import butterknife.Unbinder
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.loaders.SongLoader
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder
import com.bumptech.glide.Glide
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import java.util.*
/**
* Created by hemanths on 25/09/17.
*/
class RetroMusicAlbums : DreamService() {
@BindView(R.id.recycler_view)
internal var mRecyclerView: RecyclerView? = null
@BindView(R.id.title)
internal var mTitle: TextView? = null
@BindView(R.id.text)
internal var mText: TextView? = null
@BindView(R.id.title_container)
internal var mViewGroup: ViewGroup? = null
private val mBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
if (intent == null) {
return
}
val artist = intent.getStringExtra("artist")
val track = intent.getStringExtra("track")
if (mViewGroup != null) {
mViewGroup!!.visibility = View.VISIBLE
TransitionManager.beginDelayedTransition(mViewGroup!!)
if (mTitle != null) {
mTitle!!.text = track
}
if (mText != null) {
mText!!.text = artist
}
}
}
}
private var unbinder: Unbinder? = null
private var mDisposable: CompositeDisposable? = null
private val playingQueue: Observable<ArrayList<Song>>
get() = Observable.just(MusicPlayerRemote.playingQueue)
override fun onAttachedToWindow() {
super.onAttachedToWindow()
val view = LayoutInflater.from(this).inflate(R.layout.dream_service, null)
setContentView(view)
unbinder = ButterKnife.bind(this, view)
mRecyclerView!!.itemAnimator = DefaultItemAnimator()
val layoutManager = GridLayoutManager(this, 4, RecyclerView.VERTICAL, false)
mRecyclerView!!.layoutManager = layoutManager
mDisposable!!.add(playingQueue
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.flatMap {
return@flatMap Observable.create<ArrayList<Song>> { e ->
if (it.isEmpty()) {
e.onNext(SongLoader.getAllSongs(this@RetroMusicAlbums).blockingFirst())
} else {
e.onNext(it)
}
e.onComplete()
}
}
.subscribe { songs ->
if (songs.size > 0) {
val imagesAdapter = ImagesAdapter(songs)
mRecyclerView!!.adapter = imagesAdapter
}
})
}
override fun onCreate() {
super.onCreate()
isInteractive = true
isFullscreen = true
mDisposable = CompositeDisposable()
val iF = IntentFilter()
iF.addAction("com.android.music.musicservicecommand")
iF.addAction("com.android.music.metachanged")
registerReceiver(mBroadcastReceiver, iF)
}
override fun onDestroy() {
super.onDestroy()
unbinder!!.unbind()
mDisposable!!.clear()
unregisterReceiver(mBroadcastReceiver)
}
internal inner class ImagesAdapter(private val list: ArrayList<Song>) : RecyclerView.Adapter<ImagesAdapter.ViewHolder>() {
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(applicationContext)
.inflate(R.layout.image, viewGroup, false))
}
override fun onBindViewHolder(holder: ViewHolder, i: Int) {
val song = list[i]
SongGlideRequest.Builder.from(Glide.with(applicationContext), song)
.checkIgnoreMediaStore(applicationContext)
.generatePalette(applicationContext).build()
.override(400, 400)
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onColorReady(color: Int) {
}
})
}
override fun getItemCount(): Int {
return list.size
}
internal inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
override fun onClick(v: View?) {
super.onClick(v)
MusicPlayerRemote.openQueue(list, adapterPosition, true)
}
}
}
}

View file

@ -28,7 +28,6 @@ import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
import code.name.monkey.retromusic.model.Song;
import code.name.monkey.retromusic.service.MusicService;
import code.name.monkey.retromusic.ui.activities.MainActivity;
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
import code.name.monkey.retromusic.util.PreferenceUtil;
import code.name.monkey.retromusic.util.RetroColorUtil;
import code.name.monkey.retromusic.util.RetroUtil;
@ -57,27 +56,27 @@ public class PlayingNotificationImpl extends PlayingNotification {
final RemoteViews notificationLayoutBig = new RemoteViews(service.getPackageName(),
R.layout.notification_big);
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
if (TextUtils.isEmpty(song.getTitle()) && TextUtils.isEmpty(song.getArtistName())) {
notificationLayout.setViewVisibility(R.id.media_titles, View.INVISIBLE);
} else {
notificationLayout.setViewVisibility(R.id.media_titles, View.VISIBLE);
notificationLayout.setTextViewText(R.id.title, song.title);
notificationLayout.setTextViewText(R.id.text, song.artistName);
notificationLayout.setTextViewText(R.id.title, song.getTitle());
notificationLayout.setTextViewText(R.id.text, song.getArtistName());
}
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName) && TextUtils
.isEmpty(song.albumName)) {
if (TextUtils.isEmpty(song.getTitle()) && TextUtils.isEmpty(song.getArtistName()) && TextUtils
.isEmpty(song.getAlbumName())) {
notificationLayoutBig.setViewVisibility(R.id.media_titles, View.INVISIBLE);
} else {
notificationLayoutBig.setViewVisibility(R.id.media_titles, View.VISIBLE);
notificationLayoutBig.setTextViewText(R.id.title, song.title);
notificationLayoutBig.setTextViewText(R.id.text, song.artistName);
notificationLayoutBig.setTextViewText(R.id.text2, song.albumName);
notificationLayoutBig.setTextViewText(R.id.title, song.getTitle());
notificationLayoutBig.setTextViewText(R.id.text, song.getArtistName());
notificationLayoutBig.setTextViewText(R.id.text2, song.getAlbumName());
}
linkButtons(notificationLayout, notificationLayoutBig);
Intent action = new Intent(service, NowPayingActivity.class);
Intent action = new Intent(service, MainActivity.class);
action.putExtra("expand", true);
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

View file

@ -16,13 +16,12 @@ import com.bumptech.glide.request.target.SimpleTarget;
import androidx.core.app.NotificationCompat;
import androidx.media.app.NotificationCompat.MediaStyle;
import code.name.monkey.retromusic.Constants;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.glide.SongGlideRequest;
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
import code.name.monkey.retromusic.model.Song;
import code.name.monkey.retromusic.service.MusicService;
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
import code.name.monkey.retromusic.ui.activities.MainActivity;
import code.name.monkey.retromusic.util.PreferenceUtil;
import code.name.monkey.retromusic.util.RetroColorUtil;
@ -43,14 +42,14 @@ public class PlayingNotificationImpl24 extends PlayingNotification {
final int playButtonResId = isPlaying ? R.drawable.ic_pause_white_24dp :
R.drawable.ic_play_arrow_white_24dp;
Intent action = new Intent(service, NowPayingActivity.class);
Intent action = new Intent(service, MainActivity.class);
action.putExtra("expand", true);
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
final PendingIntent clickIntent = PendingIntent
.getActivity(service, 0, action, PendingIntent.FLAG_UPDATE_CURRENT);
final ComponentName serviceName = new ComponentName(service, MusicService.class);
Intent intent = new Intent(Constants.ACTION_QUIT);
Intent intent = new Intent(ACTION_QUIT);
intent.setComponent(serviceName);
final PendingIntent deleteIntent = PendingIntent.getService(service, 0, intent, 0);
@ -106,9 +105,9 @@ public class PlayingNotificationImpl24 extends PlayingNotification {
.setLargeIcon(bitmap)
.setContentIntent(clickIntent)
.setDeleteIntent(deleteIntent)
.setContentTitle(Html.fromHtml("<b>" + song.title + "</b>"))
.setContentText(song.artistName)
.setSubText(Html.fromHtml("<b>" + song.albumName + "</b>"))
.setContentTitle(Html.fromHtml("<b>" + song.getTitle() + "</b>"))
.setContentText(song.getArtistName())
.setSubText(Html.fromHtml("<b>" + song.getAlbumName() + "</b>"))
.setOngoing(isPlaying)
.setShowWhen(false)
.addAction(previousAction)

View file

@ -1,248 +0,0 @@
package code.name.monkey.retromusic.service.notification;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.widget.RemoteViews;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import code.name.monkey.appthemehelper.util.ColorUtil;
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.glide.SongGlideRequest;
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper;
import code.name.monkey.retromusic.model.Song;
import code.name.monkey.retromusic.service.MusicService;
import code.name.monkey.retromusic.ui.activities.NowPayingActivity;
import code.name.monkey.retromusic.util.PreferenceUtil;
import code.name.monkey.retromusic.util.RetroUtil;
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor;
import static code.name.monkey.retromusic.Constants.ACTION_QUIT;
import static code.name.monkey.retromusic.Constants.ACTION_REWIND;
import static code.name.monkey.retromusic.Constants.ACTION_SKIP;
import static code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE;
import static code.name.monkey.retromusic.util.RetroUtil.createBitmap;
/**
* @author Hemanth S (h4h13).
*/
public class PlayingNotificationOreo extends PlayingNotification {
private Target<BitmapPaletteWrapper> target;
private RemoteViews getCombinedRemoteViews(boolean collapsed, Song song) {
RemoteViews remoteViews = new RemoteViews(service.getPackageName(),
collapsed ? R.layout.layout_notification_collapsed : R.layout.layout_notification_expanded);
remoteViews.setTextViewText(R.id.appName,
service.getString(R.string.app_name) + "" + song.albumName);
remoteViews.setTextViewText(R.id.title, song.title);
remoteViews.setTextViewText(R.id.subtitle, song.artistName);
TypedArray typedArray = service
.obtainStyledAttributes(new int[]{android.R.attr.selectableItemBackground});
int selectableItemBackground = typedArray.getResourceId(0, 0);
typedArray.recycle();
remoteViews.setInt(R.id.content, "setBackgroundResource", selectableItemBackground);
linkButtons(remoteViews);
//setNotificationContent(remoteViews, ColorUtil.isColorLight(backgroundColor));
return remoteViews;
}
@Override
public void update() {
stopped = false;
final Song song = service.getCurrentSong();
final boolean isPlaying = service.isPlaying();
final RemoteViews notificationLayout = getCombinedRemoteViews(true, song);
final RemoteViews notificationLayoutBig = getCombinedRemoteViews(false, song);
Intent action = new Intent(service, NowPayingActivity.class);
action.putExtra("expand", true);
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
final PendingIntent clickIntent = PendingIntent
.getActivity(service, 0, action, PendingIntent.FLAG_UPDATE_CURRENT);
final PendingIntent deleteIntent = buildPendingIntent(service, ACTION_QUIT, null);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(service,
NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(clickIntent)
.setDeleteIntent(deleteIntent)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setCustomContentView(notificationLayout)
.setCustomBigContentView(notificationLayoutBig)
.setOngoing(isPlaying);
final int bigNotificationImageSize = service.getResources()
.getDimensionPixelSize(R.dimen.notification_big_image_size);
service.runOnUiThread(new Runnable() {
@Override
public void run() {
if (target != null) {
Glide.clear(target);
}
target = SongGlideRequest.Builder.from(Glide.with(service), song)
.checkIgnoreMediaStore(service)
.generatePalette(service).build()
.into(new SimpleTarget<BitmapPaletteWrapper>(bigNotificationImageSize,
bigNotificationImageSize) {
@Override
public void onResourceReady(BitmapPaletteWrapper resource,
GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
MediaNotificationProcessor mediaNotificationProcessor = new MediaNotificationProcessor(
service, service, (i, i2) -> update(resource.getBitmap(), i, i2));
mediaNotificationProcessor.processNotification(resource.getBitmap());
}
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, errorDrawable);
update(null, Color.WHITE, Color.BLACK);
}
private void update(@Nullable Bitmap bitmap, int bgColor, int textColor) {
if (bitmap != null) {
notificationLayout.setImageViewBitmap(R.id.largeIcon, bitmap);
notificationLayoutBig.setImageViewBitmap(R.id.largeIcon, bitmap);
} else {
notificationLayout
.setImageViewResource(R.id.largeIcon, R.drawable.default_album_art);
notificationLayoutBig
.setImageViewResource(R.id.largeIcon, R.drawable.default_album_art);
}
if (!PreferenceUtil.getInstance().coloredNotification()) {
bgColor = Color.WHITE;
}
setBackgroundColor(bgColor);
setNotificationContent(ColorUtil.isColorLight(bgColor));
if (stopped) {
return; // notification has been stopped before loading was finished
}
updateNotifyModeAndPostNotification(builder.build());
}
private void setBackgroundColor(int color) {
notificationLayout.setInt(R.id.image, "setBackgroundColor", color);
notificationLayoutBig.setInt(R.id.image, "setBackgroundColor", color);
notificationLayout.setInt(R.id.foregroundImage, "setColorFilter", color);
notificationLayoutBig.setInt(R.id.foregroundImage, "setColorFilter", color);
}
private void setNotificationContent(boolean dark) {
int primary = MaterialValueHelper.getPrimaryTextColor(service, dark);
int secondary = MaterialValueHelper.getSecondaryTextColor(service, dark);
Bitmap close = createBitmap(
RetroUtil
.getTintedVectorDrawable(service, R.drawable.ic_close_white_24dp, primary),
NOTIFICATION_CONTROLS_SIZE_MULTIPLIER);
Bitmap prev = createBitmap(
RetroUtil
.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp,
primary), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER);
Bitmap next = createBitmap(
RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp,
primary), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER);
Bitmap playPause = createBitmap(RetroUtil.getTintedVectorDrawable(service,
isPlaying ? R.drawable.ic_pause_white_24dp
: R.drawable.ic_play_arrow_white_24dp, primary),
NOTIFICATION_CONTROLS_SIZE_MULTIPLIER);
notificationLayout.setTextColor(R.id.title, primary);
notificationLayout.setTextColor(R.id.subtitle, secondary);
notificationLayout.setTextColor(R.id.appName, secondary);
notificationLayout.setImageViewBitmap(R.id.action_prev, prev);
notificationLayout.setImageViewBitmap(R.id.action_next, next);
notificationLayout.setImageViewBitmap(R.id.action_play_pause, playPause);
notificationLayoutBig.setTextColor(R.id.title, primary);
notificationLayoutBig.setTextColor(R.id.subtitle, secondary);
notificationLayoutBig.setTextColor(R.id.appName, secondary);
notificationLayoutBig.setImageViewBitmap(R.id.action_quit, close);
notificationLayoutBig.setImageViewBitmap(R.id.action_prev, prev);
notificationLayoutBig.setImageViewBitmap(R.id.action_next, next);
notificationLayoutBig.setImageViewBitmap(R.id.action_play_pause, playPause);
notificationLayout.setImageViewBitmap(R.id.smallIcon,
createBitmap(RetroUtil
.getTintedVectorDrawable(service, R.drawable.ic_notification, secondary),
0.6f));
notificationLayoutBig.setImageViewBitmap(R.id.smallIcon,
createBitmap(RetroUtil
.getTintedVectorDrawable(service, R.drawable.ic_notification, secondary),
0.6f));
notificationLayout.setInt(R.id.arrow, "setColorFilter", secondary);
notificationLayoutBig.setInt(R.id.arrow, "setColorFilter", secondary);
}
});
}
});
if (stopped) {
return; // notification has been stopped before loading was finished
}
updateNotifyModeAndPostNotification(builder.build());
}
private PendingIntent buildPendingIntent(Context context, final String action,
final ComponentName serviceName) {
Intent intent = new Intent(action);
intent.setComponent(serviceName);
return PendingIntent.getService(context, 0, intent, 0);
}
private void linkButtons(final RemoteViews notificationLayout) {
PendingIntent pendingIntent;
final ComponentName serviceName = new ComponentName(service, MusicService.class);
// Previous track
pendingIntent = buildPendingIntent(service, ACTION_REWIND, serviceName);
notificationLayout.setOnClickPendingIntent(R.id.action_prev, pendingIntent);
// Play and pause
pendingIntent = buildPendingIntent(service, ACTION_TOGGLE_PAUSE, serviceName);
notificationLayout.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent);
// Next track
pendingIntent = buildPendingIntent(service, ACTION_SKIP, serviceName);
notificationLayout.setOnClickPendingIntent(R.id.action_next, pendingIntent);
// Close
pendingIntent = buildPendingIntent(service, ACTION_QUIT, serviceName);
notificationLayout.setOnClickPendingIntent(R.id.action_quit, pendingIntent);
}
}

View file

@ -0,0 +1,221 @@
package code.name.monkey.retromusic.service.notification
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.Constants.ACTION_QUIT
import code.name.monkey.retromusic.Constants.ACTION_REWIND
import code.name.monkey.retromusic.Constants.ACTION_SKIP
import code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.ui.activities.MainActivity
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.RetroUtil.createBitmap
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import com.bumptech.glide.request.animation.GlideAnimation
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.target.Target
/**
* @author Hemanth S (h4h13).
*/
class PlayingNotificationOreo : PlayingNotification() {
private var target: Target<BitmapPaletteWrapper>? = null
private fun getCombinedRemoteViews(collapsed: Boolean, song: Song): RemoteViews {
val remoteViews = RemoteViews(service.packageName,
if (collapsed) R.layout.layout_notification_collapsed else R.layout.layout_notification_expanded)
remoteViews.setTextViewText(R.id.appName, service.getString(R.string.app_name) + "" + song.albumName)
remoteViews.setTextViewText(R.id.title, song.title)
remoteViews.setTextViewText(R.id.subtitle, song.artistName)
val typedArray = service.obtainStyledAttributes(intArrayOf(android.R.attr.selectableItemBackground))
val selectableItemBackground = typedArray.getResourceId(0, 0)
typedArray.recycle()
remoteViews.setInt(R.id.content, "setBackgroundResource", selectableItemBackground)
linkButtons(remoteViews)
//setNotificationContent(remoteViews, ColorUtil.isColorLight(backgroundColor));
return remoteViews
}
override fun update() {
stopped = false
val song = service.currentSong
val isPlaying = service.isPlaying
val notificationLayout = getCombinedRemoteViews(true, song)
val notificationLayoutBig = getCombinedRemoteViews(false, song)
val action = Intent(service, MainActivity::class.java)
action.putExtra("expand", true)
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val clickIntent = PendingIntent
.getActivity(service, 0, action, PendingIntent.FLAG_UPDATE_CURRENT)
val deleteIntent = buildPendingIntent(service, ACTION_QUIT, null)
val builder = NotificationCompat.Builder(service,
PlayingNotification.NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(clickIntent)
.setDeleteIntent(deleteIntent)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setCustomContentView(notificationLayout)
.setCustomBigContentView(notificationLayoutBig)
.setOngoing(isPlaying)
val bigNotificationImageSize = service.resources
.getDimensionPixelSize(R.dimen.notification_big_image_size)
service.runOnUiThread(Runnable {
if (target != null) {
Glide.clear(target!!)
}
target = SongGlideRequest.Builder.from(Glide.with(service), song)
.checkIgnoreMediaStore(service)
.generatePalette(service).build()
.into(object : SimpleTarget<BitmapPaletteWrapper>(bigNotificationImageSize,
bigNotificationImageSize) {
override fun onResourceReady(resource: BitmapPaletteWrapper,
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>) {
val mediaNotificationProcessor = MediaNotificationProcessor(
service, service) { i, _ -> update(resource.bitmap, i) }
mediaNotificationProcessor.processNotification(resource.bitmap)
}
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
super.onLoadFailed(e, errorDrawable)
update(null, Color.WHITE)
}
private fun update(bitmap: Bitmap?, bgColor: Int) {
var bgColorFinal = bgColor
if (bitmap != null) {
notificationLayout.setImageViewBitmap(R.id.largeIcon, bitmap)
notificationLayoutBig.setImageViewBitmap(R.id.largeIcon, bitmap)
} else {
notificationLayout.setImageViewResource(R.id.largeIcon, R.drawable.default_album_art)
notificationLayoutBig.setImageViewResource(R.id.largeIcon, R.drawable.default_album_art)
}
if (!PreferenceUtil.getInstance().coloredNotification()) {
bgColorFinal = Color.WHITE
}
setBackgroundColor(bgColorFinal)
setNotificationContent(ColorUtil.isColorLight(bgColorFinal))
if (stopped) {
return // notification has been stopped before loading was finished
}
updateNotifyModeAndPostNotification(builder.build())
}
private fun setBackgroundColor(color: Int) {
notificationLayout.setInt(R.id.image, "setBackgroundColor", color)
notificationLayoutBig.setInt(R.id.image, "setBackgroundColor", color)
notificationLayout.setInt(R.id.foregroundImage, "setColorFilter", color)
notificationLayoutBig.setInt(R.id.foregroundImage, "setColorFilter", color)
}
private fun setNotificationContent(dark: Boolean) {
val primary = MaterialValueHelper.getPrimaryTextColor(service, dark)
val secondary = MaterialValueHelper.getSecondaryTextColor(service, dark)
val close = createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_close_white_24dp, primary)!!, PlayingNotification.NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
val prev = createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, primary)!!, PlayingNotification.NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
val next = createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, primary)!!, PlayingNotification.NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
val playPause = createBitmap(RetroUtil.getTintedVectorDrawable(service,
if (isPlaying)
R.drawable.ic_pause_white_24dp
else
R.drawable.ic_play_arrow_white_24dp, primary)!!, PlayingNotification.NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
notificationLayout.setTextColor(R.id.title, primary)
notificationLayout.setTextColor(R.id.subtitle, secondary)
notificationLayout.setTextColor(R.id.appName, secondary)
notificationLayout.setImageViewBitmap(R.id.action_prev, prev)
notificationLayout.setImageViewBitmap(R.id.action_next, next)
notificationLayout.setImageViewBitmap(R.id.action_play_pause, playPause)
notificationLayoutBig.setTextColor(R.id.title, primary)
notificationLayoutBig.setTextColor(R.id.subtitle, secondary)
notificationLayoutBig.setTextColor(R.id.appName, secondary)
notificationLayoutBig.setImageViewBitmap(R.id.action_quit, close)
notificationLayoutBig.setImageViewBitmap(R.id.action_prev, prev)
notificationLayoutBig.setImageViewBitmap(R.id.action_next, next)
notificationLayoutBig.setImageViewBitmap(R.id.action_play_pause, playPause)
notificationLayout.setImageViewBitmap(R.id.smallIcon, createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_notification, secondary)!!, 0.6f))
notificationLayoutBig.setImageViewBitmap(R.id.smallIcon, createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_notification, secondary)!!, 0.6f))
notificationLayout.setInt(R.id.arrow, "setColorFilter", secondary)
notificationLayoutBig.setInt(R.id.arrow, "setColorFilter", secondary)
}
})
})
if (stopped) {
return // notification has been stopped before loading was finished
}
updateNotifyModeAndPostNotification(builder.build())
}
private fun buildPendingIntent(context: Context, action: String,
serviceName: ComponentName?): PendingIntent {
val intent = Intent(action)
intent.component = serviceName
return PendingIntent.getService(context, 0, intent, 0)
}
private fun linkButtons(notificationLayout: RemoteViews) {
var pendingIntent: PendingIntent
val serviceName = ComponentName(service, MusicService::class.java)
// Previous track
pendingIntent = buildPendingIntent(service, ACTION_REWIND, serviceName)
notificationLayout.setOnClickPendingIntent(R.id.action_prev, pendingIntent)
// Play and pause
pendingIntent = buildPendingIntent(service, ACTION_TOGGLE_PAUSE, serviceName)
notificationLayout.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent)
// Next track
pendingIntent = buildPendingIntent(service, ACTION_SKIP, serviceName)
notificationLayout.setOnClickPendingIntent(R.id.action_next, pendingIntent)
// Close
pendingIntent = buildPendingIntent(service, ACTION_QUIT, serviceName)
notificationLayout.setOnClickPendingIntent(R.id.action_quit, pendingIntent)
}
}