PageRenderTime 39ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/app/src/main/java/com/music/player/haige/mvp/ui/music/service/MusicDataManager.java

https://bitbucket.org/Naruto-S/haige-android
Java | 1186 lines | 1036 code | 137 blank | 13 comment | 319 complexity | c6499bc0874d9bbc887481bd4235c7af MD5 | raw file
  1. package com.music.player.haige.mvp.ui.music.service;
  2. import android.Manifest;
  3. import android.content.ContentResolver;
  4. import android.content.Context;
  5. import android.content.SharedPreferences;
  6. import android.database.Cursor;
  7. import android.database.MatrixCursor;
  8. import android.net.Uri;
  9. import android.os.SystemClock;
  10. import android.provider.MediaStore;
  11. import android.support.v4.content.PermissionChecker;
  12. import android.text.TextUtils;
  13. import com.google.gson.Gson;
  14. import com.google.gson.reflect.TypeToken;
  15. import com.music.player.haige.mvp.model.entity.music.MusicPlaybackTrack;
  16. import com.music.player.haige.mvp.model.entity.music.Song;
  17. import com.music.player.haige.mvp.model.respository.provider.MusicPlaybackState;
  18. import com.music.player.haige.mvp.model.utils.CommonUtils;
  19. import com.music.player.haige.mvp.model.utils.HaigeUtil;
  20. import com.music.player.haige.mvp.ui.utils.Utils;
  21. import java.io.BufferedReader;
  22. import java.io.File;
  23. import java.io.FileInputStream;
  24. import java.io.InputStream;
  25. import java.io.InputStreamReader;
  26. import java.io.RandomAccessFile;
  27. import java.util.ArrayList;
  28. import java.util.HashMap;
  29. import java.util.LinkedList;
  30. import java.util.ListIterator;
  31. import java.util.Random;
  32. import java.util.TreeSet;
  33. import timber.log.Timber;
  34. /**
  35. * ================================================
  36. * Created by huangcong on 2018/4/3.
  37. * <p>
  38. * 音乐数据管理
  39. * ================================================
  40. */
  41. public class MusicDataManager {
  42. private static final String TAG = MusicDataManager.class.getName();
  43. private static final String[] PROJECTION = new String[]{
  44. "audio._id AS _id", MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM,
  45. MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA,
  46. MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.ALBUM_ID,
  47. MediaStore.Audio.Media.ARTIST_ID
  48. };
  49. private static final String[] PROJECTION_MATRIX = new String[]{
  50. "_id", MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM,
  51. MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA,
  52. MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.ALBUM_ID,
  53. MediaStore.Audio.Media.ARTIST_ID
  54. };
  55. private static final int ID_COLIDX = 0;
  56. public static final int MAX_HISTORY_SIZE = 1000;
  57. public static final int SHUFFLE_NONE = 0;
  58. public static final int SHUFFLE_NORMAL = 1;
  59. public static final int SHUFFLE_AUTO = 2;
  60. public static final int REPEAT_NONE = 2;
  61. public static final int REPEAT_CURRENT = 1;
  62. public static final int REPEAT_ALL = 2;
  63. private MusicService musicService;
  64. private Gson mGson;
  65. private HashMap<Long, Song> mPlaylistInfo = new HashMap<>();
  66. private ArrayList<MusicPlaybackTrack> mPlaylist = new ArrayList<>(100);
  67. private static LinkedList<Integer> mHistory = new LinkedList<>();
  68. private Cursor mCursor;
  69. private int mPlayPos = -1;
  70. private int mNextPlayPos = -1;
  71. private static final Shuffler mShuffler = new Shuffler();
  72. private int mShuffleMode = SHUFFLE_NONE;
  73. private int mRepeatMode = REPEAT_ALL;
  74. private long[] mAutoShuffleList = null;
  75. private int mCardId;
  76. private SharedPreferences mPreferences;
  77. private boolean mQueueIsSaveable = true;
  78. private MusicPlaybackState mPlaybackStateStore;
  79. public long mLastSeekPos = 0;
  80. public MusicDataManager(MusicService musicService, Gson gson) {
  81. this.musicService = musicService;
  82. this.mGson = gson;
  83. this.mPreferences = musicService.getSharedPreferences("Haige_Music_Service", Context.MODE_PRIVATE);
  84. this.mPlaybackStateStore = MusicPlaybackState.getInstance(musicService);
  85. }
  86. public HashMap<Long, Song> getPlaylistInfo() {
  87. return mPlaylistInfo;
  88. }
  89. public void putPlayinfos(final HashMap<Long, Song> songHashMap) {
  90. mPlaylistInfo = songHashMap;
  91. }
  92. public ArrayList<MusicPlaybackTrack> getPlaylist() {
  93. return mPlaylist;
  94. }
  95. public int getPlayPos() {
  96. return mPlayPos;
  97. }
  98. public void setPlayPos(int pos) {
  99. this.mPlayPos = pos;
  100. }
  101. public LinkedList<Integer> getHistory() {
  102. return mHistory;
  103. }
  104. public int getQueueHistoryPosition(int position) {
  105. if (position >= 0 && position < mHistory.size()) {
  106. return mHistory.get(position);
  107. }
  108. return -1;
  109. }
  110. public int[] getQueueHistoryList() {
  111. int[] history = new int[mHistory.size()];
  112. for (int i = 0; i < mHistory.size(); i++) {
  113. history[i] = mHistory.get(i);
  114. }
  115. return history;
  116. }
  117. public Cursor getCursor() {
  118. return mCursor;
  119. }
  120. public String getContentUriPath() {
  121. return MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + mCursor.getLong(ID_COLIDX);
  122. }
  123. public void updateCardId() {
  124. mCardId = getCardId();
  125. }
  126. public int getShuffleMode() {
  127. return mShuffleMode;
  128. }
  129. public int getRepeatMode() {
  130. return mRepeatMode;
  131. }
  132. public void setQueueIsSaveable(boolean mQueueIsSaveable) {
  133. this.mQueueIsSaveable = mQueueIsSaveable;
  134. }
  135. public void setRepeatMode(final int repeatmode) {
  136. mRepeatMode = repeatmode;
  137. setNextTrack();
  138. saveQueue(false);
  139. musicService.notifyChange(musicService.REPEATMODE_CHANGED);
  140. }
  141. public String getPath() {
  142. if (mCursor == null) {
  143. return null;
  144. }
  145. return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.DATA));
  146. }
  147. public String getAlbumName() {
  148. if (mCursor == null) {
  149. return null;
  150. }
  151. return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.ALBUM));
  152. }
  153. public String getAlbumPath() {
  154. if (mCursor == null) {
  155. return null;
  156. }
  157. return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.MIME_TYPE));
  158. }
  159. public String[] getAlbumPathAll() {
  160. try {
  161. int len = mPlaylistInfo.size();
  162. String[] albums = new String[len];
  163. long[] queue = getQueue();
  164. for (int i = 0; i < len; i++) {
  165. albums[i] = mPlaylistInfo.get(queue[i]).albumData;
  166. }
  167. return albums;
  168. } catch (Exception e) {
  169. e.printStackTrace();
  170. }
  171. return new String[]{};
  172. }
  173. public String getTrackName() {
  174. if (mCursor == null) {
  175. return null;
  176. }
  177. return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.TITLE));
  178. }
  179. public boolean isTrackLocal() {
  180. Song info = mPlaylistInfo.get(getAudioId());
  181. if (info == null) {
  182. return true;
  183. }
  184. return info.isLocal;
  185. }
  186. public String getMusicName() {
  187. Song info = mPlaylistInfo.get(getAudioId());
  188. if (info == null) {
  189. return null;
  190. }
  191. return info.musicName;
  192. }
  193. public String getMusicCover() {
  194. Song info = mPlaylistInfo.get(getAudioId());
  195. if (info == null) {
  196. return null;
  197. }
  198. return info.musicCover;
  199. }
  200. public String getMusicUrl() {
  201. Song info = mPlaylistInfo.get(getAudioId());
  202. if (info == null) {
  203. return null;
  204. }
  205. return info.musicPath;
  206. }
  207. public int getMusicLikeCount() {
  208. Song info = mPlaylistInfo.get(getAudioId());
  209. if (info == null) {
  210. return 0;
  211. }
  212. return info.likeCount;
  213. }
  214. public int getMusicShareCount() {
  215. Song info = mPlaylistInfo.get(getAudioId());
  216. if (info == null) {
  217. return 0;
  218. }
  219. return info.shareCount;
  220. }
  221. public int getMusicDownloadCount() {
  222. Song info = mPlaylistInfo.get(getAudioId());
  223. if (info == null) {
  224. return 0;
  225. }
  226. return info.downloadCount;
  227. }
  228. public boolean isFavorite() {
  229. Song info = mPlaylistInfo.get(getAudioId());
  230. if (info == null) {
  231. return true;
  232. }
  233. return info.isFavorite();
  234. }
  235. public String getAlbumPath(long id) {
  236. try {
  237. String str = mPlaylistInfo.get(id).albumData;
  238. return str;
  239. } catch (Exception e) {
  240. e.printStackTrace();
  241. }
  242. return null;
  243. }
  244. public String getGenreName() {
  245. if (mCursor == null || mPlayPos < 0 || mPlayPos >= mPlaylist.size()) {
  246. return null;
  247. }
  248. try {
  249. String[] genreProjection = {MediaStore.Audio.Genres.NAME};
  250. Uri genreUri = MediaStore.Audio.Genres.getContentUriForAudioId("external",
  251. (int) mPlaylist.get(mPlayPos).mId);
  252. Cursor genreCursor = musicService.getContentResolver().query(genreUri, genreProjection,
  253. null, null, null);
  254. if (genreCursor != null) {
  255. try {
  256. if (genreCursor.moveToFirst()) {
  257. return genreCursor.getString(
  258. genreCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME));
  259. }
  260. } finally {
  261. genreCursor.close();
  262. }
  263. }
  264. } catch (Exception e) {
  265. }
  266. return null;
  267. }
  268. public String getArtistName() {
  269. if (mCursor == null) {
  270. return null;
  271. }
  272. return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.ARTIST));
  273. }
  274. public long getAlbumId() {
  275. if (mCursor == null) {
  276. return -1;
  277. }
  278. return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.ALBUM_ID));
  279. }
  280. public long getArtistId() {
  281. if (mCursor == null) {
  282. return -1;
  283. }
  284. return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.ARTIST_ID));
  285. }
  286. public long getAudioId() {
  287. MusicPlaybackTrack track = getCurrentTrack();
  288. if (track != null) {
  289. return track.mId;
  290. }
  291. return -1;
  292. }
  293. public long getLastSeekPos() {
  294. return mLastSeekPos;
  295. }
  296. public MusicPlaybackTrack getCurrentTrack() {
  297. return getTrack(mPlayPos);
  298. }
  299. public synchronized MusicPlaybackTrack getTrack(int index) {
  300. if (index >= 0 && index < mPlaylist.size()) {
  301. return mPlaylist.get(index);
  302. }
  303. return null;
  304. }
  305. public long getNextAudioId() {
  306. if (mNextPlayPos >= 0 && mNextPlayPos < mPlaylist.size() && musicService.mPlayer.isInitialized()) {
  307. return mPlaylist.get(mNextPlayPos).mId;
  308. }
  309. return -1;
  310. }
  311. public long getPreviousAudioId() {
  312. if (musicService.mPlayer.isInitialized()) {
  313. int pos = getPreviousPlayPosition(false);
  314. if (pos >= 0 && pos < mPlaylist.size()) {
  315. return mPlaylist.get(pos).mId;
  316. }
  317. }
  318. return -1;
  319. }
  320. public long[] getQueue() {
  321. final int len = mPlaylist.size();
  322. final long[] list = new long[len];
  323. for (int i = 0; i < len; i++) {
  324. list[i] = mPlaylist.get(i).mId;
  325. }
  326. return list;
  327. }
  328. public long getQueueItemAtPosition(int position) {
  329. if (position >= 0 && position < mPlaylist.size()) {
  330. return mPlaylist.get(position).mId;
  331. }
  332. return -1;
  333. }
  334. public int removeTrack(final long id) {
  335. int numRemoved = 0;
  336. synchronized (this) {
  337. for (int i = 0; i < mPlaylist.size(); i++) {
  338. if (mPlaylist.get(i).mId == id) {
  339. numRemoved += removeTracksInternal(i, i);
  340. i--;
  341. }
  342. }
  343. mPlaylistInfo.remove(id);
  344. }
  345. if (numRemoved > 0) {
  346. musicService.notifyChange(musicService.QUEUE_CHANGED);
  347. }
  348. return numRemoved;
  349. }
  350. public void open(final HashMap<Long, Song> songHashMap, final long[] list, final int position) {
  351. mPlaylistInfo = songHashMap;
  352. Timber.d(mPlaylistInfo.toString());
  353. if (mShuffleMode == SHUFFLE_AUTO) {
  354. mShuffleMode = SHUFFLE_NORMAL;
  355. }
  356. final long oldId = getAudioId();
  357. final int listLength = list.length;
  358. boolean newList = true;
  359. Timber.e(TAG + " the old playlist : " + mPlaylist);
  360. if (mPlaylist.size() == listLength) {
  361. newList = false;
  362. for (int i = 0; i < listLength; i++) {
  363. if (list[i] != mPlaylist.get(i).mId) {
  364. newList = true;
  365. break;
  366. }
  367. }
  368. }
  369. if (newList) {
  370. addToPlayList(list, -1);
  371. musicService.notifyChange(musicService.QUEUE_CHANGED);
  372. }
  373. if (position >= 0) {
  374. mPlayPos = position;
  375. } else {
  376. mPlayPos = mShuffler.nextInt(mPlaylist.size());
  377. }
  378. mHistory.clear();
  379. musicService.openCurrentAndNextPlay(true);
  380. if (oldId != getAudioId()) {
  381. musicService.notifyChange(musicService.META_CHANGED);
  382. }
  383. }
  384. public void setAndRecordPlayPos(int nextPos) {
  385. if (mShuffleMode != SHUFFLE_NONE) {
  386. mHistory.add(mPlayPos);
  387. if (mHistory.size() > MAX_HISTORY_SIZE) {
  388. mHistory.remove(0);
  389. }
  390. }
  391. mPlayPos = nextPos;
  392. }
  393. public void moveQueueItem(int index1, int index2) {
  394. if (index1 >= mPlaylist.size()) {
  395. index1 = mPlaylist.size() - 1;
  396. }
  397. if (index2 >= mPlaylist.size()) {
  398. index2 = mPlaylist.size() - 1;
  399. }
  400. if (index1 == index2) {
  401. return;
  402. }
  403. mPlaylistInfo.remove(mPlaylist.get(index1).mId);
  404. final MusicPlaybackTrack track = mPlaylist.remove(index1);
  405. if (index1 < index2) {
  406. mPlaylist.add(index2, track);
  407. if (mPlayPos == index1) {
  408. mPlayPos = index2;
  409. } else if (mPlayPos >= index1 && mPlayPos <= index2) {
  410. mPlayPos--;
  411. }
  412. } else if (index2 < index1) {
  413. mPlaylist.add(index2, track);
  414. if (mPlayPos == index1) {
  415. mPlayPos = index2;
  416. } else if (mPlayPos >= index2 && mPlayPos <= index1) {
  417. mPlayPos++;
  418. }
  419. }
  420. }
  421. public void cycleRepeat() {
  422. if (mRepeatMode == REPEAT_NONE) {
  423. setRepeatMode(REPEAT_CURRENT);
  424. if (mShuffleMode != SHUFFLE_NONE) {
  425. setShuffleMode(SHUFFLE_NONE);
  426. }
  427. } else {
  428. setRepeatMode(REPEAT_NONE);
  429. }
  430. }
  431. public void cycleShuffle() {
  432. if (mShuffleMode == SHUFFLE_NONE) {
  433. setShuffleMode(SHUFFLE_NORMAL);
  434. if (mRepeatMode == REPEAT_CURRENT) {
  435. setRepeatMode(REPEAT_ALL);
  436. }
  437. } else if (mShuffleMode == SHUFFLE_NORMAL || mShuffleMode == SHUFFLE_AUTO) {
  438. setShuffleMode(SHUFFLE_NONE);
  439. }
  440. }
  441. public String openFile(String path) {
  442. if (mCursor == null) {
  443. Uri uri = Uri.parse(path);
  444. boolean shouldAddToPlaylist = true;
  445. long id = -1;
  446. try {
  447. id = Long.valueOf(uri.getLastPathSegment());
  448. } catch (NumberFormatException ex) {
  449. // Ignore
  450. }
  451. if (id != -1 && path.startsWith(
  452. MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString())) {
  453. updateCursor(uri);
  454. } else if (id != -1 && path.startsWith(
  455. MediaStore.Files.getContentUri("external").toString())) {
  456. updateCursor(id);
  457. } else if (path.startsWith("content://downloads/")) {
  458. String mpUri = getValueForDownloadedFile(musicService, uri, "mediaprovider_uri");
  459. Timber.d(TAG + "Downloaded file's MP uri : " + mpUri);
  460. if (!TextUtils.isEmpty(mpUri)) {
  461. return mpUri;
  462. } else {
  463. updateCursorForDownloadedFile(musicService, uri);
  464. shouldAddToPlaylist = false;
  465. }
  466. } else {
  467. String where = MediaStore.Audio.Media.DATA + "=?";
  468. String[] selectionArgs = new String[]{path};
  469. updateCursor(where, selectionArgs);
  470. }
  471. try {
  472. if (mCursor != null && shouldAddToPlaylist) {
  473. mPlaylist.clear();
  474. mPlaylist.add(new MusicPlaybackTrack(mCursor.getLong(ID_COLIDX), -1, HaigeUtil.IdType.NA, -1));
  475. musicService.notifyChange(musicService.QUEUE_CHANGED);
  476. mPlayPos = 0;
  477. mHistory.clear();
  478. }
  479. } catch (final UnsupportedOperationException ex) {
  480. // Ignore
  481. }
  482. }
  483. return null;
  484. }
  485. public boolean notifyMetaChanged(String mpUri) {
  486. if (musicService.openFile(mpUri)) {
  487. musicService.notifyChange(MusicService.META_CHANGED);
  488. return true;
  489. } else {
  490. return false;
  491. }
  492. }
  493. public void updateCursor(final long musicId) {
  494. Song info = mPlaylistInfo.get(musicId);
  495. if (info != null) {
  496. MatrixCursor cursor = new MatrixCursor(PROJECTION);
  497. cursor.addRow(new Object[]{info.songId, info.artistName, info.albumName, info.musicName
  498. , info.musicPath, info.albumData, info.albumId, info.artistId});
  499. cursor.moveToFirst();
  500. mCursor = cursor;
  501. cursor.close();
  502. }
  503. }
  504. private void updateCursor(final String selection, final String[] selectionArgs) {
  505. synchronized (this) {
  506. closeCursor();
  507. mCursor = openCursorAndGoToFirst(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
  508. PROJECTION, selection, selectionArgs);
  509. }
  510. }
  511. private void updateCursor(final Uri uri) {
  512. synchronized (this) {
  513. closeCursor();
  514. mCursor = openCursorAndGoToFirst(uri, PROJECTION, null, null);
  515. }
  516. }
  517. private void updateCursorForDownloadedFile(Context context, Uri uri) {
  518. synchronized (this) {
  519. closeCursor();
  520. MatrixCursor cursor = new MatrixCursor(PROJECTION_MATRIX);
  521. String title = getValueForDownloadedFile(context, uri, "title");
  522. cursor.addRow(new Object[]{
  523. null,
  524. null,
  525. null,
  526. title,
  527. null,
  528. null,
  529. null,
  530. null
  531. });
  532. mCursor = cursor;
  533. mCursor.moveToFirst();
  534. }
  535. }
  536. private String getValueForDownloadedFile(Context context, Uri uri, String column) {
  537. Cursor cursor = null;
  538. final String[] projection = {
  539. column
  540. };
  541. try {
  542. cursor = context.getContentResolver().query(uri, projection, null, null, null);
  543. if (cursor != null && cursor.moveToFirst()) {
  544. return cursor.getString(0);
  545. }
  546. } finally {
  547. if (cursor != null) {
  548. cursor.close();
  549. }
  550. }
  551. return null;
  552. }
  553. public synchronized void closeCursor() {
  554. if (mCursor != null) {
  555. mCursor.close();
  556. mCursor = null;
  557. }
  558. }
  559. private Cursor openCursorAndGoToFirst(Uri uri, String[] projection,
  560. String selection, String[] selectionArgs) {
  561. Cursor c = musicService.getContentResolver().query(uri, projection,
  562. selection, selectionArgs, null);
  563. if (c == null) {
  564. return null;
  565. }
  566. if (!c.moveToFirst()) {
  567. c.close();
  568. return null;
  569. }
  570. return c;
  571. }
  572. public void addToPlayList(final long[] list, int position) {
  573. final int addLen = list.length;
  574. if (position < 0) {
  575. mPlaylist.clear();
  576. position = 0;
  577. }
  578. mPlaylist.ensureCapacity(mPlaylist.size() + addLen);
  579. if (position > mPlaylist.size()) {
  580. position = mPlaylist.size();
  581. }
  582. final ArrayList<MusicPlaybackTrack> arrayList = new ArrayList<MusicPlaybackTrack>(addLen);
  583. for (int i = 0; i < list.length; i++) {
  584. arrayList.add(new MusicPlaybackTrack(list[i], i, HaigeUtil.IdType.NA, -1));
  585. }
  586. mPlaylist.addAll(position, arrayList);
  587. if (mPlaylist.size() == 0) {
  588. closeCursor();
  589. musicService.notifyChange(musicService.META_CHANGED);
  590. }
  591. }
  592. public int removeTracksInternal(int first, int last) {
  593. if (last < first) {
  594. return 0;
  595. } else if (first < 0) {
  596. first = 0;
  597. } else if (last >= mPlaylist.size()) {
  598. last = mPlaylist.size() - 1;
  599. }
  600. boolean gotonext = false;
  601. if (first <= mPlayPos && mPlayPos <= last) {
  602. mPlayPos = first;
  603. gotonext = true;
  604. } else if (mPlayPos > last) {
  605. mPlayPos -= last - first + 1;
  606. }
  607. final int numToRemove = last - first + 1;
  608. if (first == 0 && last == mPlaylist.size() - 1) {
  609. mPlayPos = -1;
  610. mNextPlayPos = -1;
  611. mPlaylist.clear();
  612. mHistory.clear();
  613. } else {
  614. for (int i = 0; i < numToRemove; i++) {
  615. mPlaylistInfo.remove(mPlaylist.get(first).mId);
  616. mPlaylist.remove(first);
  617. }
  618. ListIterator<Integer> positionIterator = mHistory.listIterator();
  619. while (positionIterator.hasNext()) {
  620. int pos = positionIterator.next();
  621. if (pos >= first && pos <= last) {
  622. positionIterator.remove();
  623. } else if (pos > last) {
  624. positionIterator.set(pos - numToRemove);
  625. }
  626. }
  627. }
  628. if (gotonext) {
  629. if (mPlaylist.size() == 0) {
  630. musicService.stop(true);
  631. mPlayPos = -1;
  632. closeCursor();
  633. } else {
  634. if (mShuffleMode != SHUFFLE_NONE) {
  635. mPlayPos = getNextPosition(true);
  636. } else if (mPlayPos >= mPlaylist.size()) {
  637. mPlayPos = 0;
  638. }
  639. final boolean wasPlaying = musicService.isPlaying();
  640. musicService.stop(false);
  641. musicService.openCurrentAndNext();
  642. if (wasPlaying) {
  643. musicService.play();
  644. }
  645. }
  646. musicService.notifyChange(musicService.META_CHANGED);
  647. }
  648. return last - first + 1;
  649. }
  650. public void setNextPosition(int nextPosition) {
  651. this.mNextPlayPos = nextPosition;
  652. }
  653. public int getNextPosition() {
  654. return mNextPlayPos;
  655. }
  656. public int getNextPosition(final boolean force) {
  657. if (mPlaylist == null || mPlaylist.isEmpty()) {
  658. return -1;
  659. }
  660. if (!force && mRepeatMode == REPEAT_CURRENT) {
  661. if (mPlayPos < 0) {
  662. return 0;
  663. }
  664. return mPlayPos;
  665. } else if (mShuffleMode == SHUFFLE_NORMAL) {
  666. final int numTracks = mPlaylist.size();
  667. final int[] trackNumPlays = new int[numTracks];
  668. for (int i = 0; i < numTracks; i++) {
  669. trackNumPlays[i] = 0;
  670. }
  671. final int numHistory = mHistory.size();
  672. for (int i = 0; i < numHistory; i++) {
  673. final int idx = mHistory.get(i).intValue();
  674. if (idx >= 0 && idx < numTracks) {
  675. trackNumPlays[idx]++;
  676. }
  677. }
  678. if (mPlayPos >= 0 && mPlayPos < numTracks) {
  679. trackNumPlays[mPlayPos]++;
  680. }
  681. int minNumPlays = Integer.MAX_VALUE;
  682. int numTracksWithMinNumPlays = 0;
  683. for (int i = 0; i < trackNumPlays.length; i++) {
  684. if (trackNumPlays[i] < minNumPlays) {
  685. minNumPlays = trackNumPlays[i];
  686. numTracksWithMinNumPlays = 1;
  687. } else if (trackNumPlays[i] == minNumPlays) {
  688. numTracksWithMinNumPlays++;
  689. }
  690. }
  691. if (minNumPlays > 0 && numTracksWithMinNumPlays == numTracks
  692. && mRepeatMode != REPEAT_ALL && !force) {
  693. return -1;
  694. }
  695. int skip = mShuffler.nextInt(numTracksWithMinNumPlays);
  696. for (int i = 0; i < trackNumPlays.length; i++) {
  697. if (trackNumPlays[i] == minNumPlays) {
  698. if (skip == 0) {
  699. return i;
  700. } else {
  701. skip--;
  702. }
  703. }
  704. }
  705. Timber.d(TAG + " Getting the next position resulted did not get a result when it should have");
  706. return -1;
  707. } else if (mShuffleMode == SHUFFLE_AUTO) {
  708. doAutoShuffleUpdate();
  709. return mPlayPos + 1;
  710. } else {
  711. if (mPlayPos >= mPlaylist.size() - 1) {
  712. if (mRepeatMode == REPEAT_NONE && !force) {
  713. return -1;
  714. } else if (mRepeatMode == REPEAT_ALL || force) {
  715. return 0;
  716. }
  717. return -1;
  718. } else {
  719. return mPlayPos + 1;
  720. }
  721. }
  722. }
  723. public void doAutoShuffleUpdate() {
  724. boolean notify = false;
  725. if (mPlayPos > 10) {
  726. removeTracks(0, mPlayPos - 9);
  727. notify = true;
  728. }
  729. final int toAdd = 7 - (mPlaylist.size() - (mPlayPos < 0 ? -1 : mPlayPos));
  730. for (int i = 0; i < toAdd; i++) {
  731. int lookback = mHistory.size();
  732. int idx = -1;
  733. while (true) {
  734. idx = mShuffler.nextInt(mAutoShuffleList.length);
  735. if (!wasRecentlyUsed(idx, lookback)) {
  736. break;
  737. }
  738. lookback /= 2;
  739. }
  740. mHistory.add(idx);
  741. if (mHistory.size() > MAX_HISTORY_SIZE) {
  742. mHistory.remove(0);
  743. }
  744. mPlaylist.add(new MusicPlaybackTrack(mAutoShuffleList[idx], -1, HaigeUtil.IdType.NA, -1));
  745. notify = true;
  746. }
  747. if (notify) {
  748. musicService.notifyChange(musicService.QUEUE_CHANGED);
  749. }
  750. }
  751. public void reloadQueue() {
  752. int id = mCardId;
  753. if (mPreferences.contains("cardid")) {
  754. id = mPreferences.getInt("cardid", ~mCardId);
  755. }
  756. if (id == mCardId) {
  757. mPlaylist = mPlaybackStateStore.getQueue();
  758. try {
  759. FileInputStream in = new FileInputStream(new File(musicService.getCacheDir().getAbsolutePath() + "playlist"));
  760. String c = readTextFromSDcard(in);
  761. HashMap<Long, Song> play = mGson.fromJson(c, new TypeToken<HashMap<Long, Song>>() {
  762. }.getType());
  763. if (play != null && play.size() > 0) {
  764. mPlaylistInfo = play;
  765. Timber.d(TAG + " " + mPlaylistInfo.keySet().toString());
  766. }
  767. } catch (Exception e) {
  768. e.printStackTrace();
  769. }
  770. }
  771. if ((mPlaylist.size() == mPlaylistInfo.size()) && mPlaylist.size() > 0) {
  772. final int pos = mPreferences.getInt("curpos", 0);
  773. if (pos < 0 || pos >= mPlaylist.size()) {
  774. mPlaylist.clear();
  775. return;
  776. }
  777. mPlayPos = pos;
  778. updateCursor(mPlaylist.get(mPlayPos).mId);
  779. if (mCursor == null) {
  780. SystemClock.sleep(3000);
  781. updateCursor(mPlaylist.get(mPlayPos).mId);
  782. }
  783. synchronized (this) {
  784. closeCursor();
  785. musicService.setOpenFailedCounter(20);
  786. musicService.openCurrentAndNext();
  787. }
  788. // if (!mPlayer.isInitialized() && isTrackLocal()) {
  789. // mPlaylist.clear();
  790. // return;
  791. // }
  792. final long seekpos = mPreferences.getLong("seekpos", 0);
  793. mLastSeekPos = seekpos;
  794. musicService.seek(seekpos >= 0 && seekpos < musicService.duration() ? seekpos : 0);
  795. Timber.d(TAG + " restored queue, currently at position "
  796. + musicService.position() + "/" + musicService.duration()
  797. + " (requested " + seekpos + ")");
  798. int repMode = mPreferences.getInt("repeatmode", REPEAT_ALL);
  799. if (repMode != REPEAT_ALL && repMode != REPEAT_CURRENT) {
  800. repMode = REPEAT_NONE;
  801. }
  802. mRepeatMode = repMode;
  803. int shuffleMode = mPreferences.getInt("shufflemode", SHUFFLE_NONE);
  804. if (shuffleMode != SHUFFLE_AUTO && shuffleMode != SHUFFLE_NORMAL) {
  805. shuffleMode = SHUFFLE_NONE;
  806. }
  807. if (shuffleMode != SHUFFLE_NONE) {
  808. mHistory = mPlaybackStateStore.getHistory(mPlaylist.size());
  809. }
  810. if (shuffleMode == SHUFFLE_AUTO) {
  811. if (!makeAutoShuffleList()) {
  812. shuffleMode = SHUFFLE_NONE;
  813. }
  814. }
  815. mShuffleMode = shuffleMode;
  816. } else {
  817. clearPlayInfo();
  818. }
  819. musicService.notifyChange(musicService.MUSIC_CHANGED);
  820. }
  821. public boolean removeTrackAtPosition(final long id, final int position) {
  822. synchronized (this) {
  823. if (position >= 0 &&
  824. position < mPlaylist.size() &&
  825. mPlaylist.get(position).mId == id) {
  826. mPlaylistInfo.remove(id);
  827. return removeTracks(position, position) > 0;
  828. }
  829. }
  830. return false;
  831. }
  832. public int removeTracks(final int first, final int last) {
  833. final int numremoved = removeTracksInternal(first, last);
  834. if (numremoved > 0) {
  835. musicService.notifyChange(musicService.QUEUE_CHANGED);
  836. }
  837. return numremoved;
  838. }
  839. public void clearPlayInfo() {
  840. File file = new File(musicService.getCacheDir().getAbsolutePath() + "playlist");
  841. if (file.exists()) {
  842. file.delete();
  843. }
  844. MusicPlaybackState.getInstance(musicService).clearQueue();
  845. }
  846. private int getCardId() {
  847. if (CommonUtils.isMarshmallow()) {
  848. if (PermissionChecker.PERMISSION_GRANTED == PermissionChecker.checkSelfPermission(musicService.getBaseContext(), Manifest.permission.READ_EXTERNAL_STORAGE)) {
  849. return getmCardId();
  850. } else return 0;
  851. } else {
  852. return getmCardId();
  853. }
  854. }
  855. private int getmCardId() {
  856. final ContentResolver resolver = musicService.getContentResolver();
  857. Cursor cursor = resolver.query(Uri.parse("content://media/external/fs_id"), null, null,
  858. null, null);
  859. int mCardId = -1;
  860. if (cursor != null && cursor.moveToFirst()) {
  861. mCardId = cursor.getInt(0);
  862. cursor.close();
  863. }
  864. return mCardId;
  865. }
  866. public void updateNextTrack() {
  867. if (mNextPlayPos >= 0 && mNextPlayPos < mPlaylist.size()
  868. && getShuffleMode() != SHUFFLE_NONE) {
  869. setNextTrack(mNextPlayPos);
  870. } else {
  871. setNextTrack();
  872. }
  873. }
  874. public void setNextTrack() {
  875. setNextTrack(getNextPosition(false));
  876. }
  877. public void setNextTrack(int position) {
  878. mNextPlayPos = position;
  879. Timber.e(TAG + " setNextTrack: next play position = " + mNextPlayPos);
  880. if (mNextPlayPos >= 0 && mPlaylist != null && mNextPlayPos < mPlaylist.size()) {
  881. final long id = mPlaylist.get(mNextPlayPos).mId;
  882. Song song = mPlaylistInfo.get(id);
  883. if (song != null) {
  884. if (mPlaylistInfo.get(id).isLocal) {
  885. musicService.setNextDataSource(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id);
  886. } else {
  887. musicService.setNextDataSource(null);
  888. }
  889. }
  890. } else {
  891. musicService.setNextDataSource(null);
  892. }
  893. }
  894. private boolean wasRecentlyUsed(final int idx, int lookbacksize) {
  895. if (lookbacksize == 0) {
  896. return false;
  897. }
  898. final int histsize = mHistory.size();
  899. if (histsize < lookbacksize) {
  900. lookbacksize = histsize;
  901. }
  902. final int maxidx = histsize - 1;
  903. for (int i = 0; i < lookbacksize; i++) {
  904. final long entry = mHistory.get(maxidx - i);
  905. if (entry == idx) {
  906. return true;
  907. }
  908. }
  909. return false;
  910. }
  911. private boolean makeAutoShuffleList() {
  912. Cursor cursor = null;
  913. try {
  914. cursor = musicService.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
  915. new String[]{
  916. MediaStore.Audio.Media._ID
  917. }, MediaStore.Audio.Media.IS_MUSIC + "=1", null, null);
  918. if (cursor == null || cursor.getCount() == 0) {
  919. return false;
  920. }
  921. final int len = cursor.getCount();
  922. final long[] list = new long[len];
  923. for (int i = 0; i < len; i++) {
  924. cursor.moveToNext();
  925. list[i] = cursor.getLong(0);
  926. }
  927. mAutoShuffleList = list;
  928. return true;
  929. } catch (final RuntimeException e) {
  930. } finally {
  931. if (cursor != null) {
  932. cursor.close();
  933. cursor = null;
  934. }
  935. }
  936. return false;
  937. }
  938. public void saveQueue(final boolean full) {
  939. if (!mQueueIsSaveable) {
  940. return;
  941. }
  942. final SharedPreferences.Editor editor = mPreferences.edit();
  943. if (full) {
  944. try {
  945. mPlaybackStateStore.saveState(mPlaylist, mShuffleMode != SHUFFLE_NONE ? mHistory : null);
  946. if (mPlaylistInfo.size() > 0) {
  947. String temp = mGson.toJson(mPlaylistInfo);
  948. File file = new File(musicService.getCacheDir().getAbsolutePath() + "playlist");
  949. RandomAccessFile ra = new RandomAccessFile(file, "rws");
  950. ra.write(temp.getBytes());
  951. ra.close();
  952. }
  953. editor.putInt("cardid", mCardId);
  954. } catch (Exception e) {
  955. e.printStackTrace();
  956. }
  957. }
  958. editor.putInt("curpos", mPlayPos);
  959. if (Utils.isNotNull(musicService.mPlayer) && musicService.mPlayer.isInitialized()) {
  960. editor.putLong("seekpos", musicService.mPlayer.position());
  961. }
  962. editor.putInt("repeatmode", mRepeatMode);
  963. editor.putInt("shufflemode", mShuffleMode);
  964. editor.apply();
  965. }
  966. public void setShuffleMode(final int shufflemode) {
  967. if (mShuffleMode == shufflemode && mPlaylist.size() > 0) {
  968. return;
  969. }
  970. mShuffleMode = shufflemode;
  971. if (mShuffleMode == SHUFFLE_AUTO) {
  972. if (makeAutoShuffleList()) {
  973. mPlaylist.clear();
  974. doAutoShuffleUpdate();
  975. mPlayPos = 0;
  976. musicService.openCurrentAndNext();
  977. musicService.play();
  978. musicService.notifyChange(musicService.META_CHANGED);
  979. return;
  980. } else {
  981. mShuffleMode = SHUFFLE_NONE;
  982. }
  983. } else {
  984. setNextTrack();
  985. }
  986. saveQueue(false);
  987. musicService.notifyChange(musicService.SHUFFLEMODE_CHANGED);
  988. }
  989. private String readTextFromSDcard(InputStream is) throws Exception {
  990. InputStreamReader reader = new InputStreamReader(is);
  991. BufferedReader bufferedReader = new BufferedReader(reader);
  992. StringBuffer buffer = new StringBuffer();
  993. String str;
  994. while ((str = bufferedReader.readLine()) != null) {
  995. buffer.append(str);
  996. buffer.append("\n");
  997. }
  998. return buffer.toString();
  999. }
  1000. public int getPreviousPlayPosition(boolean removeFromHistory) {
  1001. synchronized (this) {
  1002. if (mShuffleMode == SHUFFLE_NORMAL) {
  1003. final int histsize = mHistory.size();
  1004. if (histsize == 0) {
  1005. return -1;
  1006. }
  1007. final Integer pos = mHistory.get(histsize - 1);
  1008. if (removeFromHistory) {
  1009. mHistory.remove(histsize - 1);
  1010. }
  1011. return pos.intValue();
  1012. } else {
  1013. if (mPlayPos > 0) {
  1014. return mPlayPos - 1;
  1015. } else {
  1016. return mPlaylist.size() - 1;
  1017. }
  1018. }
  1019. }
  1020. }
  1021. private static final class Shuffler {
  1022. private final LinkedList<Integer> mHistoryOfNumbers = new LinkedList<Integer>();
  1023. private final TreeSet<Integer> mPreviousNumbers = new TreeSet<Integer>();
  1024. private final Random mRandom = new Random();
  1025. private int mPrevious;
  1026. public Shuffler() {
  1027. super();
  1028. }
  1029. public int nextInt(final int interval) {
  1030. int next;
  1031. do {
  1032. next = mRandom.nextInt(interval);
  1033. } while (next == mPrevious && interval > 1
  1034. && !mPreviousNumbers.contains(Integer.valueOf(next)));
  1035. mPrevious = next;
  1036. mHistoryOfNumbers.add(mPrevious);
  1037. mPreviousNumbers.add(mPrevious);
  1038. cleanUpHistory();
  1039. return next;
  1040. }
  1041. private void cleanUpHistory() {
  1042. if (!mHistoryOfNumbers.isEmpty() && mHistoryOfNumbers.size() >= MAX_HISTORY_SIZE) {
  1043. for (int i = 0; i < Math.max(1, MAX_HISTORY_SIZE / 2); i++) {
  1044. mPreviousNumbers.remove(mHistoryOfNumbers.removeFirst());
  1045. }
  1046. }
  1047. }
  1048. }
  1049. }