PageRenderTime 38ms CodeModel.GetById 46ms RepoModel.GetById 0ms app.codeStats 0ms

/MM5/src/com/sandrstar/android/gallery/ListViewCursorAdapter.java

https://github.com/AlexStarc/MM5
Java | 475 lines | 301 code | 81 blank | 93 comment | 69 complexity | 539fe3ef0df6abcb122a3ad8d36bb3ee MD5 | raw file
  1. /*
  2. * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  3. * Version 2, December 2004
  4. *
  5. * Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
  6. *
  7. * Everyone is permitted to copy and distribute verbatim or modified
  8. * copies of this license document, and changing it is allowed as long
  9. * as the name is changed.
  10. *
  11. * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  12. * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  13. *
  14. * 0. You just DO WHAT THE FUCK YOU WANT TO.
  15. *
  16. * This program is free software. It comes without any warranty, to
  17. * the extent permitted by applicable law. You can redistribute it
  18. * and/or modify it under the terms of the Do What The Fuck You Want
  19. * To Public License, Version 2, as published by Sam Hocevar. See
  20. * http://sam.zoy.org/wtfpl/COPYING for more details.
  21. */
  22. /**
  23. * This is adapter for ListView view of ContentGallery
  24. */
  25. package com.sandrstar.android.gallery;
  26. import java.io.IOException;
  27. import android.content.Context;
  28. import android.database.Cursor;
  29. import android.media.MediaPlayer;
  30. import android.os.Handler;
  31. import android.os.SystemClock;
  32. import android.provider.MediaStore;
  33. import android.provider.MediaStore.Audio.AudioColumns;
  34. import android.text.format.Time;
  35. import android.util.Log;
  36. import android.view.LayoutInflater;
  37. import android.view.View;
  38. import android.view.View.OnClickListener;
  39. import android.view.ViewGroup;
  40. import android.view.animation.AlphaAnimation;
  41. import android.view.animation.AnimationSet;
  42. import android.view.animation.DecelerateInterpolator;
  43. import android.view.animation.ScaleAnimation;
  44. import android.widget.Button;
  45. import android.widget.CursorAdapter;
  46. import android.widget.ProgressBar;
  47. import android.widget.TextView;
  48. /**
  49. * @author AlexStarc
  50. *
  51. */
  52. public class ListViewCursorAdapter extends CursorAdapter implements MediaPlayer.OnCompletionListener {
  53. private final static String TAG = "ListViewCursorAdapter";
  54. private OnClickListener playButtonListener = null;
  55. private Integer mnFocus = CGalleryConstants.GALLERY_INVALID_INDEX.value();
  56. private Integer mnPlayIndex = CGalleryConstants.GALLERY_INVALID_INDEX.value();
  57. private static final String GALLERYVIEW_UNDEFINED_FIELD = "Unknown";
  58. private static final String GALLERYVIEW_START_TIME = "00:00";
  59. private static final Integer GALLERYLISTVIEW_ITEM_ACTIVE = 1;
  60. private static final Integer GALLERYLISTVIEW_ITEM_NONACTIVE = 0;
  61. private boolean mbSelectAnimationPlayed = false;
  62. Integer mnPlayTime = CGalleryConstants.GALLERY_INVALID_INDEX.value();
  63. private View mPlayProgressView = null;
  64. TextView mElapsedText = null;
  65. ProgressBar mProgressBar = null;
  66. Handler mPlayProgressUpdateHandler = null;
  67. // Runnable for progress updates handling
  68. private Runnable mUpdatePlayProgress = null;
  69. MediaPlayer mPlayer = null;
  70. /**
  71. * ListViewCursorAdapter - main constructor
  72. *
  73. * @param context - main context;
  74. * @param c - cursor to be used for adapter;
  75. * @param autoReQuery - boolean flag to allow auto-re-query;
  76. */
  77. public ListViewCursorAdapter(final Context context, final Cursor c, final boolean autoReQuery) {
  78. super(context, c, autoReQuery);
  79. Log.i(TAG, "created");
  80. this.mPlayProgressUpdateHandler = new Handler();
  81. // create MediaPlayer for playing of selected sound
  82. this.mPlayer = new MediaPlayer();
  83. this.mPlayer.setOnCompletionListener(this);
  84. this.mUpdatePlayProgress = new Runnable() {
  85. @Override
  86. public void run() {
  87. String itemText;
  88. final Time trackTime = new Time();
  89. // make elapsed time bigger
  90. if( ListViewCursorAdapter.this.mPlayer != null ) {
  91. ListViewCursorAdapter.this.mnPlayTime = ListViewCursorAdapter.this.mPlayer.getCurrentPosition() / 1000;
  92. if(null != ListViewCursorAdapter.this.mElapsedText &&
  93. null != ListViewCursorAdapter.this.mProgressBar) {
  94. trackTime.set(ListViewCursorAdapter.this.mnPlayTime * 1000);
  95. // determine how time should be shown - currently check only hours existence
  96. if(trackTime.hour <= 0) {
  97. itemText = trackTime.format("%M:%S");
  98. } else {
  99. itemText = trackTime.format("%H:%M:%S");
  100. }
  101. ListViewCursorAdapter.this.mElapsedText.setText(itemText);
  102. ListViewCursorAdapter.this.mProgressBar.setProgress(ListViewCursorAdapter.this.mnPlayTime);
  103. }
  104. ListViewCursorAdapter.this.mPlayProgressUpdateHandler.postAtTime(this, SystemClock.uptimeMillis() + 1000);
  105. }
  106. }
  107. };
  108. }
  109. @Override
  110. public void bindView(final View elementView, final Context context, final Cursor cursor) {
  111. try {
  112. final int fileNameCol = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
  113. final String fileName = cursor.getString(fileNameCol);
  114. final TextView fileNameView = (TextView)elementView.findViewById(R.id.listview_item_text);
  115. if(null != fileNameView) {
  116. fileNameView.setText(fileName);
  117. }
  118. final GalleryContentItem viewTag = new GalleryContentItem(fileName, cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)));
  119. viewTag.setIndex(cursor.getPosition());
  120. elementView.setTag(viewTag);
  121. if(this.mnFocus == cursor.getPosition()) {
  122. populateFocusView(elementView, cursor);
  123. if(!this.mbSelectAnimationPlayed) {
  124. // play animation on focused view
  125. final AnimationSet showUpAnimationSet = new AnimationSet(true);
  126. // Add scaling animation
  127. showUpAnimationSet.addAnimation( new ScaleAnimation((float)1.0,
  128. (float)1.0,
  129. (float)0.75,
  130. (float)1.0) );
  131. // Add fade out animation
  132. showUpAnimationSet.addAnimation( new AlphaAnimation((float)0.3, (float)1.0) );
  133. showUpAnimationSet.setDuration(400);
  134. showUpAnimationSet.setInterpolator(new DecelerateInterpolator());
  135. elementView.startAnimation(showUpAnimationSet);
  136. this.mbSelectAnimationPlayed = true;
  137. }
  138. }
  139. final Button playButton = (Button)elementView.findViewById(R.id.listview_item_play);
  140. // also, update icon if it's currently playing item
  141. if(this.mnPlayIndex == cursor.getPosition()) {
  142. playButton.setBackgroundResource(R.drawable.listview_item_stop_button);
  143. } else {
  144. playButton.setBackgroundResource(R.drawable.listview_item_button);
  145. }
  146. } catch(final Exception e) {
  147. Log.e(TAG, "bindView(): " + e.getClass() + " thrown " + e.getMessage());
  148. }
  149. }
  150. @Override
  151. public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
  152. View elementView = null;
  153. try {
  154. final LayoutInflater inflater = LayoutInflater.from(context);
  155. if( this.mnFocus == cursor.getPosition() ) {
  156. elementView = inflater.inflate(R.layout.listviewgallery_item_selected, parent, false);
  157. populateFocusView(elementView, cursor);
  158. } else {
  159. elementView = inflater.inflate(R.layout.listviewgallery_item, parent, false);
  160. }
  161. final int fileNameCol = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
  162. final String fileName = cursor.getString(fileNameCol);
  163. final TextView fileNameView = (TextView)elementView.findViewById(R.id.listview_item_text);
  164. final Button playButton = (Button)elementView.findViewById(R.id.listview_item_play);
  165. if(null != fileNameView) {
  166. fileNameView.setText(fileName);
  167. }
  168. if(null != playButton) {
  169. playButton.setOnClickListener(getPlayButtonListener());
  170. // also, update icon if it's currently playing item
  171. if( this.mnPlayIndex == cursor.getPosition() ) {
  172. playButton.setBackgroundResource(R.drawable.listview_item_stop_button);
  173. } else {
  174. playButton.setBackgroundResource(R.drawable.listview_item_button);
  175. }
  176. }
  177. // create and set GalleryContentItem as tag to every view
  178. final GalleryContentItem viewTag = new GalleryContentItem(fileName, cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)));
  179. viewTag.setIndex(cursor.getPosition());
  180. elementView.setTag(viewTag);
  181. } catch(final Exception e) {
  182. Log.e(TAG, "newView(): " + e.getClass() + " thrown " + e.getMessage());
  183. }
  184. if(this.mnFocus == cursor.getPosition() &&
  185. !this.mbSelectAnimationPlayed) {
  186. // play animation on focused view
  187. final AnimationSet showUpAnimationSet = new AnimationSet(true);
  188. // Add scaling animation
  189. showUpAnimationSet.addAnimation( new ScaleAnimation((float)1.0,
  190. (float)1.0,
  191. (float)0.75,
  192. (float)1.0) );
  193. // Add fade out animation
  194. showUpAnimationSet.addAnimation( new AlphaAnimation((float)0.3, (float)1.0) );
  195. showUpAnimationSet.setDuration(400);
  196. showUpAnimationSet.setInterpolator(new DecelerateInterpolator());
  197. if( elementView != null ) {
  198. elementView.startAnimation(showUpAnimationSet);
  199. }
  200. this.mbSelectAnimationPlayed = true;
  201. }
  202. return elementView;
  203. }
  204. /**
  205. * @param playButtonListener the playButtonListener to set
  206. */
  207. public void setPlayButtonListener(final OnClickListener playButtonListener) {
  208. this.playButtonListener = playButtonListener;
  209. }
  210. /**
  211. * @return the playButtonListener
  212. */
  213. public OnClickListener getPlayButtonListener() {
  214. return this.playButtonListener;
  215. }
  216. /**
  217. * @param nFocus the nFocus to set
  218. */
  219. public void setNFocus(final Integer nFocus) {
  220. this.mnFocus = nFocus;
  221. this.mbSelectAnimationPlayed = false;
  222. notifyDataSetChanged();
  223. }
  224. /**
  225. * @return the nFocus
  226. */
  227. public Integer getNFocus() {
  228. return this.mnFocus;
  229. }
  230. /**
  231. * populateFocusView - to fill up info for focused element fields
  232. *
  233. * @param elementView - View of element to be populated with extended data
  234. * @param cursor - cursor needed to retrieve extended data
  235. */
  236. public void populateFocusView(final View elementView, final Cursor cursor) {
  237. TextView itemTextView;
  238. String itemText;
  239. // here's additional information should be populated for the sound file
  240. itemTextView = (TextView)elementView.findViewById(R.id.listview_item_artist);
  241. if(null != itemTextView) {
  242. itemText = cursor.getString(cursor.getColumnIndex(AudioColumns.ARTIST));
  243. itemText = "Artist: " + ((itemText == null) ? GALLERYVIEW_UNDEFINED_FIELD : itemText);
  244. itemTextView.setText(itemText);
  245. }
  246. itemTextView = (TextView)elementView.findViewById(R.id.listview_item_album);
  247. if(null != itemTextView) {
  248. itemText = cursor.getString(cursor.getColumnIndex(AudioColumns.ALBUM));
  249. itemText = "Album: " + ((itemText == null) ? GALLERYVIEW_UNDEFINED_FIELD : itemText);
  250. itemTextView.setText(itemText);
  251. }
  252. itemTextView = (TextView)elementView.findViewById(R.id.listview_item_duration);
  253. if(null != itemTextView) {
  254. itemText = cursor.getString(cursor.getColumnIndex(AudioColumns.DURATION));
  255. if(itemText == null) {
  256. itemText = GALLERYVIEW_UNDEFINED_FIELD;
  257. } else {
  258. final Time trackTime = new Time();
  259. Integer nFocusTrackDuration;
  260. nFocusTrackDuration = Long.valueOf(itemText).intValue();
  261. // Set maximum value to progress bar from total time
  262. final ProgressBar progressBar = (ProgressBar)elementView.findViewById(R.id.play_progressbar_bar);
  263. progressBar.setMax(nFocusTrackDuration / 1000);
  264. trackTime.set(nFocusTrackDuration);
  265. // determine how time should be shown - currently check only hours existence
  266. if( trackTime.hour <= 0 ) {
  267. itemText = trackTime.format("%M:%S");
  268. } else {
  269. itemText = trackTime.format("%H:%M:%S");
  270. }
  271. }
  272. itemTextView.setText("Duration: " + itemText);
  273. itemTextView = (TextView)elementView.findViewById(R.id.play_progressbar_total_time);
  274. if(null != itemTextView) {
  275. itemTextView.setText(itemText);
  276. }
  277. }
  278. // check if we're populating now playing view and obtain playing view if missed
  279. if(this.mPlayProgressView == null && this.mnFocus.equals(this.mnPlayIndex)) {
  280. initPlayingProgressView(elementView);
  281. }
  282. if(this.mPlayProgressView != null) {
  283. // show up or hide progress if the file is currently playing
  284. this.mPlayProgressView.setVisibility(this.mnPlayIndex.equals(this.mnFocus) ? View.VISIBLE : View.INVISIBLE);
  285. }
  286. }
  287. /**
  288. * Sets current playing index into adapter and doing setup necessary for playing view
  289. *
  290. * @param nPlayIndex the nPlayIndex to set
  291. * @param listItemView - View of element to be used as playing one
  292. * @throws java.io.IOException - because of MediaPlayer.prepare()
  293. */
  294. public void setNPlayIndex(final Integer nPlayIndex, final View listItemView) throws IOException {
  295. try {
  296. this.mPlayer.reset();
  297. this.mnPlayIndex = nPlayIndex;
  298. GalleryContentItem itemTag = null;
  299. // start play of selected file
  300. if(null != listItemView) {
  301. itemTag = (GalleryContentItem)listItemView.getTag();
  302. }
  303. if(null != itemTag) {
  304. this.mPlayer.setDataSource(itemTag.getContentPath());
  305. this.mPlayer.prepare();
  306. this.mPlayer.start();
  307. }
  308. if(nPlayIndex.equals(this.mnFocus) &&
  309. nPlayIndex >= 0 &&
  310. null != listItemView) {
  311. // reset total play time to 0, because we're beginning to play again
  312. this.mnPlayTime = 0;
  313. // remember play progress view in order to let it to be properly updated
  314. initPlayingProgressView(listItemView);
  315. if(null != this.mPlayProgressView ) {
  316. this.mPlayProgressView.setVisibility(View.VISIBLE);
  317. }
  318. } else {
  319. if(nPlayIndex < 0) {
  320. if(null != this.mPlayProgressView) {
  321. this.mPlayProgressView.setVisibility(View.INVISIBLE);
  322. // need to reset progress also in order to eliminate incorrect play begin
  323. this.mProgressBar.setProgress(0);
  324. }
  325. this.mPlayProgressView = null;
  326. this.mElapsedText = null;
  327. this.mProgressBar = null;
  328. this.mnPlayTime = 0;
  329. this.mPlayProgressUpdateHandler.removeCallbacks(this.mUpdatePlayProgress);
  330. }
  331. }
  332. notifyDataSetChanged();
  333. } catch(final Exception e) {
  334. Log.e(TAG, "setNPlayIndex(): " + e.getClass() + " thrown " + e.getMessage());
  335. }
  336. }
  337. /**
  338. * @return the nPlayIndex
  339. */
  340. public Integer getNPlayIndex() {
  341. return this.mnPlayIndex;
  342. }
  343. @Override
  344. public int getViewTypeCount() {
  345. return 2;
  346. }
  347. @Override
  348. public boolean hasStableIds() {
  349. return false;
  350. }
  351. @Override
  352. public int getItemViewType(final int position) {
  353. int retval = GALLERYLISTVIEW_ITEM_NONACTIVE;
  354. if(position == this.mnFocus) {
  355. retval = GALLERYLISTVIEW_ITEM_ACTIVE;
  356. }
  357. return retval;
  358. }
  359. @Override
  360. public void onCompletion(final MediaPlayer mediaPlayer) {
  361. try {
  362. setNPlayIndex(CGalleryConstants.GALLERY_INVALID_INDEX.value(), null);
  363. this.mPlayProgressUpdateHandler.removeCallbacks(this.mUpdatePlayProgress);
  364. } catch (final IOException e) {
  365. Log.e(TAG, "onCompletion(): " + e.getClass() + " thrown " + e.getMessage());
  366. }
  367. notifyDataSetChanged();
  368. }
  369. /**
  370. * For initializing playProgressView and its utility sub-views
  371. *
  372. * @param elementView - list element view from which progress view should be retrieved
  373. */
  374. private void initPlayingProgressView(final View elementView) {
  375. // remember play progress view in order to let it to be properly updated
  376. this.mPlayProgressView = elementView.findViewById(R.id.listview_play_progressbar);
  377. this.mElapsedText = null;
  378. this.mProgressBar = null;
  379. if(null != this.mPlayProgressView ) {
  380. this.mElapsedText = (TextView)this.mPlayProgressView.findViewById(R.id.play_progressbar_elapsed_time);
  381. this.mProgressBar = (ProgressBar)this.mPlayProgressView.findViewById(R.id.play_progressbar_bar);
  382. if(null != this.mProgressBar) {
  383. this.mProgressBar.setProgress(0);
  384. }
  385. if(null != this.mElapsedText) {
  386. this.mElapsedText.setText(GALLERYVIEW_START_TIME);
  387. }
  388. // NOTE: maximum value for progress bar will be set in the adapter
  389. // here we're also starting timers callbacks for playing
  390. this.mPlayProgressUpdateHandler.removeCallbacks(this.mUpdatePlayProgress);
  391. this.mPlayProgressUpdateHandler.postDelayed(this.mUpdatePlayProgress, CGalleryConstants.GALLERYLIST_PROGRESS_UPDATE_INTERVAL.value());
  392. }
  393. }
  394. }