Add async support to SuperUserCommands

Add a simple MusicTrackListAdapter to the activity
Loading the artworks in the adapter
Add a download link to the README.md
This commit is contained in:
David Schulte 2015-01-27 00:04:51 +01:00
parent 0598cbccc4
commit 0a3b9b95ee
18 changed files with 473 additions and 141 deletions

View file

@ -5,8 +5,10 @@ This Android app exports your Play Music mp3 files directly to your sdcard. Even
## Notice
This project will be rewritten and the complete source will be a available soon.
The android package id is currently "de.arcus.playmusicexporter2". I did this to work on both version while i'm working on the new code version. This will be replaced by the old id "de.arcus.playmusicexporter" when the new code is done.
The android package id is currently "de.arcus.playmusicexporter2". This will be replaced by the old id "de.arcus.playmusicexporter" when the new code is done.
You can get the current working version here: https://www.david-schulte.de/en/play-music-exporter-updater/
## Copyright
Copyright (c) 2015 David Schulte. See LICENSE.txt for details.
Copyright (c) 2015 David Schulte. See LICENSE.txt for details.

View file

@ -22,6 +22,8 @@
package de.arcus.framework.superuser;
import android.app.Activity;
import org.apache.http.util.ByteArrayBuffer;
import java.io.BufferedReader;
@ -97,10 +99,16 @@ public class SuperUserCommand {
*/
private boolean mBinaryStandardOutput = false;
/**
* @return Gets whether the output will be binary
*/
public boolean getBinaryStandardOutput() {
return mBinaryStandardOutput;
}
/**
* @param binaryStandardOutput Set this if you want a binary output
*/
public void setBinaryStandardOutput(boolean binaryStandardOutput) {
mBinaryStandardOutput = binaryStandardOutput;
}
@ -169,6 +177,16 @@ public class SuperUserCommand {
return (!mSuperUserFailed);
}
/**
* The async execution thread
*/
private SuperUserCommandThread mThread;
/**
* The async callback
*/
private SuperUserCommandCallback mCallback;
/**
* Creates a command with one command line
* @param command The command
@ -188,10 +206,41 @@ public class SuperUserCommand {
mTimeout = DEFAULT_COMMAND_TIMEOUT;
}
/**
* Execute the command asynchronously.
* Please notice that the commands will only executed one after another.
* The command will wait until the su process is free.
* @param callback The callback instance
*/
public void executeAsync(SuperUserCommandCallback callback) {
mCallback = callback;
// Thread is running
if (mThread != null) return;
// Create a new thread
mThread = new SuperUserCommandThread();
// Starts a thread
mThread.start();
}
/**
* Execute the command asynchronously.
* Please notice that the commands will only executed one after another.
* The command will wait until the su process is free.
* @param callback The callback instance
* @param activity Set the activity to execute the callback on the UI thread
*/
public void executeAsync(SuperUserCommandCallback callback, Activity activity) {
}
/**
* Execute the command and return whether the command was executed.
* It will only return false if the app wasn't granted superuser permissions, like {@link #superuserWasSuccessful()}.
* It will also return true if the command itself returns error outputs. To check this case you should use {@link #commandWasSuccessful()} instead.
* Please consider to use {@link #executeAsync} instead of this and execute the command asynchronously.
* @return Gets whether the execution was successful.
*/
public boolean execute() {
@ -319,4 +368,22 @@ public class SuperUserCommand {
}
}
}
/**
* Thread to executes the command asynchronously
*/
private class SuperUserCommandThread extends Thread {
@Override
public void run() {
super.run();
// Executes the command
execute();
if (mCallback != null)
mCallback.onFinished(SuperUserCommand.this);
}
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015 David Schulte
*
* 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 de.arcus.framework.superuser;
/**
* Callback class if the async execution is finish
*/
public interface SuperUserCommandCallback {
/**
* Callback event
* @param command The command that finished
*/
public abstract void onFinished(SuperUserCommand command);
}

View file

@ -95,4 +95,19 @@ public class SuperUserTools {
return superUserCommand.getStandardOutputBinary();
}
/**
* Gets all bytes from one file
* @param path The path to the file
* @param callback The callback
*/
public static void fileReadToByteArrayAsync(String path, SuperUserCommandCallback callback) {
SuperUserCommand superUserCommand = new SuperUserCommand("cat '" + path + "'");
// Don't spam the log with binary code
superUserCommand.setHideStandardOutput(true);
superUserCommand.setBinaryStandardOutput(true);
superUserCommand.executeAsync(callback);
}
}

View file

