mirror of
https://github.com/playmusicexporter/playmusicexporter
synced 2024-05-14 18:46:42 +00:00
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:
parent
0598cbccc4
commit
0a3b9b95ee
|
@ -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.
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
BIN
playmusicexporter/src/main/res/drawable-hdpi/cd_case.png
Normal file
BIN
playmusicexporter/src/main/res/drawable-hdpi/cd_case.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
BIN
playmusicexporter/src/main/res/drawable-mdpi/cd_case.png
Normal file
BIN
playmusicexporter/src/main/res/drawable-mdpi/cd_case.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
playmusicexporter/src/main/res/drawable-xhdpi/cd_case.png
Normal file
BIN
playmusicexporter/src/main/res/drawable-xhdpi/cd_case.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
BIN
playmusicexporter/src/main/res/drawable-xxhdpi/cd_case.png
Normal file
BIN
playmusicexporter/src/main/res/drawable-xxhdpi/cd_case.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue