This commit is contained in:
parent
091d711ff9
commit
58b40d862c
@ -315,4 +315,7 @@ THE SOFTWARE.
|
||||
<string name="media_stats_progress">Scan progress</string>
|
||||
|
||||
<string name="media_library_scan_running">Scanning media library…</string>
|
||||
|
||||
<!-- Plugin system -->
|
||||
<string name="plugins">Plugins</string>
|
||||
</resources>
|
||||
|
@ -26,9 +26,14 @@ package ch.blinkenlights.android.vanilla;
|
||||
import ch.blinkenlights.android.medialibrary.MediaLibrary;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
@ -38,7 +43,6 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.iosched.tabs.VanillaTabLayout;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.text.TextUtils;
|
||||
@ -56,6 +60,11 @@ import android.widget.TextView;
|
||||
import android.widget.SearchView;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
/**
|
||||
@ -139,6 +148,19 @@ public class LibraryActivity
|
||||
* open the playback activity when an item is pressed twice.
|
||||
*/
|
||||
private long mLastActedId;
|
||||
/**
|
||||
* Holds last intent that was passed to the context menu
|
||||
*/
|
||||
private Intent mLastRequestedCtx;
|
||||
/**
|
||||
* Plugin descriptions and packages.
|
||||
* Keys are plugin names, values are their packages
|
||||
*/
|
||||
private Map<String, ApplicationInfo> mPlugins = new HashMap<>();
|
||||
/**
|
||||
* Broadcast receiver for plugin collecting
|
||||
*/
|
||||
private BroadcastReceiver mPluginInfoReceiver;
|
||||
/**
|
||||
* The pager adapter that manages each media ListView.
|
||||
*/
|
||||
@ -172,6 +194,7 @@ public class LibraryActivity
|
||||
mViewPager = pager;
|
||||
|
||||
SharedPreferences settings = PlaybackService.getSettings(this);
|
||||
mPluginInfoReceiver = new PluginBroadcastReceiver();
|
||||
|
||||
mBottomBarControls = (BottomBarControls)findViewById(R.id.bottombar_controls);
|
||||
mBottomBarControls.setOnClickListener(this);
|
||||
@ -195,6 +218,43 @@ public class LibraryActivity
|
||||
bindControlButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows plugin selection dialog. Be sure that {@link #mLastRequestedCtx} is initialized
|
||||
* and {@link #mPlugins} are populated before calling this.
|
||||
*
|
||||
* @see PluginBroadcastReceiver
|
||||
*/
|
||||
private void showPluginMenu() {
|
||||
Set<String> pluginNames = mPlugins.keySet();
|
||||
final String[] pNamesArr = pluginNames.toArray(new String[pluginNames.size()]);
|
||||
new AlertDialog.Builder(this)
|
||||
.setItems(pNamesArr, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
long id = mLastRequestedCtx.getLongExtra("id", LibraryAdapter.INVALID_ID);
|
||||
Song resolved = MediaUtils.getSongByTypeId(LibraryActivity.this, MediaUtils.TYPE_SONG, id);
|
||||
if (resolved != null) {
|
||||
ApplicationInfo selected = mPlugins.get(pNamesArr[which]);
|
||||
Intent request = new Intent(PluginUtils.ACTION_LAUNCH_PLUGIN);
|
||||
request.setPackage(selected.packageName);
|
||||
request.putExtra(PluginUtils.EXTRA_PARAM_URI, Uri.fromFile(new File(resolved.path)));
|
||||
request.putExtra(PluginUtils.EXTRA_PARAM_SONG_TITLE, resolved.title);
|
||||
request.putExtra(PluginUtils.EXTRA_PARAM_SONG_ARTIST, resolved.artist);
|
||||
request.putExtra(PluginUtils.EXTRA_PARAM_SONG_ALBUM, resolved.album);
|
||||
startService(request);
|
||||
}
|
||||
|
||||
mLastRequestedCtx = null;
|
||||
}
|
||||
})
|
||||
.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
mLastRequestedCtx = null;
|
||||
}
|
||||
}).create().show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestart()
|
||||
{
|
||||
@ -213,6 +273,18 @@ public class LibraryActivity
|
||||
updateHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
registerReceiver(mPluginInfoReceiver, new IntentFilter(PluginUtils.ACTION_HANDLE_PLUGIN_PARAMS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
unregisterReceiver(mPluginInfoReceiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the tab order and update the tab bars if needed.
|
||||
*/
|
||||
@ -593,6 +665,7 @@ public class LibraryActivity
|
||||
private static final int CTX_MENU_MORE_FROM_ALBUM = 8;
|
||||
private static final int CTX_MENU_MORE_FROM_ARTIST = 9;
|
||||
private static final int CTX_MENU_OPEN_EXTERNAL = 10;
|
||||
private static final int CTX_MENU_PLUGINS = 11;
|
||||
|
||||
/**
|
||||
* Creates a context menu for an adapter row.
|
||||
@ -627,8 +700,11 @@ public class LibraryActivity
|
||||
}
|
||||
if (type == MediaUtils.TYPE_ALBUM || type == MediaUtils.TYPE_SONG)
|
||||
menu.add(0, CTX_MENU_MORE_FROM_ARTIST, 0, R.string.more_from_artist).setIntent(rowData);
|
||||
if (type == MediaUtils.TYPE_SONG)
|
||||
if (type == MediaUtils.TYPE_SONG) {
|
||||
menu.add(0, CTX_MENU_MORE_FROM_ALBUM, 0, R.string.more_from_album).setIntent(rowData);
|
||||
if (PluginUtils.checkPlugins(this))
|
||||
menu.add(0, CTX_MENU_PLUGINS, 1, R.string.plugins).setIntent(rowData); // last in order
|
||||
}
|
||||
menu.addSubMenu(0, CTX_MENU_ADD_TO_PLAYLIST, 0, R.string.add_to_playlist).getItem().setIntent(rowData);
|
||||
menu.add(0, CTX_MENU_DELETE, 0, R.string.delete).setIntent(rowData);
|
||||
}
|
||||
@ -709,6 +785,15 @@ public class LibraryActivity
|
||||
FileUtils.dispatchIntent(this, intent);
|
||||
break;
|
||||
}
|
||||
case CTX_MENU_PLUGINS: {
|
||||
// obtain list of plugins anew - some plugins may be installed/deleted
|
||||
mPlugins.clear();
|
||||
mLastRequestedCtx = intent;
|
||||
Intent requestPlugins = new Intent(PluginUtils.ACTION_REQUEST_PLUGIN_PARAMS);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
sendBroadcast(requestPlugins);
|
||||
break;
|
||||
}
|
||||
case CTX_MENU_MORE_FROM_ARTIST: {
|
||||
String selection;
|
||||
if (intent.getIntExtra(LibraryAdapter.DATA_TYPE, -1) == MediaUtils.TYPE_ALBUM) {
|
||||
@ -923,4 +1008,20 @@ public class LibraryActivity
|
||||
}
|
||||
}
|
||||
|
||||
private class PluginBroadcastReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
List<ResolveInfo> resolved = getPackageManager().queryBroadcastReceivers(new Intent(PluginUtils.ACTION_REQUEST_PLUGIN_PARAMS), 0);
|
||||
if (PluginUtils.ACTION_HANDLE_PLUGIN_PARAMS.equals(intent.getAction())) {
|
||||
// plugin answered, store it in the map
|
||||
String pluginName = intent.getStringExtra(PluginUtils.EXTRA_PARAM_PLUGIN_NAME);
|
||||
ApplicationInfo info = intent.getParcelableExtra(PluginUtils.EXTRA_PARAM_PLUGIN_APP);
|
||||
mPlugins.put(pluginName, info);
|
||||
|
||||
if (mPlugins.size() == resolved.size()) { // got all plugins
|
||||
showPluginMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
69
src/ch/blinkenlights/android/vanilla/PluginUtils.java
Normal file
69
src/ch/blinkenlights/android/vanilla/PluginUtils.java
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ch.blinkenlights.android.vanilla;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Common plugin utilities and constants reside here.
|
||||
* Note that public `action` and `extra` strings are common over all plugins, so please keep them in sync.
|
||||
*/
|
||||
|
||||
public class PluginUtils {
|
||||
|
||||
private PluginUtils() {
|
||||
}
|
||||
|
||||
// these actions are for passing between main player and plugins
|
||||
public static final String ACTION_REQUEST_PLUGIN_PARAMS = "ch.blinkenlights.android.vanilla.action.REQUEST_PLUGIN_PARAMS"; // broadcast
|
||||
public static final String ACTION_HANDLE_PLUGIN_PARAMS = "ch.blinkenlights.android.vanilla.action.HANDLE_PLUGIN_PARAMS"; // answer
|
||||
public static final String ACTION_WAKE_PLUGIN = "ch.blinkenlights.android.vanilla.action.WAKE_PLUGIN"; // targeted at each found
|
||||
public static final String ACTION_LAUNCH_PLUGIN = "ch.blinkenlights.android.vanilla.action.LAUNCH_PLUGIN"; // targeted at selected by user
|
||||
|
||||
// these are used by plugins to describe themselves
|
||||
public static final String EXTRA_PARAM_PLUGIN_NAME = "ch.blinkenlights.android.vanilla.extra.PLUGIN_NAME";
|
||||
public static final String EXTRA_PARAM_PLUGIN_APP = "ch.blinkenlights.android.vanilla.extra.PLUGIN_APP";
|
||||
public static final String EXTRA_PARAM_PLUGIN_DESC = "ch.blinkenlights.android.vanilla.extra.PLUGIN_DESC";
|
||||
|
||||
// this is passed to plugin when it is selected by user
|
||||
public static final String EXTRA_PARAM_URI = "ch.blinkenlights.android.vanilla.extra.URI";
|
||||
public static final String EXTRA_PARAM_SONG_TITLE = "ch.blinkenlights.android.vanilla.extra.SONG_TITLE";
|
||||
public static final String EXTRA_PARAM_SONG_ALBUM = "ch.blinkenlights.android.vanilla.extra.SONG_ALBUM";
|
||||
public static final String EXTRA_PARAM_SONG_ARTIST = "ch.blinkenlights.android.vanilla.extra.SONG_ARTIST";
|
||||
|
||||
static final String EXTRA_PLUGIN_MAP = "ch.blinkenlights.android.vanilla.internal.extra.PLUGIN_MAP";
|
||||
|
||||
public static boolean checkPlugins(Context ctx) {
|
||||
List<ResolveInfo> resolved = ctx.getPackageManager().queryBroadcastReceivers(new Intent(ACTION_REQUEST_PLUGIN_PARAMS), 0);
|
||||
if(!resolved.isEmpty()) {
|
||||
// If plugin is just installed, Android will not deliver intents to its receiver
|
||||
// until it's started at least one time
|
||||
for (ResolveInfo ri : resolved) {
|
||||
Intent awaker = new Intent(ACTION_WAKE_PLUGIN);
|
||||
awaker.setPackage(ri.activityInfo.packageName);
|
||||
ctx.startService(awaker);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user