@ -61,8 +61,8 @@ public class TrackDetailActivity extends ActionBarActivity {
// Create the detail fragment and add it to the activity
// using a fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(TrackDetailFragment.ARG_ITEM_ID,
getIntent().getStringExtra(TrackDetailFragment.ARG_ITEM_ID));
arguments.putString(TrackDetailFragment.ARG_MUSIC_TRACK_LIST,
getIntent().getStringExtra(TrackDetailFragment.ARG_MUSIC_TRACK_LIST));
TrackDetailFragment fragment = new TrackDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()

View file

@ -29,8 +29,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import de.arcus.playmusiclib.items.MusicTrackList;
import de.arcus.playmusicexporter2.dummy.DummyContent;
/**
* A fragment representing a single Track detail screen.
@ -43,12 +43,14 @@ public class TrackDetailFragment extends Fragment {
* The fragment argument representing the item ID that this fragment
* represents.
*/
public static final String ARG_ITEM_ID = "item_id";
public static final String ARG_MUSIC_TRACK_LIST = "music_track_list";
/**
* The dummy content this fragment is presenting.
* The track list
*/
private DummyContent.DummyItem mItem;
private MusicTrackList mMusicTrackList;
private String mTest;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
@ -61,11 +63,12 @@ public class TrackDetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments().containsKey(ARG_ITEM_ID)) {
if (getArguments().containsKey(ARG_MUSIC_TRACK_LIST)) {
// Load the dummy content specified by the fragment
// arguments. In a real-world scenario, use a Loader
// to load content from a content provider.
mItem = DummyContent.ITEM_MAP.get(getArguments().getString(ARG_ITEM_ID));
// mMusicTrackList = (MusicTrackList)getArguments().getSerializable(ARG_MUSIC_TRACK_LIST);
mTest = getArguments().getString(ARG_MUSIC_TRACK_LIST);
}
}
@ -75,8 +78,8 @@ public class TrackDetailFragment extends Fragment {
View rootView = inflater.inflate(R.layout.fragment_track_detail, container, false);
// Show the dummy content as text in a TextView.
if (mItem != null) {
((TextView) rootView.findViewById(R.id.track_detail)).setText(mItem.content);
if (mTest != null) {
((TextView) rootView.findViewById(R.id.track_detail)).setText(mTest);
}
return rootView;

View file

@ -24,20 +24,14 @@ package de.arcus.playmusicexporter2;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import java.util.List;
import de.arcus.framework.logger.Logger;
import de.arcus.framework.crashhandler.CrashHandler;
import de.arcus.playmusiclib.PlayMusicManager;
import de.arcus.playmusiclib.datasources.PlaylistDataSource;
import de.arcus.playmusiclib.datasources.AlbumDataSource;
import de.arcus.playmusiclib.enums.ID3v2Version;
import de.arcus.playmusiclib.items.MusicTrack;
import de.arcus.playmusiclib.items.Playlist;
/**
* An activity representing a list of Tracks. This activity
@ -108,32 +102,16 @@ public class TrackListActivity extends ActionBarActivity
playMusicManager.setID3EnableFallback(true);
playMusicManager.setID3v2Version(ID3v2Version.ID3v23);
PlaylistDataSource playlistDataSource = new PlaylistDataSource(playMusicManager);
playMusicManager.copyDatabaseToSdCard();
playlistDataSource.setSerchKey("Angesagte Songs");
AlbumDataSource albumDataSource = new AlbumDataSource(playMusicManager);
// Load all albums
List<Playlist> playlists = playlistDataSource.getAll();
for (Playlist playlist : playlists) {
// Load tracks from album
List<MusicTrack> tracks = playlist.getMusicTrackList();
for (MusicTrack track : tracks) {
// Test: exports the track to the sd card
String filename = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) + "/"+track.getTitle()+".mp3";
boolean success = playMusicManager.exportMusicTrack(track, filename);
Log.d("Debug", track.getTitle() + ": " + success);
}
}
((TrackListFragment) getSupportFragmentManager()
.findFragmentById(R.id.track_list)).setList(albumDataSource.getAll());
} catch (Exception e) {
Logger.getInstance().logError("Test", e.toString());
}
// TODO: If exposing deep links into your app, handle intents here.
}
/**
@ -147,7 +125,7 @@ public class TrackListActivity extends ActionBarActivity
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(TrackDetailFragment.ARG_ITEM_ID, id);
arguments.putString(TrackDetailFragment.ARG_MUSIC_TRACK_LIST, id);
TrackDetailFragment fragment = new TrackDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
@ -158,7 +136,7 @@ public class TrackListActivity extends ActionBarActivity
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, TrackDetailActivity.class);
detailIntent.putExtra(TrackDetailFragment.ARG_ITEM_ID, id);
detailIntent.putExtra(TrackDetailFragment.ARG_MUSIC_TRACK_LIST, id);
startActivity(detailIntent);
}
}

View file

@ -26,11 +26,14 @@ import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import de.arcus.playmusicexporter2.dummy.DummyContent;
import java.util.ArrayList;
import java.util.List;
import de.arcus.playmusicexporter2.adapter.MusicTrackListAdapter;
import de.arcus.playmusiclib.items.MusicTrackList;
/**
* A list fragment representing a list of Tracks. This fragment
@ -82,6 +85,8 @@ public class TrackListFragment extends ListFragment {
}
};
private MusicTrackListAdapter mMusicTrackListAdapter;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
@ -89,16 +94,30 @@ public class TrackListFragment extends ListFragment {
public TrackListFragment() {
}
/**
* @param list Set the list
*/
public void setList(List<? extends MusicTrackList> list) {
// Create a new list
List<MusicTrackList> newList = new ArrayList<>();
// Copy the list
for(MusicTrackList musicTrackList : list) {
newList.add(musicTrackList);
}
// Set the list in the adapter
mMusicTrackListAdapter.setList(newList);
getListView().invalidateViews();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TODO: replace with a real list adapter.
setListAdapter(new ArrayAdapter<>(
getActivity(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1,
DummyContent.ITEMS));
mMusicTrackListAdapter = new MusicTrackListAdapter(getActivity());
setListAdapter(mMusicTrackListAdapter);
}
@Override
@ -138,7 +157,7 @@ public class TrackListFragment extends ListFragment {
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);
mCallbacks.onItemSelected(mMusicTrackListAdapter.getList().get(position).getTitle());
}
@Override

View file

@ -0,0 +1,211 @@
/*
* Copyright (c) 2015 David Schulte
*
* 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 de.arcus.playmusicexporter2.adapter;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;
import java.util.List;
import de.arcus.framework.superuser.SuperUserCommand;
import de.arcus.framework.superuser.SuperUserCommandCallback;
import de.arcus.framework.superuser.SuperUserTools;
import de.arcus.playmusicexporter2.R;
import de.arcus.playmusiclib.items.MusicTrackList;
/**
* Adapter for the music track lists
*/
public class MusicTrackListAdapter implements ListAdapter {
/**
* The context of the app
*/
private Context mContext;
/**
* The list
*/
private List<MusicTrackList> mList;
/**
* @param list Sets a new list
*/
public void setList(List<MusicTrackList> list) {
mList = list;
}
/**
* @return Gets the list
*/
public List<MusicTrackList> getList() {
return mList;
}
/**
* Create a new track list adapter
* @param context The app context
*/
public MusicTrackListAdapter(Context context) {
mContext = context;
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
}
@Override
public int getCount() {
if (mList == null) return 0;
return mList.size();
}
@Override
public Object getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
// We don't have ids
return 0;
}
@Override
public boolean hasStableIds() {
// We don't have ids
return false;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// The track list
MusicTrackList musicTrackList = mList.get(position);
View view = convertView;
// Inflates a view
if (view == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.adapter_music_track_list, parent, false);
}
TextView textView;
// Set the title
textView = (TextView)view.findViewById(R.id.text_music_track_list_title);
textView.setText(musicTrackList.getTitle());
// Set the description
textView = (TextView)view.findViewById(R.id.text_music_track_list_description);
textView.setText(musicTrackList.getDescription());
// Final for the callback
final ImageView imageViewArtwork = (ImageView)view.findViewById(R.id.image_music_track_artwork);
// Default icon
imageViewArtwork.setImageResource(R.drawable.cd_case);
// Gets the artwork
String artworkPath = musicTrackList.getArtworkPath();
if (artworkPath != null) {
// Be careful! Don't scroll to fast! This will spam the superuser to do list!
SuperUserTools.fileReadToByteArrayAsync(artworkPath, new SuperUserCommandCallback() {
@Override
public void onFinished(SuperUserCommand command) {
// Success
if (command.commandWasSuccessful()) {
// Binary data
byte[] bitmapData = command.getStandardOutputBinary();
// Load the bitmap
try {
final Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length);
// The the bitmap in the UI thread
Runnable runnable = new Runnable() {
@Override
public void run() {
imageViewArtwork.setImageBitmap(bitmap);
}
};
imageViewArtwork.post(runnable);
} catch (Exception e) {
e.printStackTrace();
}
} else {
// File not found
imageViewArtwork.setImageResource(R.drawable.cd_case);
}
}
});
}
return view;
}
@Override
public int getItemViewType(int position) {
// We don't have view types
return 0;
}
@Override
public int getViewTypeCount() {
// We don't have view types
return 1;
}
@Override
public boolean isEmpty() {
return (mList == null || mList.isEmpty());
}
@Override
public boolean areAllItemsEnabled() {
return true;
}
@Override
public boolean isEnabled(int position) {
return true;
}
}

