// Copyright 2009 Google Inc. // Copyright 2011 NPR // // 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 org.npr.android.news; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.database.Cursor; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.util.Log; import android.view.*; import android.view.View.OnClickListener; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.*; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.SlidingDrawer.OnDrawerCloseListener; import android.widget.SlidingDrawer.OnDrawerOpenListener; import org.npr.android.util.DisplayUtils; import org.npr.android.util.PlaylistEntry; import org.npr.android.util.PlaylistProvider; import org.npr.android.util.PlaylistRepository; import org.npr.android.widget.DragListener; import org.npr.android.widget.DragNDropListView; import org.npr.android.widget.DropListener; public class PlaylistView extends FrameLayout implements OnClickListener, OnSeekBarChangeListener, OnDrawerOpenListener, OnDrawerCloseListener, AdapterView.OnItemClickListener, DragListener, DropListener { private static final String LOG_TAG = PlaylistView.class.getName(); private final Context context; private PlaylistAdapter playlistAdapter; private PlaylistRepository playlist; private SlidingDrawer drawer; private RelativeLayout handle; private RelativeLayout playerContracted; private RelativeLayout playerExpanded; private TextView playerStatus; private TextView contractedPlayerStatus; private TextView newsItemText; private TextView contractedNewsItemText; private SeekBar progressBar; private boolean changingProgress; private TextView lengthText; private boolean playPauseShowsPlay; private ImageButton rewindButton; private ImageButton rewind30Button; private ImageButton playPauseButton; private ImageButton fastForwardButton; private ImageButton contractedPlayButton; private DragNDropListView listView; private Button clearPlayedSegments; private Button clearPlaylist; private boolean playEnabled; private boolean moveControlsEnabled; private boolean rewindEnabled; private boolean fastForwardEnabled; private int touchSlop; private int startX; private int startY; private boolean cancelDown; private Playable storedPlayable = null; private enum ClickedItem { rewind, rewind30, playPause, fastForward, contractedPlay, progressbar } private ClickedItem clickedItem; private BroadcastReceiver changeReceiver; private BroadcastReceiver updateReceiver; private BroadcastReceiver closeReceiver; private BroadcastReceiver errorReceiver; private BroadcastReceiver playlistChangedReceiver; private GestureDetector gestureDetector; private final Handler handler = new Handler() { @Override public void handleMessage(final Message msg) { switch (msg.what) { case ListItemGestureListener.MSG_FLING: final PlaylistEntry entry = getPlaylistEntryAtPosition(msg.arg1); View listItem = listView.getChildAt(msg.arg1 - listView.getFirstVisiblePosition()); Animation fling = AnimationUtils.loadAnimation( context, msg.arg2 < 0 ? R.anim.playlist_remove_left : R.anim.playlist_remove_right ); fling.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationEnd(Animation animation) { playlist.delete(entry); updatePlaylist(); } @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } }); listItem.startAnimation(fling); break; } } }; public PlaylistView(Context context) { super(context); this.context = context; } public PlaylistView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; } public PlaylistView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.context = context; } /** * Returns a pointer to the SlidingDrawer for the * player window. * * @return The player's SlidingDrawer */ public SlidingDrawer getPlayerDrawer() { return drawer; } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); init(); } private void init() { ViewGroup.inflate(context, R.layout.playlist, this); playlist = new PlaylistRepository(context.getApplicationContext(), context.getContentResolver()); drawer = (SlidingDrawer) findViewById(R.id.drawer); drawer.setOnDrawerOpenListener(this); drawer.setOnDrawerCloseListener(this); touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); handle = (RelativeLayout) findViewById(R.id.handle); playerContracted = (RelativeLayout) findViewById(R.id.player_contracted); playerExpanded = (RelativeLayout) findViewById(R.id.player_expanded); playerStatus = (TextView) findViewById(R.id.status); contractedPlayerStatus = (TextView) findViewById(R.id.contracted_status); newsItemText = (TextView) findViewById(R.id.news_item_text); contractedNewsItemText = (TextView) findViewById(R.id .contracted_news_item_text); progressBar = (SeekBar) findViewById(R.id.stream_progress_bar); progressBar.setOnSeekBarChangeListener(this); changingProgress = false; lengthText = (TextView) findViewById(R.id.stream_length_display_text); lengthText.setText("0:00 / 0:00"); playPauseShowsPlay = true; contractedPlayButton = (ImageButton) findViewById(R.id .contracted_play_pause); rewindButton = (ImageButton) findViewById(R.id.stream_rewind_button); rewind30Button = (ImageButton) findViewById(R.id.stream_rewind_30_button); playPauseButton = (ImageButton) findViewById(R.id.stream_play_pause_button); fastForwardButton = (ImageButton) findViewById(R.id .stream_fastforward_button); clearPlayedSegments = (Button) findViewById(R.id.clear_played_segments); clearPlayedSegments.setOnClickListener(this); clearPlaylist = (Button) findViewById(R.id.clear_playlist); clearPlaylist.setOnClickListener(this); Cursor cursor = queryPlaylist(); playlistAdapter = new PlaylistAdapter(context, cursor); changeReceiver = new PlaybackChangeReceiver(); Intent intent = context.registerReceiver(changeReceiver, new IntentFilter(PlaybackService.SERVICE_CHANGE_NAME)); if (intent != null) { changeReceiver.onReceive(context, intent); } else { Log.d(LOG_TAG, "Call clearPlayer from init"); clearPlayer(); } updateReceiver = new PlaybackUpdateReceiver(); intent = context.registerReceiver(updateReceiver, new IntentFilter(PlaybackService.SERVICE_UPDATE_NAME)); if (intent != null) { updateReceiver.onReceive(context, intent); } closeReceiver = new PlaybackCloseReceiver(); context.registerReceiver(closeReceiver, new IntentFilter(PlaybackService.SERVICE_CLOSE_NAME)); errorReceiver = new PlaybackErrorReceiver(); context.registerReceiver(errorReceiver, new IntentFilter(PlaybackService.SERVICE_ERROR_NAME)); playlistChangedReceiver = new PlaylistChangedReceiver(); context.registerReceiver(playlistChangedReceiver, new IntentFilter(PlaylistRepository.PLAYLIST_CHANGED)); listView = (DragNDropListView) findViewById(R.id.playlist); listView.setAdapter(playlistAdapter); listView.setOnItemClickListener(this); listView.setDragListener(this); listView.setDropListener(this); // Gesture detection gestureDetector = new GestureDetector(getContext(), new ListItemGestureListener(listView, handler) ); View.OnTouchListener gestureListener = new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { return gestureDetector.onTouchEvent(event); } }; listView.setOnTouchListener(gestureListener); if (context instanceof Activity) { ((Activity) context).registerForContextMenu(listView); } refreshList(); } private Cursor queryPlaylist() { Cursor cursor = context.getContentResolver().query(PlaylistProvider .CONTENT_URI, null, null, null, PlaylistProvider.Items.PLAY_ORDER); return cursor; } private void refreshList() { if (playlistAdapter != null) { playlistAdapter.changeCursor( queryPlaylist() ); playlistAdapter.notifyDataSetChanged(); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); // Emulator calls detach twice, so clear receiver if (changeReceiver != null) { context.unregisterReceiver(changeReceiver); changeReceiver = null; } if (updateReceiver != null) { context.unregisterReceiver(updateReceiver); updateReceiver = null; } if (closeReceiver != null) { context.unregisterReceiver(closeReceiver); closeReceiver = null; } if (errorReceiver != null) { context.unregisterReceiver(errorReceiver); errorReceiver = null; } if (playlistChangedReceiver != null) { context.unregisterReceiver(playlistChangedReceiver); playlistChangedReceiver = null; } if (playlistAdapter != null) { playlistAdapter.close(); playlistAdapter = null; } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.clear_playlist: Intent intent = new Intent(context, PlaybackService.class); intent.setAction(PlaybackService.SERVICE_CLEAR_PLAYER); context.startService(intent); playlist.clearAll(); refreshList(); configurePlayerControls(); break; case R.id.clear_played_segments: playlist.clearPlayed(); refreshList(); configurePlayerControls(); break; } } protected void playEntryNow(final PlaylistEntry entry) { playNow( Playable.PlayableFactory.fromPlaylistEntry(entry), PlaybackService.SERVICE_PLAY_ENTRY ); } protected void playSingleNow(final Playable playable) { playNow(playable, PlaybackService.SERVICE_PLAY_SINGLE); } private void playNow(final Playable playable, String action) { startPlaylistSpinners(); Intent intent = new Intent(context, PlaybackService.class); intent.setAction(action); intent.putExtra(Playable.PLAYABLE_TYPE, playable); context.startService(intent); newsItemText.setText(playable.getTitle()); contractedNewsItemText.setText(playable.getTitle()); playlistAdapter.setActiveId(Long.toString(playable.getId())); refreshList(); configurePlayerControls(); } private void configurePlayerControls() { if (playlist.getItemCount() > 0) { clearPlaylist.setEnabled(true); clearPlayedSegments.setEnabled(playlist.getReadCount() > 0); } else { clearPlaylist.setEnabled(false); clearPlayedSegments.setEnabled(false); } String activeId = playlistAdapter.getActiveId(); if (activeId != null) { playerStatus.setText(R.string.msg_player_now_playing); contractedPlayerStatus.setText(R.string.msg_player_now_playing); if (!activeId.equals("-1")) { playEnabled = true; moveControlsEnabled = true; rewindEnabled = !playlist.isFirstEntry(activeId); fastForwardEnabled = !playlist.isLastEntry(activeId); } else { playEnabled = true; moveControlsEnabled = true; rewindEnabled = false; fastForwardEnabled = (playlist.getFirstUnreadEntry() != null); } } else { Playable firstUnreadEntry = playlist.getFirstUnreadEntry(); if (firstUnreadEntry != null) { playerStatus.setText(R.string.msg_player_ready_to_play); contractedPlayerStatus.setText(R.string.msg_player_ready_to_play); String title = firstUnreadEntry.getTitle(); newsItemText.setText(title); contractedNewsItemText.setText(title); } else { playerStatus.setText(R.string.msg_player_nothing_to_play); contractedPlayerStatus.setText(R.string.msg_player_nothing_to_play); newsItemText.setText(""); contractedNewsItemText.setText(""); } playEnabled = (firstUnreadEntry != null); moveControlsEnabled = false; rewindEnabled = false; fastForwardEnabled = false; } } private void clearPlayer() { playlistAdapter.setActiveId(null); configurePlayerControls(); progressBar.setProgress(0); progressBar.setSecondaryProgress(0); lengthText.setText("0:00 / 0:00"); stopPlaylistSpinners(); } private class PlaybackChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { try { Context serviceContext = context.createPackageContext(context.getPackageName(), Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); Bundle bundle = intent.getExtras(); bundle.setClassLoader(serviceContext.getClassLoader()); storedPlayable = bundle.getParcelable(Playable.PLAYABLE_TYPE); if (storedPlayable != null) { newsItemText.setText(storedPlayable.getTitle()); contractedNewsItemText.setText(storedPlayable.getTitle()); playlistAdapter.setActiveId(Long.toString(storedPlayable.getId())); } } catch (PackageManager.NameNotFoundException e) { Log.e(LOG_TAG, "Name not found exception in playback change", e); } refreshList(); configurePlayerControls(); showPlayPause(false); } } private class PlaybackUpdateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int duration = intent.getIntExtra(PlaybackService.EXTRA_DURATION, 1); // Drop out if no duration is given (flicker?) if (duration == 1) { Log.v(LOG_TAG, "Playback update; no duration dropout"); return; } int position = intent.getIntExtra(PlaybackService.EXTRA_POSITION, 0); int downloaded = intent.getIntExtra(PlaybackService.EXTRA_DOWNLOADED, 1); Log.v(LOG_TAG, "Playback update; position = " + position + " millsecs; " + "downloaded = " + duration + " millsecs"); boolean isPlaying = intent.getBooleanExtra(PlaybackService .EXTRA_IS_PLAYING, false); if (!changingProgress) { progressBar.setMax(duration); progressBar.setProgress(position); } progressBar.setSecondaryProgress(downloaded); // StringBuilder much faster than String.Format StringBuilder length = new StringBuilder(13); length.append(position / 60000); length.append(':'); int secs = position / 1000 % 60; if (secs < 10) { length.append('0'); } length.append(secs); length.append(" / "); length.append(duration / 60000); length.append(':'); secs = duration / 1000 % 60; if (secs < 10) { length.append('0'); } length.append(secs); lengthText.setText(length.toString()); if (position > 0) { // Streams have no 'downloaded' amount if (downloaded == 0 || downloaded >= position) { stopPlaylistSpinners(); } else if (isPlaying) { startPlaylistSpinners(); } } if (isPlaying == playPauseShowsPlay) { if (isPlaying) { if (storedPlayable == null || !storedPlayable.isStream()) { playPauseButton.setImageResource(R.drawable.pause_button_normal); playPauseButton.setContentDescription(getResources().getString(R.string.acd_pause_button)); contractedPlayButton.setImageResource(R.drawable.pause_button_normal); contractedPlayButton.setContentDescription(getResources().getString(R.string.acd_pause_button)); } else { playPauseButton.setImageResource(R.drawable.stop_button_normal); playPauseButton.setContentDescription(getResources().getString(R.string.acd_stop_button)); contractedPlayButton.setImageResource(R.drawable.stop_button_normal); contractedPlayButton.setContentDescription(getResources().getString(R.string.acd_stop_button)); } playPauseShowsPlay = false; } else { playPauseButton.setImageResource(R.drawable.play_button_normal); playPauseButton.setContentDescription(getResources().getString(R.string.acd_play_button)); contractedPlayButton.setImageResource(R.drawable.play_button_normal); contractedPlayButton.setContentDescription(getResources().getString(R.string.acd_play_button)); playPauseShowsPlay = true; } } } } private class PlaybackCloseReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.d(LOG_TAG, "Playback close received - calling clear player"); clearPlayer(); refreshList(); } } private class PlaybackErrorReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.d(LOG_TAG, "Playback error received - toasting message"); String message = context.getString(R.string.msg_unknown_error); int error = intent.getIntExtra(PlaybackService.EXTRA_ERROR, -1); if (error == PlaybackService.PLAYBACK_SERVICE_ERROR.Playback.ordinal()) { message = context.getString(R.string.msg_playback_error); } else if (error == PlaybackService.PLAYBACK_SERVICE_ERROR.Connection.ordinal()) { message = context.getString(R.string.msg_playback_connection_error); } else if (error == PlaybackService.PLAYBACK_SERVICE_ERROR.InvalidPlayable.ordinal()) { message = context.getString(R.string.msg_playback_invalid_playable_error); clearPlayer(); } Toast.makeText(context, message, Toast.LENGTH_LONG).show(); } } private class PlaylistChangedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { configurePlayerControls(); } } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { seekBar.setProgress(progress); if (fromUser) { Intent intent = new Intent(context, PlaybackService.class); intent.setAction(PlaybackService.SERVICE_SEEK_TO); intent.putExtra(PlaybackService.EXTRA_SEEK_TO, progress); context.startService(intent); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { changingProgress = true; } @Override public void onStopTrackingTouch(SeekBar seekBar) { changingProgress = false; } @Override public void onDrawerOpened() { handle.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, DisplayUtils.convertToDIP(context, 150))); playerContracted.setVisibility(View.GONE); playerExpanded.setVisibility(View.VISIBLE); refreshList(); } @Override public void onDrawerClosed() { handle.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, DisplayUtils.convertToDIP(context, 95))); playerContracted.setVisibility(View.VISIBLE); playerExpanded.setVisibility(View.GONE); } public boolean isExpanded() { return drawer.isOpened(); } public void setExpanded(boolean expanded) { if (expanded) { drawer.animateOpen(); } else { drawer.animateClose(); } } private boolean ViewContainsXY(View v, int x, int y) { Rect r = new Rect(); v.getDrawingRect(r); offsetDescendantRectToMyCoords(v, r); return r.contains(x, y); } private void closeDrawerIfPastThreshold(int y) { Rect r = new Rect(); drawer.getDrawingRect(r); if ((y - startY) > (r.height() / 3)) { drawer.close(); } } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { final int x = (int) event.getX(), y = (int) event.getY(); if (isExpanded()) { if (ViewContainsXY(playPauseButton, x, y)) { clickedItem = ClickedItem.playPause; return true; } else if (ViewContainsXY(rewindButton, x, y)) { clickedItem = ClickedItem.rewind; return true; } else if (ViewContainsXY(rewind30Button, x, y)) { clickedItem = ClickedItem.rewind30; return true; } else if (ViewContainsXY(fastForwardButton, x, y)) { clickedItem = ClickedItem.fastForward; return true; } else if (ViewContainsXY(progressBar, x, y)) { clickedItem = ClickedItem.progressbar; return true; } } else { if (ViewContainsXY(contractedPlayButton, x, y)) { clickedItem = ClickedItem.contractedPlay; return true; } } } return false; } private void showPlayPause(boolean showPressed) { if (playPauseShowsPlay) { if (showPressed) { playPauseButton.setImageResource(R.drawable.play_button_pressed); contractedPlayButton.setImageResource(R.drawable.play_button_pressed); } else { playPauseButton.setImageResource(R.drawable.play_button_normal); contractedPlayButton.setImageResource(R.drawable.play_button_normal); } } else { if (storedPlayable == null || !storedPlayable.isStream()) { if (showPressed) { playPauseButton.setImageResource(R.drawable.pause_button_pressed); contractedPlayButton.setImageResource(R.drawable.pause_button_pressed); } else { playPauseButton.setImageResource(R.drawable.pause_button_normal); contractedPlayButton.setImageResource(R.drawable.pause_button_normal); } } else { if (showPressed) { playPauseButton.setImageResource(R.drawable.stop_button_pressed); contractedPlayButton.setImageResource(R.drawable.stop_button_pressed); } else { playPauseButton.setImageResource(R.drawable.stop_button_normal); contractedPlayButton.setImageResource(R.drawable.stop_button_normal); } } } } @Override public boolean onTouchEvent(MotionEvent event) { if (clickedItem != null) { final int x = (int) event.getX(), y = (int) event.getY(); switch (clickedItem) { case playPause: switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (ViewContainsXY(playPauseButton, x, y)) { if (playEnabled) { showPlayPause(true); } startY = y; cancelDown = false; return true; } break; case MotionEvent.ACTION_MOVE: if (!ViewContainsXY(playPauseButton, x, y)) { if (playEnabled) { showPlayPause(false); } cancelDown = true; return true; } break; case MotionEvent.ACTION_UP: if (playEnabled && !cancelDown) { playPauseShowsPlay = !playPauseShowsPlay; if (playPauseShowsPlay) { stopPlaylistSpinners(); } else { startPlaylistSpinners(); } showPlayPause(false); Intent intent = new Intent(context, PlaybackService.class); intent.setAction(PlaybackService.SERVICE_TOGGLE_PLAY); intent.putExtra(Playable.PLAYABLE_TYPE, storedPlayable); context.startService(intent); } else { closeDrawerIfPastThreshold(y); } clickedItem = null; return true; } break; case rewind: switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (ViewContainsXY(rewindButton, x, y)) { if (rewindEnabled) { rewindButton.setImageResource(R.drawable.rew_pressed); } startY = y; cancelDown = false; return true; } break; case MotionEvent.ACTION_MOVE: if (!ViewContainsXY(rewindButton, x, y)) { if (rewindEnabled) { rewindButton.setImageResource(R.drawable.rew_normal); } cancelDown = true; return false; } break; case MotionEvent.ACTION_UP: if (rewindEnabled && !cancelDown) { rewindButton.setImageResource(R.drawable.rew_normal); Intent intent = new Intent(context, PlaybackService.class); intent.setAction(PlaybackService.SERVICE_PLAY_PREVIOUS); context.startService(intent); } else { closeDrawerIfPastThreshold(y); } clickedItem = null; return true; } break; case rewind30: switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (ViewContainsXY(rewind30Button, x, y)) { if (moveControlsEnabled) { rewind30Button.setImageResource(R.drawable.rew_30_pressed); } startY = y; cancelDown = false; return true; } break; case MotionEvent.ACTION_MOVE: if (!ViewContainsXY(rewind30Button, x, y)) { if (moveControlsEnabled) { rewind30Button.setImageResource(R.drawable.rew_30_normal); } cancelDown = true; return false; } break; case MotionEvent.ACTION_UP: if (moveControlsEnabled && !cancelDown) { rewind30Button.setImageResource(R.drawable.rew_30_normal); Intent intent = new Intent(context, PlaybackService.class); intent.setAction(PlaybackService.SERVICE_BACK_30); context.startService(intent); } else { closeDrawerIfPastThreshold(y); } clickedItem = null; return true; } break; case fastForward: switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (ViewContainsXY(fastForwardButton, x, y)) { if (fastForwardEnabled) { fastForwardButton.setImageResource(R.drawable.ffwd_pressed); } startY = y; cancelDown = false; return true; } break; case MotionEvent.ACTION_MOVE: if (!ViewContainsXY(fastForwardButton, x, y)) { if (fastForwardEnabled) { fastForwardButton.setImageResource(R.drawable.ffwd_normal); } cancelDown = true; return false; } break; case MotionEvent.ACTION_UP: if (fastForwardEnabled && !cancelDown) { fastForwardButton.setImageResource(R.drawable.ffwd_normal); Intent intent = new Intent(context, PlaybackService.class); intent.setAction(PlaybackService.SERVICE_PLAY_NEXT); context.startService(intent); } else { closeDrawerIfPastThreshold(y); } clickedItem = null; return true; } break; case contractedPlay: switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (ViewContainsXY(contractedPlayButton, x, y)) { if (playEnabled) { showPlayPause(true); } startY = y; cancelDown = false; return true; } break; case MotionEvent.ACTION_MOVE: if (!ViewContainsXY(contractedPlayButton, x, y)) { if (playEnabled) { showPlayPause(false); } cancelDown = true; return false; } break; case MotionEvent.ACTION_UP: if (playEnabled && !cancelDown) { playPauseShowsPlay = !playPauseShowsPlay; if (playPauseShowsPlay) { stopPlaylistSpinners(); } else { startPlaylistSpinners(); } showPlayPause(false); Intent intent = new Intent(context, PlaybackService.class); intent.setAction(PlaybackService.SERVICE_TOGGLE_PLAY); intent.putExtra(Playable.PLAYABLE_TYPE, storedPlayable); context.startService(intent); } else { Rect r = new Rect(); drawer.getDrawingRect(r); if ((startY - y) > (r.height() / 3)) { drawer.open(); } } clickedItem = null; return true; } break; case progressbar: switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (ViewContainsXY(progressBar, x, y)) { startX = x; startY = y; return true; } break; case MotionEvent.ACTION_MOVE: boolean xMovement = Math.abs(x - startX) >= touchSlop; if (moveControlsEnabled && xMovement) { progressBar.onTouchEvent(event); } else if (Math.abs(y - startY) >= touchSlop && !xMovement) { cancelDown = true; } return true; case MotionEvent.ACTION_UP: if (moveControlsEnabled && !cancelDown) { progressBar.onTouchEvent(event); } else { closeDrawerIfPastThreshold(y); } clickedItem = null; return true; } break; } } return false; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { PlaylistEntry entry = getPlaylistEntryAtPosition(position); playEntryNow(entry); } /** * Returns a PlaylistEntry for the item at the given position in the * playlist. * * @param position The position of the item starting at 0 * @return A PlaylistEntry or null of the position is invalid or cannot be * found. */ public PlaylistEntry getPlaylistEntryAtPosition(int position) { PlaylistEntry entry = null; DragNDropListView listView = (DragNDropListView) findViewById(R.id.playlist); Cursor c = (Cursor) listView.getItemAtPosition(position); if (c != null) { c.moveToPosition(position); long playlistId = c.getLong(c.getColumnIndex(PlaylistProvider.Items._ID)); Log.d(LOG_TAG, "clicked on position " + position + ", id " + playlistId); entry = playlist.getPlaylistItemFromId(playlistId); if (entry == null) { Log.e(LOG_TAG, "Couldn't find playlist item " + playlistId + " at position" + position); } } return entry; } private void startPlaylistSpinners() { ProgressBar loadingIndicator = (ProgressBar) findViewById(R.id.player_loading_indicator); if (loadingIndicator != null) { loadingIndicator.setVisibility(View.VISIBLE); } else { Log.w(LOG_TAG, "Can't find loading indicator. Expanded? " + isExpanded()); } loadingIndicator = (ProgressBar) findViewById(R.id.player_loading_indicator_contracted); if (loadingIndicator != null) { loadingIndicator.setVisibility(View.VISIBLE); } } private void stopPlaylistSpinners() { ProgressBar loadingIndicator = (ProgressBar) findViewById(R.id.player_loading_indicator); if (loadingIndicator != null) { loadingIndicator.setVisibility(View.INVISIBLE); } loadingIndicator = (ProgressBar) findViewById(R.id.player_loading_indicator_contracted); if (loadingIndicator != null) { loadingIndicator.setVisibility(View.INVISIBLE); } } @Override public void onStartDrag(View itemView) { drawer.lock(); itemView.setVisibility(View.INVISIBLE); } @Override public void onDrag(int x, int y, ListView listView) { } @Override public void onStopDrag(View itemView) { itemView.setVisibility(View.VISIBLE); drawer.unlock(); } @Override public void onDrop(int from, int to) { playlist.move(from, to); refreshList(); } public void updatePlaylist() { refreshList(); configurePlayerControls(); if (playlist.getItemCount() == 0) { Intent intent = new Intent(context, PlaybackService.class); intent.setAction(PlaybackService.SERVICE_CLEAR_PLAYER); context.startService(intent); } } public String getActiveId() { return playlistAdapter.getActiveId(); } }