Shake actions
Also moves Action into its own file since it is now also used in PlaybackService
This commit is contained in:
parent
7a34f5db51
commit
44897e85d2
37
res/layout/shake_pref.xml
Normal file
37
res/layout/shake_pref.xml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
-->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/value"
|
||||||
|
android:padding="5dip"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="right" />
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/seek_bar"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</LinearLayout>
|
@ -159,6 +159,12 @@ THE SOFTWARE.
|
|||||||
<string name="default_action_title">Default Action</string>
|
<string name="default_action_title">Default Action</string>
|
||||||
<string name="default_playlist_action_title">Default Playlist Action</string>
|
<string name="default_playlist_action_title">Default Playlist Action</string>
|
||||||
|
|
||||||
|
<string name="pref_shake">Accelerometer Shake</string>
|
||||||
|
<string name="enable_shake_title">Enable Accelerometer Shake</string>
|
||||||
|
<string name="enable_shake_summary">Only active when music is playing. Does not work when screen is off on some devices.</string>
|
||||||
|
<string name="shake_action_title">Accelerometer Shake Action</string>
|
||||||
|
<string name="shake_threshold_title">Shake Force Threshold</string>
|
||||||
|
|
||||||
<string name="pref_misc">Miscellaneous Features</string>
|
<string name="pref_misc">Miscellaneous Features</string>
|
||||||
<string name="disable_lockscreen_title">Disable Lockscreen</string>
|
<string name="disable_lockscreen_title">Disable Lockscreen</string>
|
||||||
<string name="disable_lockscreen_summary">Do not show the lockscreen with the library screen or playback screen open.</string>
|
<string name="disable_lockscreen_summary">Do not show the lockscreen with the library screen or playback screen open.</string>
|
||||||
|
@ -123,6 +123,27 @@ THE SOFTWARE.
|
|||||||
android:entryValues="@array/entry_values"
|
android:entryValues="@array/entry_values"
|
||||||
android:defaultValue="3" />
|
android:defaultValue="3" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory android:title="@string/pref_shake">
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="enable_shake"
|
||||||
|
android:title="@string/enable_shake_title"
|
||||||
|
android:summary="@string/enable_shake_summary"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
<org.kreed.vanilla.ListPreferenceSummary
|
||||||
|
android:key="shake_action"
|
||||||
|
android:title="@string/shake_action_title"
|
||||||
|
android:entries="@array/swipe_action_entries"
|
||||||
|
android:entryValues="@array/swipe_action_values"
|
||||||
|
android:defaultValue="NextSong"
|
||||||
|
android:dependency="enable_shake" />
|
||||||
|
<!-- Might be nice to show something indicating the current shake force for this preference. -->
|
||||||
|
<org.kreed.vanilla.ShakeThresholdPreference
|
||||||
|
android:key="shake_threshold"
|
||||||
|
android:negativeButtonText="@null"
|
||||||
|
android:dialogLayout="@layout/shake_pref"
|
||||||
|
android:title="@string/shake_threshold_title"
|
||||||
|
android:dependency="enable_shake" />
|
||||||
|
</PreferenceCategory>
|
||||||
<PreferenceCategory android:title="@string/pref_misc">
|
<PreferenceCategory android:title="@string/pref_misc">
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="disable_lockscreen"
|
android:key="disable_lockscreen"
|
||||||
|
107
src/org/kreed/vanilla/Action.java
Normal file
107
src/org/kreed/vanilla/Action.java
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.kreed.vanilla;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various actions that can be passed to {@link PlaybackService#performAction(Action, PlaybackActivity)}.
|
||||||
|
*/
|
||||||
|
enum Action {
|
||||||
|
/**
|
||||||
|
* Dummy action: do nothing.
|
||||||
|
*/
|
||||||
|
Nothing,
|
||||||
|
/**
|
||||||
|
* Open the library activity.
|
||||||
|
*/
|
||||||
|
Library,
|
||||||
|
/**
|
||||||
|
* If playing music, pause. Otherwise, start playing.
|
||||||
|
*/
|
||||||
|
PlayPause,
|
||||||
|
/**
|
||||||
|
* Skip to the next song.
|
||||||
|
*/
|
||||||
|
NextSong,
|
||||||
|
/**
|
||||||
|
* Go back to the previous song.
|
||||||
|
*/
|
||||||
|
PreviousSong,
|
||||||
|
/**
|
||||||
|
* Skip to the first song from the next album.
|
||||||
|
*/
|
||||||
|
NextAlbum,
|
||||||
|
/**
|
||||||
|
* Skip to the last song from the previous album.
|
||||||
|
*/
|
||||||
|
PreviousAlbum,
|
||||||
|
/**
|
||||||
|
* Cycle the repeat mode.
|
||||||
|
*/
|
||||||
|
Repeat,
|
||||||
|
/**
|
||||||
|
* Cycle the shuffle mode.
|
||||||
|
*/
|
||||||
|
Shuffle,
|
||||||
|
/**
|
||||||
|
* Enqueue the rest of the current album.
|
||||||
|
*/
|
||||||
|
EnqueueAlbum,
|
||||||
|
/**
|
||||||
|
* Enqueue the rest of the songs by the current artist.
|
||||||
|
*/
|
||||||
|
EnqueueArtist,
|
||||||
|
/**
|
||||||
|
* Enqueue the rest of the songs in the current genre.
|
||||||
|
*/
|
||||||
|
EnqueueGenre,
|
||||||
|
/**
|
||||||
|
* Clear the queue of all remaining songs.
|
||||||
|
*/
|
||||||
|
ClearQueue,
|
||||||
|
/**
|
||||||
|
* Toggle the controls in the playback activity.
|
||||||
|
*/
|
||||||
|
ToggleControls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an action from the given SharedPreferences.
|
||||||
|
*
|
||||||
|
* @param prefs The SharedPreferences instance to load from.
|
||||||
|
* @param key The preference key to load.
|
||||||
|
* @param def The value to return if the key is not found or cannot be loaded.
|
||||||
|
* @return The loaded action or def if no action could be loaded.
|
||||||
|
*/
|
||||||
|
public static Action getAction(SharedPreferences prefs, String key, Action def)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
String pref = prefs.getString(key, null);
|
||||||
|
if (pref == null)
|
||||||
|
return def;
|
||||||
|
return Enum.valueOf(Action.class, pref);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -177,8 +177,8 @@ public class FullPlaybackActivity extends PlaybackActivity
|
|||||||
startActivity(new Intent(this, FullPlaybackActivity.class));
|
startActivity(new Intent(this, FullPlaybackActivity.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
mCoverPressAction = getAction(settings, "cover_press_action", Action.ToggleControls);
|
mCoverPressAction = Action.getAction(settings, "cover_press_action", Action.ToggleControls);
|
||||||
mCoverLongPressAction = getAction(settings, "cover_longpress_action", Action.PlayPause);
|
mCoverLongPressAction = Action.getAction(settings, "cover_longpress_action", Action.PlayPause);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -435,14 +435,13 @@ public class FullPlaybackActivity extends PlaybackActivity
|
|||||||
mSeekBarTracking = false;
|
mSeekBarTracking = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void performAction(Action action)
|
public void performAction(Action action)
|
||||||
{
|
{
|
||||||
if (action == Action.ToggleControls) {
|
if (action == Action.ToggleControls) {
|
||||||
setControlsVisible(!mControlsVisible);
|
setControlsVisible(!mControlsVisible);
|
||||||
mHandler.sendEmptyMessage(MSG_SAVE_CONTROLS);
|
mHandler.sendEmptyMessage(MSG_SAVE_CONTROLS);
|
||||||
} else {
|
} else {
|
||||||
super.performAction(action);
|
PlaybackService.get(this).performAction(action, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,23 +52,6 @@ public class PlaybackActivity extends Activity
|
|||||||
View.OnClickListener,
|
View.OnClickListener,
|
||||||
CoverView.Callback
|
CoverView.Callback
|
||||||
{
|
{
|
||||||
enum Action {
|
|
||||||
Nothing,
|
|
||||||
Library,
|
|
||||||
PlayPause,
|
|
||||||
NextSong,
|
|
||||||
PreviousSong,
|
|
||||||
NextAlbum,
|
|
||||||
PreviousAlbum,
|
|
||||||
Repeat,
|
|
||||||
Shuffle,
|
|
||||||
EnqueueAlbum,
|
|
||||||
EnqueueArtist,
|
|
||||||
EnqueueGenre,
|
|
||||||
ClearQueue,
|
|
||||||
ToggleControls,
|
|
||||||
}
|
|
||||||
|
|
||||||
private Action mUpAction;
|
private Action mUpAction;
|
||||||
private Action mDownAction;
|
private Action mDownAction;
|
||||||
|
|
||||||
@ -119,26 +102,6 @@ public class PlaybackActivity extends Activity
|
|||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve an action from the given SharedPreferences.
|
|
||||||
*
|
|
||||||
* @param prefs The SharedPreferences instance to load from.
|
|
||||||
* @param key The preference key.
|
|
||||||
* @param def The value to return if the key is not found or cannot be loaded.
|
|
||||||
* @return An action
|
|
||||||
*/
|
|
||||||
public static Action getAction(SharedPreferences prefs, String key, Action def)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
String pref = prefs.getString(key, null);
|
|
||||||
if (pref == null)
|
|
||||||
return def;
|
|
||||||
return Enum.valueOf(Action.class, pref);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart()
|
public void onStart()
|
||||||
{
|
{
|
||||||
@ -150,8 +113,8 @@ public class PlaybackActivity extends Activity
|
|||||||
startService(new Intent(this, PlaybackService.class));
|
startService(new Intent(this, PlaybackService.class));
|
||||||
|
|
||||||
SharedPreferences prefs = PlaybackService.getSettings(this);
|
SharedPreferences prefs = PlaybackService.getSettings(this);
|
||||||
mUpAction = getAction(prefs, "swipe_up_action", Action.Nothing);
|
mUpAction = Action.getAction(prefs, "swipe_up_action", Action.Nothing);
|
||||||
mDownAction = getAction(prefs, "swipe_down_action", Action.Nothing);
|
mDownAction = Action.getAction(prefs, "swipe_down_action", Action.Nothing);
|
||||||
|
|
||||||
Window window = getWindow();
|
Window window = getWindow();
|
||||||
if (prefs.getBoolean("disable_lockscreen", false))
|
if (prefs.getBoolean("disable_lockscreen", false))
|
||||||
@ -411,63 +374,16 @@ public class PlaybackActivity extends Activity
|
|||||||
PlaybackService.get(this).enqueueFromCurrent(type);
|
PlaybackService.get(this).enqueueFromCurrent(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void performAction(Action action)
|
|
||||||
{
|
|
||||||
switch (action) {
|
|
||||||
case Nothing:
|
|
||||||
break;
|
|
||||||
case Library:
|
|
||||||
openLibrary(null);
|
|
||||||
break;
|
|
||||||
case PlayPause:
|
|
||||||
playPause();
|
|
||||||
break;
|
|
||||||
case NextSong:
|
|
||||||
shiftCurrentSong(SongTimeline.SHIFT_NEXT_SONG);
|
|
||||||
break;
|
|
||||||
case PreviousSong:
|
|
||||||
shiftCurrentSong(SongTimeline.SHIFT_PREVIOUS_SONG);
|
|
||||||
break;
|
|
||||||
case NextAlbum:
|
|
||||||
shiftCurrentSong(SongTimeline.SHIFT_NEXT_ALBUM);
|
|
||||||
break;
|
|
||||||
case PreviousAlbum:
|
|
||||||
shiftCurrentSong(SongTimeline.SHIFT_PREVIOUS_ALBUM);
|
|
||||||
break;
|
|
||||||
case Repeat:
|
|
||||||
cycleFinishAction();
|
|
||||||
break;
|
|
||||||
case Shuffle:
|
|
||||||
cycleShuffle();
|
|
||||||
break;
|
|
||||||
case EnqueueAlbum:
|
|
||||||
enqueue(MediaUtils.TYPE_ALBUM);
|
|
||||||
break;
|
|
||||||
case EnqueueArtist:
|
|
||||||
enqueue(MediaUtils.TYPE_ARTIST);
|
|
||||||
break;
|
|
||||||
case EnqueueGenre:
|
|
||||||
enqueue(MediaUtils.TYPE_GENRE);
|
|
||||||
break;
|
|
||||||
case ClearQueue:
|
|
||||||
PlaybackService.get(this).clearQueue();
|
|
||||||
Toast.makeText(this, R.string.queue_cleared, Toast.LENGTH_SHORT).show();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Invalid action: " + action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void upSwipe()
|
public void upSwipe()
|
||||||
{
|
{
|
||||||
performAction(mUpAction);
|
PlaybackService.get(this).performAction(mUpAction, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void downSwipe()
|
public void downSwipe()
|
||||||
{
|
{
|
||||||
performAction(mDownAction);
|
PlaybackService.get(this).performAction(mDownAction, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int GROUP_SHUFFLE = 100;
|
private static final int GROUP_SHUFFLE = 100;
|
||||||
|
@ -37,6 +37,10 @@ import android.content.res.TypedArray;
|
|||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEvent;
|
||||||
|
import android.hardware.SensorEventListener;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@ -70,6 +74,7 @@ public final class PlaybackService extends Service
|
|||||||
, MediaPlayer.OnErrorListener
|
, MediaPlayer.OnErrorListener
|
||||||
, SharedPreferences.OnSharedPreferenceChangeListener
|
, SharedPreferences.OnSharedPreferenceChangeListener
|
||||||
, SongTimeline.Callback
|
, SongTimeline.Callback
|
||||||
|
, SensorEventListener
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Name of the state file.
|
* Name of the state file.
|
||||||
@ -269,6 +274,10 @@ public final class PlaybackService extends Service
|
|||||||
private PowerManager.WakeLock mWakeLock;
|
private PowerManager.WakeLock mWakeLock;
|
||||||
private NotificationManager mNotificationManager;
|
private NotificationManager mNotificationManager;
|
||||||
private AudioManager mAudioManager;
|
private AudioManager mAudioManager;
|
||||||
|
/**
|
||||||
|
* The SensorManager service.
|
||||||
|
*/
|
||||||
|
private SensorManager mSensorManager;
|
||||||
|
|
||||||
SongTimeline mTimeline;
|
SongTimeline mTimeline;
|
||||||
private Song mCurrentSong;
|
private Song mCurrentSong;
|
||||||
@ -308,6 +317,32 @@ public final class PlaybackService extends Service
|
|||||||
*/
|
*/
|
||||||
private boolean mDuckedLoss;
|
private boolean mDuckedLoss;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum time in milliseconds between shake actions.
|
||||||
|
*/
|
||||||
|
private static final int MIN_SHAKE_PERIOD = 500;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magnitude of last sensed acceleration.
|
||||||
|
*/
|
||||||
|
private float mAccelLast;
|
||||||
|
/**
|
||||||
|
* Filtered acceleration used for shake detection.
|
||||||
|
*/
|
||||||
|
private float mAccelFiltered;
|
||||||
|
/**
|
||||||
|
* Elapsed realtime of last shake action.
|
||||||
|
*/
|
||||||
|
private long mLastShakeTime;
|
||||||
|
/**
|
||||||
|
* Minimum jerk required for shake.
|
||||||
|
*/
|
||||||
|
private float mShakeThreshold;
|
||||||
|
/**
|
||||||
|
* What to do when an accelerometer shake is detected.
|
||||||
|
*/
|
||||||
|
private Action mShakeAction;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate()
|
public void onCreate()
|
||||||
{
|
{
|
||||||
@ -325,6 +360,7 @@ public final class PlaybackService extends Service
|
|||||||
|
|
||||||
mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
||||||
mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
|
mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
|
||||||
|
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
|
||||||
CompatFroyo.createAudioFocus();
|
CompatFroyo.createAudioFocus();
|
||||||
@ -347,6 +383,8 @@ public final class PlaybackService extends Service
|
|||||||
mInvertNotification = settings.getBoolean("notification_inverted_color", false);
|
mInvertNotification = settings.getBoolean("notification_inverted_color", false);
|
||||||
mNotificationAction = createNotificationAction(settings);
|
mNotificationAction = createNotificationAction(settings);
|
||||||
mHeadsetPause = getSettings(this).getBoolean("headset_pause", true);
|
mHeadsetPause = getSettings(this).getBoolean("headset_pause", true);
|
||||||
|
mShakeAction = settings.getBoolean("enable_shake", false) ? Action.getAction(settings, "shake_action", Action.NextSong) : Action.Nothing;
|
||||||
|
mShakeThreshold = settings.getInt("shake_threshold", 80) / 10.0f;
|
||||||
|
|
||||||
PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
|
PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
|
||||||
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "VanillaMusicLock");
|
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "VanillaMusicLock");
|
||||||
@ -380,6 +418,10 @@ public final class PlaybackService extends Service
|
|||||||
synchronized (sWait) {
|
synchronized (sWait) {
|
||||||
sWait.notifyAll();
|
sWait.notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mAccelFiltered = 0.0f;
|
||||||
|
mAccelLast = SensorManager.GRAVITY_EARTH;
|
||||||
|
setupSensor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -456,6 +498,9 @@ public final class PlaybackService extends Service
|
|||||||
// we haven't registered the receiver yet
|
// we haven't registered the receiver yet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mShakeAction != Action.Nothing)
|
||||||
|
mSensorManager.unregisterListener(this);
|
||||||
|
|
||||||
if (mWakeLock != null && mWakeLock.isHeld())
|
if (mWakeLock != null && mWakeLock.isHeld())
|
||||||
mWakeLock.release();
|
mWakeLock.release();
|
||||||
|
|
||||||
@ -473,6 +518,17 @@ public final class PlaybackService extends Service
|
|||||||
return sSettings;
|
return sSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the accelerometer.
|
||||||
|
*/
|
||||||
|
private void setupSensor()
|
||||||
|
{
|
||||||
|
if (mShakeAction == Action.Nothing || (mState & FLAG_PLAYING) == 0)
|
||||||
|
mSensorManager.unregisterListener(this);
|
||||||
|
else
|
||||||
|
mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
|
||||||
|
}
|
||||||
|
|
||||||
private void loadPreference(String key)
|
private void loadPreference(String key)
|
||||||
{
|
{
|
||||||
SharedPreferences settings = getSettings(this);
|
SharedPreferences settings = getSettings(this);
|
||||||
@ -515,6 +571,11 @@ public final class PlaybackService extends Service
|
|||||||
mStockBroadcast = settings.getBoolean(key, false);
|
mStockBroadcast = settings.getBoolean(key, false);
|
||||||
} else if ("headset_play".equals(key)) {
|
} else if ("headset_play".equals(key)) {
|
||||||
mHeadsetPlay = settings.getBoolean(key, false);
|
mHeadsetPlay = settings.getBoolean(key, false);
|
||||||
|
} else if ("enable_shake".equals(key) || "shake_action".equals(key)) {
|
||||||
|
mShakeAction = settings.getBoolean("enable_shake", false) ? Action.getAction(settings, "shake_action", Action.NextSong) : Action.Nothing;
|
||||||
|
setupSensor();
|
||||||
|
} else if ("shake_threshold".equals(key)) {
|
||||||
|
mShakeThreshold = settings.getInt("shake_threshold", 80) / 10.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
|
||||||
@ -603,6 +664,8 @@ public final class PlaybackService extends Service
|
|||||||
if (mWakeLock != null && mWakeLock.isHeld())
|
if (mWakeLock != null && mWakeLock.isHeld())
|
||||||
mWakeLock.release();
|
mWakeLock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupSensor();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((toggled & FLAG_NO_MEDIA) != 0 && (state & FLAG_NO_MEDIA) != 0) {
|
if ((toggled & FLAG_NO_MEDIA) != 0 && (state & FLAG_NO_MEDIA) != 0) {
|
||||||
@ -1547,4 +1610,114 @@ public final class PlaybackService extends Service
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSensorChanged(SensorEvent se)
|
||||||
|
{
|
||||||
|
double x = se.values[0];
|
||||||
|
double y = se.values[1];
|
||||||
|
double z = se.values[2];
|
||||||
|
|
||||||
|
float accel = (float)Math.sqrt(x*x + y*y + z*z);
|
||||||
|
float delta = accel - mAccelLast;
|
||||||
|
mAccelLast = accel;
|
||||||
|
|
||||||
|
float filtered = mAccelFiltered * 0.9f + delta;
|
||||||
|
mAccelFiltered = filtered;
|
||||||
|
|
||||||
|
if (filtered > mShakeThreshold) {
|
||||||
|
long now = SystemClock.elapsedRealtime();
|
||||||
|
if (now - mLastShakeTime > MIN_SHAKE_PERIOD) {
|
||||||
|
mLastShakeTime = now;
|
||||||
|
performAction(mShakeAction, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAccuracyChanged(Sensor sensor, int accuracy)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the given action.
|
||||||
|
*
|
||||||
|
* @param action The action to execute.
|
||||||
|
* @param receiver Optional. If non-null, update the PlaybackActivity with
|
||||||
|
* new song or state from the executed action. The activity will still be
|
||||||
|
* updated by the broadcast if not passed here; passing it just makes the
|
||||||
|
* update immediate.
|
||||||
|
*/
|
||||||
|
public void performAction(Action action, PlaybackActivity receiver)
|
||||||
|
{
|
||||||
|
switch (action) {
|
||||||
|
case Nothing:
|
||||||
|
break;
|
||||||
|
case Library:
|
||||||
|
Intent intent = new Intent(this, LibraryActivity.class);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
startActivity(intent);
|
||||||
|
break;
|
||||||
|
case PlayPause: {
|
||||||
|
int state = playPause();
|
||||||
|
if (receiver != null)
|
||||||
|
receiver.setState(state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NextSong: {
|
||||||
|
Song song = shiftCurrentSong(SongTimeline.SHIFT_NEXT_SONG);
|
||||||
|
if (receiver != null)
|
||||||
|
receiver.setSong(song);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PreviousSong: {
|
||||||
|
Song song = shiftCurrentSong(SongTimeline.SHIFT_PREVIOUS_SONG);
|
||||||
|
if (receiver != null)
|
||||||
|
receiver.setSong(song);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NextAlbum: {
|
||||||
|
Song song = shiftCurrentSong(SongTimeline.SHIFT_NEXT_ALBUM);
|
||||||
|
if (receiver != null)
|
||||||
|
receiver.setSong(song);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PreviousAlbum: {
|
||||||
|
Song song = shiftCurrentSong(SongTimeline.SHIFT_PREVIOUS_ALBUM);
|
||||||
|
if (receiver != null)
|
||||||
|
receiver.setSong(song);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Repeat: {
|
||||||
|
int state = cycleFinishAction();
|
||||||
|
if (receiver != null)
|
||||||
|
receiver.setState(state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Shuffle: {
|
||||||
|
int state = cycleShuffle();
|
||||||
|
if (receiver != null)
|
||||||
|
receiver.setState(state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EnqueueAlbum:
|
||||||
|
enqueueFromCurrent(MediaUtils.TYPE_ALBUM);
|
||||||
|
break;
|
||||||
|
case EnqueueArtist:
|
||||||
|
enqueueFromCurrent(MediaUtils.TYPE_ARTIST);
|
||||||
|
break;
|
||||||
|
case EnqueueGenre:
|
||||||
|
enqueueFromCurrent(MediaUtils.TYPE_GENRE);
|
||||||
|
break;
|
||||||
|
case ClearQueue:
|
||||||
|
clearQueue();
|
||||||
|
Toast.makeText(this, R.string.queue_cleared, Toast.LENGTH_SHORT).show();
|
||||||
|
break;
|
||||||
|
case ToggleControls:
|
||||||
|
// Handled in FullPlaybackActivity.performAction
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid action: " + action);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
103
src/org/kreed/vanilla/ShakeThresholdPreference.java
Normal file
103
src/org/kreed/vanilla/ShakeThresholdPreference.java
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.kreed.vanilla;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.preference.DialogPreference;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.SeekBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SeekBar preference to set the shake force threshold.
|
||||||
|
*/
|
||||||
|
public class ShakeThresholdPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener {
|
||||||
|
/**
|
||||||
|
* TextView to display current threshold.
|
||||||
|
*/
|
||||||
|
private TextView mValueText;
|
||||||
|
|
||||||
|
public ShakeThresholdPreference(Context context, AttributeSet attrs)
|
||||||
|
{
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence getSummary()
|
||||||
|
{
|
||||||
|
return getSummary(getPersistedInt(80));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the summary for the given value.
|
||||||
|
*
|
||||||
|
* @param value The force threshold.
|
||||||
|
* @return A string representation of the threshold.
|
||||||
|
*/
|
||||||
|
private static String getSummary(int value)
|
||||||
|
{
|
||||||
|
return String.valueOf(value / 10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected View onCreateDialogView()
|
||||||
|
{
|
||||||
|
View view = super.onCreateDialogView();
|
||||||
|
int value = getPersistedInt(80);
|
||||||
|
|
||||||
|
mValueText = (TextView)view.findViewById(R.id.value);
|
||||||
|
mValueText.setText(getSummary(value));
|
||||||
|
|
||||||
|
SeekBar seekBar = (SeekBar)view.findViewById(R.id.seek_bar);
|
||||||
|
seekBar.setMax(150);
|
||||||
|
seekBar.setProgress(value);
|
||||||
|
seekBar.setOnSeekBarChangeListener(this);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDialogClosed(boolean positiveResult)
|
||||||
|
{
|
||||||
|
notifyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
|
||||||
|
{
|
||||||
|
if (fromUser) {
|
||||||
|
mValueText.setText(getSummary(progress));
|
||||||
|
persistInt(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartTrackingTouch(SeekBar seekBar)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopTrackingTouch(SeekBar seekBar)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user