gt: 	final Object[] mStateLock = new Object[0];
context: /*
   * Copyright (C) 2012-2015 Adrian Ulrich <adrian@blinkenlights.ch>
   * Copyright (C) 2010, 2011 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 ch.blinkenlights.android.vanilla;
  
  import android.app.Notification;
  import android.app.NotificationManager;
  import android.app.PendingIntent;
  import android.app.Service;
  import android.app.backup.BackupManager;
  import android.appwidget.AppWidgetManager;
  import android.content.BroadcastReceiver;
  import android.content.ComponentName;
  import android.content.ContentResolver;
  import android.content.Context;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.content.SharedPreferences;
  import android.database.ContentObserver;
  import android.database.Cursor;
  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.MediaPlayer;
  import android.os.Build;
  import android.os.Handler;
  import android.os.HandlerThread;
  import android.os.IBinder;
  import android.os.Looper;
  import android.os.Message;
  import android.os.PowerManager;
  import android.os.Process;
  import android.os.SystemClock;
  import android.preference.PreferenceManager;
  import android.provider.MediaStore;
  import android.util.Log;
  import android.view.View;
  import android.widget.RemoteViews;
  import android.widget.Toast;
  import java.lang.Math;
  import java.io.DataInputStream;
  import java.io.DataOutputStream;
  import java.io.EOFException;
  import java.io.File;
  import java.io.IOException;
  import java.util.ArrayList;
  
  
  /**
   * Handles music playback and pretty much all the other work.
   */
  public final class PlaybackService extends Service
  	implements Handler.Callback
  			 , MediaPlayer.OnCompletionListener
  			 , MediaPlayer.OnErrorListener
  			 , SharedPreferences.OnSharedPreferenceChangeListener
  			 , SongTimeline.Callback
  			 , SensorEventListener
  			 , AudioManager.OnAudioFocusChangeListener
  {
  	/**
  	 * Name of the state file.
  	 */
  	private static final String STATE_FILE = "state";
  	/**
  	 * Header for state file to help indicate if the file is in the right
  	 * format.
  	 */
  	private static final long STATE_FILE_MAGIC = 0x1533574DC74B6ECL;
  	/**
  	 * State file version that indicates data order.
  	 */
  	private static final int STATE_VERSION = 6;
  
  	private static final int NOTIFICATION_ID = 2;
  
  	/**
  	 * Rewind song if we already played more than 2.5 sec
  	*/
  	private static final int REWIND_AFTER_PLAYED_MS = 2500;
  
  	/**
  	 * Action for startService: toggle playback on/off.
  	 */
  	public static final String ACTION_TOGGLE_PLAYBACK = "ch.blinkenlights.android.vanilla.action.TOGGLE_PLAYBACK";
  	/**
  	 * Action for startService: start playback if paused.
  	 */
  	public static final String ACTION_PLAY = "ch.blinkenlights.android.vanilla.action.PLAY";
  	/**
  	 * Action for startService: pause playback if playing.
  	 */
  	public static final String ACTION_PAUSE = "ch.blinkenlights.android.vanilla.action.PAUSE";
  	/**
  	 * Action for startService: toggle playback on/off.
  	 *
  	 * Unlike {@link PlaybackService#ACTION_TOGGLE_PLAYBACK}, the toggle does
  	 * not occur immediately. Instead, it is delayed so that if two of these
  	 * actions are received within 400 ms, the playback activity is opened
  	 * instead.
  	 */
  	public static final String ACTION_TOGGLE_PLAYBACK_DELAYED = "ch.blinkenlights.android.vanilla.action.TOGGLE_PLAYBACK_DELAYED";
  	/**
  	 * Action for startService: toggle playback on/off.
  	 *
  	 * This works the same way as ACTION_PLAY_PAUSE but prevents the notification
  	 * from being hidden regardless of notification visibility settings.
  	 */
  	public static final String ACTION_TOGGLE_PLAYBACK_NOTIFICATION = "ch.blinkenlights.android.vanilla.action.TOGGLE_PLAYBACK_NOTIFICATION";
  	/**
  	 * Action for startService: advance to the next song.
  	 */
  	public static final String ACTION_NEXT_SONG = "ch.blinkenlights.android.vanilla.action.NEXT_SONG";
  	/**
  	 * Action for startService: advance to the next song.
  	 *
  	 * Unlike {@link PlaybackService#ACTION_NEXT_SONG}, the toggle does
  	 * not occur immediately. Instead, it is delayed so that if two of these
  	 * actions are received within 400 ms, the playback activity is opened
  	 * instead.
  	 */
  	public static final String ACTION_NEXT_SONG_DELAYED = "ch.blinkenlights.android.vanilla.action.NEXT_SONG_DELAYED";
  	/**
  	 * Action for startService: advance to the next song.
  	 *
  	 * Like ACTION_NEXT_SONG, but starts playing automatically if paused
  	 * when this is called.
  	 */
  	public static final String ACTION_NEXT_SONG_AUTOPLAY = "ch.blinkenlights.android.vanilla.action.NEXT_SONG_AUTOPLAY";
  	/**
  	 * Action for startService: go back to the previous song.
  	 */
  	public static final String ACTION_PREVIOUS_SONG = "ch.blinkenlights.android.vanilla.action.PREVIOUS_SONG";
  	/**
  	 * Action for startService: go back to the previous song.
  	 *
  	 * Like ACTION_PREVIOUS_SONG, but starts playing automatically if paused
  	 * when this is called.
  	 */
  	public static final String ACTION_PREVIOUS_SONG_AUTOPLAY = "ch.blinkenlights.android.vanilla.action.PREVIOUS_SONG_AUTOPLAY";
  	/**
  	 * Change the shuffle mode.
  	 */
  	public static final String ACTION_CYCLE_SHUFFLE = "ch.blinkenlights.android.vanilla.CYCLE_SHUFFLE";
  	/**
  	 * Change the repeat mode.
  	 */
  	public static final String ACTION_CYCLE_REPEAT = "ch.blinkenlights.android.vanilla.CYCLE_REPEAT";
  	/**
  	 * Pause music and hide the notifcation.
  	 */
  	public static final String ACTION_CLOSE_NOTIFICATION = "ch.blinkenlights.android.vanilla.CLOSE_NOTIFICATION";
  
  	public static final int NEVER = 0;
  	public static final int WHEN_PLAYING = 1;
  	public static final int ALWAYS = 2;
  
  	/**
  	 * Notification click action: open LaunchActivity.
  	 */
  	private static final int NOT_ACTION_MAIN_ACTIVITY = 0;
  	/**
  	 * Notification click action: open MiniPlaybackActivity.
  	 */
  	private static final int NOT_ACTION_MINI_ACTIVITY = 1;
  	/**
  	 * Notification click action: open FullPlaybackActivity.
  	 */
  	private static final int NOT_ACTION_FULL_ACTIVITY = 2;
  	/**
  	 * Notification click action: skip to next song.
  	 */
  	private static final int NOT_ACTION_NEXT_SONG = 3;
  
  	/**
  	 * If a user action is triggered within this time (in ms) after the
  	 * idle time fade-out occurs, playback will be resumed.
  	 */
  	private static final long IDLE_GRACE_PERIOD = 60000;
  	/**
  	 * Minimum time in milliseconds between shake actions.
  	 */
  	private static final int MIN_SHAKE_PERIOD = 500;
  	/**
  	 * Defer entering deep sleep for this time (in ms).
  	 */
  	private static final int SLEEP_STATE_DELAY = 60000;
  	/**
  	 * Save the current playlist state on queue changes after this time (in ms).
  	 */
  	private static final int SAVE_STATE_DELAY = 5000;
  	/**
  	 * If set, music will play.
  	 */
  	public static final int FLAG_PLAYING = 0x1;
  	/**
  	 * Set when there is no media available on the device.
  	 */
  	public static final int FLAG_NO_MEDIA = 0x2;
  	/**
  	 * Set when the current song is unplayable.
  	 */
  	public static final int FLAG_ERROR = 0x4;
  	/**
  	 * Set when the user needs to select songs to play.
  	 */
  	public static final int FLAG_EMPTY_QUEUE = 0x8;
  	public static final int SHIFT_FINISH = 4;
  	/**
  	 * These three bits will be one of SongTimeline.FINISH_*.
  	 */
  	public static final int MASK_FINISH = 0x7 << SHIFT_FINISH;
  	public static final int SHIFT_SHUFFLE = 7;
  	/**
  	 * These three bits will be one of SongTimeline.SHUFFLE_*.
  	 */
  	public static final int MASK_SHUFFLE = 0x7 << SHIFT_SHUFFLE;
  	public static final int SHIFT_DUCKING = 10;
  	/**
  	 * Whether we're 'ducking' (lowering the playback volume temporarily due to a transient system
  	 * sound, such as a notification) or not
  	 */
  	public static final int FLAG_DUCKING = 0x1 << SHIFT_DUCKING;
  
  	/**
  	 * The PlaybackService state, indicating if the service is playing,
  	 * repeating, etc.
  	 *
  	 * The format of this is 0b00000000_00000000_000000gff_feeedcba,
  	 * where each bit is:
  	 *     a:   {@link PlaybackService#FLAG_PLAYING}
  	 *     b:   {@link PlaybackService#FLAG_NO_MEDIA}
  	 *     c:   {@link PlaybackService#FLAG_ERROR}
  	 *     d:   {@link PlaybackService#FLAG_EMPTY_QUEUE}
  	 *     eee: {@link PlaybackService#MASK_FINISH}
  	 *     fff: {@link PlaybackService#MASK_SHUFFLE}
  	 *     g:   {@link PlaybackService#FLAG_DUCKING}
  	 */
  	int mState;
  
  	/**
  	 * How many broken songs we did already skip
  	 */
  	int mSkipBroken;
  
  	/**
  	 * Object used for state-related locking.
  	 */
  