View file

@ -1,77 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* 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 de.arcus.playmusicexporter2.dummy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Helper class for providing sample content for user interfaces created by
* Android template wizards.
* <p/>
* TODO: Replace all uses of this class before publishing your app.
*/
public class DummyContent {
/**
* An array of sample (dummy) items.
*/
public static List<DummyItem> ITEMS = new ArrayList<>();
/**
* A map of sample (dummy) items, by ID.
*/
public static Map<String, DummyItem> ITEM_MAP = new HashMap<>();
static {
// Add 3 sample items.
addItem(new DummyItem("1", "Item 1"));
addItem(new DummyItem("2", "Item 2"));
addItem(new DummyItem("3", "Item 3"));
}
private static void addItem(DummyItem item) {
ITEMS.add(item);
ITEM_MAP.put(item.id, item);
}
/**
* A dummy item representing a piece of content.
*/
public static class DummyItem {
public String id;
public String content;
public DummyItem(String id, String content) {
this.id = id;
this.content = content;
}
@Override
public String toString() {
return content;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

@ -23,6 +23,5 @@
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/track_list"
android:name="de.arcus.playmusicexporter2.TrackListFragment" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" tools:context=".TrackListActivity"
android:layout_height="match_parent" tools:context=".TrackListActivity"
tools:layout="@android:layout/list_content" />

View file

@ -22,8 +22,8 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" android:baselineAligned="false"
android:layout_height="match_parent"
android:baselineAligned="false"
android:divider="?android:attr/dividerHorizontal" android:orientation="horizontal"
android:showDividers="middle" tools:context=".TrackListActivity">

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/text_music_track_list_title"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:paddingLeft="8dp"
android:paddingTop="16dp"
android:paddingRight="16dp"
android:layout_toRightOf="@+id/image_music_track_artwork"
android:layout_toEndOf="@+id/image_music_track_artwork" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="@+id/text_music_track_list_description"
android:layout_below="@+id/text_music_track_list_title"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:paddingTop="0dp"
android:paddingLeft="8dp"
android:paddingRight="16dp"
android:paddingBottom="16dp"
android:layout_toRightOf="@+id/image_music_track_artwork"
android:layout_toEndOf="@+id/image_music_track_artwork" />
<ImageView
android:layout_width="96dp"
android:layout_height="96dp"
android:id="@+id/image_music_track_artwork"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>

View file

@ -27,6 +27,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Environment;
import android.text.TextUtils;
import com.mpatric.mp3agic.ID3v1Genres;
@ -310,6 +311,13 @@ public class PlayMusicManager {
mDatabase.close();
}
/**
* Debug function to get the database
*/
public void copyDatabaseToSdCard() {
FileTools.fileCopy(getTempDatabasePath(), Environment.getExternalStorageDirectory() + "/music.db");
}
/**
* @return Gets the path to the private music
*/
@ -326,10 +334,7 @@ public class PlayMusicManager {
// LocalCopyPath is empty
if (TextUtils.isEmpty(localCopyPath)) return null;
// Private music path
String path = getPrivateMusicPath() + "/" + localCopyPath;
// Music file exists
if (SuperUserTools.fileExists(path)) return path;
String path;
// Search in the public data
for (String publicData : mPathPublicData) {
@ -338,7 +343,13 @@ public class PlayMusicManager {
if (FileTools.fileExists(path)) return path;
}
return null;
// Private music path
path = getPrivateMusicPath() + "/" + localCopyPath;
// Don't check if the file exists, this will freeze the UI thread
//if (SuperUserTools.fileExists(path)) return path;
return path;
}
/**
@ -357,10 +368,7 @@ public class PlayMusicManager {
// Artwork path is empty
if (TextUtils.isEmpty(artworkPath)) return null;
// Private artwork path
String path = getPrivateFilesPath() + "/" + artworkPath;
// Artwork file exists
if (SuperUserTools.fileExists(path)) return path;
String path;
// Search in the public data
for (String publicData : mPathPublicData) {
@ -369,7 +377,13 @@ public class PlayMusicManager {
if (FileTools.fileExists(path)) return path;
}
return null;
// Private artwork path
path = getPrivateFilesPath() + "/" + artworkPath;
// Don't check if the file exists, this will freeze the UI thread
// if (SuperUserTools.fileExists(path)) return path;
return path;
}
/**