/*
* Copyright (C) 2014 Fastboot Mobile, LLC.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, see <http://www.gnu.org/licenses>.
*/
package com.fastbootmobile.encore.service;
import android.animation.Animator;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import com.fastbootmobile.encore.app.DriveModeActivity;
import com.fastbootmobile.encore.app.R;
import com.fastbootmobile.encore.app.ui.AlbumArtImageView;
import com.fastbootmobile.encore.framework.PlaybackProxy;
import com.fastbootmobile.encore.model.Song;
public class NavHeadService extends Service {
private static final String TAG = "NavHeadService";
private static final String PREFS = "NAVHEAD";
private static final String PREF_HEAD_X = "head_x_";
private static final String PREF_HEAD_Y = "head_y_";
private WindowManager mWindowManager;
private AlbumArtImageView mHeadView;
private WindowManager.LayoutParams mHeadLayoutParams;
private Handler mHandler;
private BasePlaybackCallback mPlaybackCallback = new BasePlaybackCallback() {
@Override
public void onSongStarted(boolean buffering, final Song s) throws RemoteException {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mHeadView != null) {
mHeadView.loadArtForSong(s);
}
}
});
}
};
public NavHeadService() {
}
@Override
public IBinder onBind(Intent intent) {
// Not used
return null;
}
@Override
public void onCreate() {
super.onCreate();
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mHandler = new Handler();
createHead();
loadHeadPosition();
PlaybackProxy.addCallback(mPlaybackCallback);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
loadHeadPosition();
}
@Override
public void onDestroy() {
super.onDestroy();
PlaybackProxy.removeCallback(mPlaybackCallback);
if (mHeadView != null) {
mHeadView.animate().scaleX(0.5f).scaleY(0.5f).alpha(0.0f).setDuration(500)
.setInterpolator(new AccelerateDecelerateInterpolator())
.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
mWindowManager.removeView(mHeadView);
}
@Override
public void onAnimationCancel(Animator animation) {
mWindowManager.removeView(mHeadView);
}
@Override
public void onAnimationRepeat(Animator animation) {
}
}).start();
}
}
private void createHead() {
mHeadView = new AlbumArtImageView(this);
mHeadView.setCrossfade(true);
mHeadView.setScaleX(0.5f);
mHeadView.setScaleY(0.5f);
mHeadView.setAlpha(0.0f);
mHeadView.animate().scaleX(1.0f).scaleY(1.0f).alpha(1.0f)
.setDuration(500).setInterpolator(new AccelerateDecelerateInterpolator()).start();
mHeadLayoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
mWindowManager.addView(mHeadView, mHeadLayoutParams);
mHeadView.setOnTouchListener(new View.OnTouchListener() {
private int mDownX;
private int mDownY;
private float mRawDownX;
private float mRawDownY;
private int mTotalMovedX;
private int mTotalMovedY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = mHeadLayoutParams.x;
mDownY = mHeadLayoutParams.y;
mRawDownX = event.getRawX();
mRawDownY = event.getRawY();
return true;
case MotionEvent.ACTION_UP:
if (mTotalMovedX > 10 || mTotalMovedY > 10) {
saveHeadPosition();
} else {
v.callOnClick();
}
return true;
case MotionEvent.ACTION_MOVE:
int deltaX = (int) (event.getRawX() - mRawDownX);
int deltaY = (int) (event.getRawY() - mRawDownY);
setHeadPosition(mDownX + deltaX, mDownY + deltaY);
mTotalMovedX += Math.abs(deltaX);
mTotalMovedY += Math.abs(deltaY);
return true;
}
return false;
}
});
mHeadView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getBaseContext(), DriveModeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
// Assign initial album art
Song currentSong = PlaybackProxy.getCurrentTrack();
if (currentSong != null) {
mHeadView.loadArtForSong(currentSong);
}
}
private void loadHeadPosition() {
final int rotation = mWindowManager.getDefaultDisplay().getRotation();
// Load position from shared preferences
SharedPreferences prefs = getSharedPreferences(PREFS, Context.MODE_PRIVATE);
int headX = prefs.getInt(PREF_HEAD_X + rotation, 0);
int headY = prefs.getInt(PREF_HEAD_Y + rotation, 100);
setHeadPosition(headX, headY);
}
private void saveHeadPosition() {
final int rotation = mWindowManager.getDefaultDisplay().getRotation();
// Save position into shared preferences
SharedPreferences prefs = getSharedPreferences(PREFS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(PREF_HEAD_X + rotation, mHeadLayoutParams.x);
editor.putInt(PREF_HEAD_Y + rotation, mHeadLayoutParams.y);
editor.apply();
}
public void setHeadPosition(int x, int y) {
final int sizePx = getResources().getDimensionPixelSize(R.dimen.nav_head_size);
mHeadLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
mHeadLayoutParams.x = x;
mHeadLayoutParams.y = y;
mHeadLayoutParams.width = sizePx;
mHeadLayoutParams.height = sizePx;
mWindowManager.updateViewLayout(mHeadView, mHeadLayoutParams);
}
}