Base extensions API for Android

This commit is contained in:
Geoffrey Métais 2015-11-19 10:57:26 +01:00
parent fe55ba65b8
commit 15922bf951
17 changed files with 852 additions and 1 deletions

1
api/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

48
api/build.gradle Normal file
View File

@ -0,0 +1,48 @@
/*
* *************************************************************************
* build.gradle.java
* **************************************************************************
* Copyright © 2015 VLC authors and VideoLAN
* Author: Geoffrey Métais
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* ***************************************************************************
*/
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion '23.0.2'
defaultConfig {
minSdkVersion 8
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
}

17
api/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/dekans/SDK/android-sdk-linux/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,36 @@
/*
* *************************************************************************
* ApplicationTest.java
* **************************************************************************
* Copyright © 2015 VLC authors and VideoLAN
* Author: Geoffrey Métais
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* ***************************************************************************
*/
package org.videolan.vlc.plugin.api;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -0,0 +1,32 @@
<!--
~ **************************************************************************
~ AndroidManifest.xml.java
~ ***************************************************************************
~ Copyright © 2015 VLC authors and VideoLAN
~ Author: Geoffrey Métais
~
~ 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 2 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, write to the Free Software
~ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
~ ***************************************************************************
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.videolan.vlc.plugin.api">
<application android:allowBackup="true" android:label="@string/app_name"
android:supportsRtl="true">
</application>
</manifest>

View File

@ -0,0 +1,10 @@
package org.videolan.vlc.plugin.api;
import org.videolan.vlc.plugin.api.VLCExtensionItem;
import android.net.Uri;
interface IExtensionHost {
// Protocol version 1
oneway void updateList(in List<VLCExtensionItem> items);
oneway void playUri(in Uri uri, String title);
}

View File

@ -0,0 +1,10 @@
package org.videolan.vlc.plugin.api;
import org.videolan.vlc.plugin.api.IExtensionHost;
import org.videolan.vlc.plugin.api.VLCExtensionItem;
interface IExtensionService {
// Protocol version 1
oneway void onInitialize(in IExtensionHost host);
oneway void browse(int intId, String stringId);
}

View File

@ -0,0 +1,3 @@
package org.videolan.vlc.plugin.api;
parcelable VLCExtensionItem;

View File

@ -0,0 +1,95 @@
/*
* *************************************************************************
* VLCExtensionItem.java
* **************************************************************************
* Copyright © 2015 VLC authors and VideoLAN
* Author: Geoffrey Métais
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* ***************************************************************************
*/
package org.videolan.vlc.plugin.api;
import android.os.Parcel;
import android.os.Parcelable;
public class VLCExtensionItem implements Parcelable {
public static final int TYPE_DIRECTORY = 0;
public static final int TYPE_VIDEO = 1;
public static final int TYPE_AUDIO = 2;
public static final int TYPE_PLAYLIST = 3;
public static final int TYPE_SUBTITLE = 4;
public static final int TYPE_OTHER_FILE = 5;
String id;
String path;
String title;
String subTitle;
//TODO choose how to deal with icons
String iconUri; // for content provider
int iconType; // Using VLC icons. maybe with iconRes?
public VLCExtensionItem(String id, String path, String title, String subTitle, String mimeType, int iconType) {
this.id = id;
this.path = path;
this.title = title;
this.subTitle = subTitle;
this.iconType = iconType;
}
public VLCExtensionItem() {
}
private VLCExtensionItem(Parcel in) {
readFromParcel(in);
}
public static final Parcelable.Creator<VLCExtensionItem> CREATOR = new
Parcelable.Creator<VLCExtensionItem>() {
public VLCExtensionItem createFromParcel(Parcel in) {
return new VLCExtensionItem(in);
}
public VLCExtensionItem[] newArray(int size) {
return new VLCExtensionItem[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(path);
dest.writeString(title);
dest.writeString(subTitle);
dest.writeString(iconUri);
dest.writeInt(iconType);
}
public void readFromParcel(Parcel in) {
id = in.readString();
path = in.readString();
title = in.readString();
subTitle = in.readString();
iconUri = in.readString();
iconType = in.readInt();
}
}

View File

@ -0,0 +1,82 @@
package org.videolan.vlc.plugin.api;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import java.util.List;
public abstract class VLCExtensionService extends Service{
private static final String TAG = "VLC/ExtensionService";
private static final ComponentName VLC_HOST_SERVICE =
new ComponentName("org.videolan.vlc",
"org.videolan.vlc.plugin.PluginService");
IExtensionHost mHost;
Context mContext = this;
private volatile Looper mServiceLooper;
private volatile Handler mServiceHandler;
protected abstract void browse(int intId, String stringId);
protected abstract void updateList(List<VLCExtensionItem> items);
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread(
"VLCExtension:" + getClass().getSimpleName());
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new Handler(mServiceLooper);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
mServiceHandler.removeCallbacksAndMessages(null); // remove all callbacks
mServiceLooper.quit();
}
public void playUri(Uri uri, String title) {
try {
mHost.playUri(uri, title);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private final IExtensionService.Stub mBinder = new IExtensionService.Stub() {
@Override
public void onInitialize(IExtensionHost host) throws RemoteException {
mHost = host;
}
@Override
public void browse(final int id, final String text) throws RemoteException {
mServiceHandler.post(new Runnable() {
@Override
public void run() {
VLCExtensionService.this.browse(id, text);
}
});
}
};
}

View File

@ -0,0 +1,26 @@
<!--
~ **************************************************************************
~ strings.xml.java
~ ***************************************************************************
~ Copyright © 2015 VLC authors and VideoLAN
~ Author: Geoffrey Métais
~
~ 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 2 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, write to the Free Software
~ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
~ ***************************************************************************
-->
<resources>
<string name="app_name">Plugin API</string>
</resources>

View File

@ -0,0 +1,38 @@
/*
* *************************************************************************
* ExampleUnitTest.java
* **************************************************************************
* Copyright © 2015 VLC authors and VideoLAN
* Author: Geoffrey Métais
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* ***************************************************************************
*/
package org.videolan.vlc.plugin.api;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

View File

@ -1,2 +1,2 @@
include ':libvlc'
include ':libvlc', ':api'
include ':vlc-android'

View File

@ -42,6 +42,17 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<permission
android:name="org.videolan.vlc.permission.READ_EXTENSION_DATA"
android:protectionLevel="normal" />
<permission
android:name="org.videolan.vlc.permission.BIND_DATA_CONSUMER"
android:protectionLevel="normal" />
<uses-permission android:name="org.videolan.vlc.permission.READ_EXTENSION_DATA" />
<uses-permission android:name="org.videolan.vlc.permission.BIND_DATA_CONSUMER" />
<application
android:name="org.videolan.vlc.VLCApplication"
android:hardwareAccelerated="true"
@ -418,6 +429,7 @@
</intent-filter>
</activity>
<service android:name=".plugin.PluginService" />
<service android:name=".PlaybackService" />
<receiver
android:name=".widget.VLCAppWidgetProviderWhite"

View File

@ -202,6 +202,7 @@ android {
dependencies {
compile project(':libvlc')
compile project(':api')
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:cardview-v7:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.1'

View File

@ -0,0 +1,234 @@
/*
* *************************************************************************
* pluginListing.java
* **************************************************************************
* Copyright © 2015 VLC authors and VideoLAN
* Author: Geoffrey Métais
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* ***************************************************************************
*/
package org.videolan.vlc.plugin;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
public class ExtensionListing implements Parcelable {
public static final int PARCELABLE_VERSION = 1;
private ComponentName mComponentName;
private int mProtocolVersion;
private boolean mCompatible;
private boolean mWorldReadable;
private String mTitle;
private String mDescription;
private int mIcon;
private ComponentName mSettingsActivity;
public ExtensionListing(){}
@Override
public int describeContents() {
return 0;
}
/**
* Returns the full qualified component name of the extension.
*/
public ComponentName componentName() {
return mComponentName;
}
/**
* Sets the full qualified component name of the extension.
*/
public ExtensionListing componentName(ComponentName componentName) {
mComponentName = componentName;
return this;
}
/**
* Returns the version of the {@link com.google.android.apps.dashclock.api.DashClockExtension}
* protocol used by the extension.
*/
public int protocolVersion() {
return mProtocolVersion;
}
/**
* Sets the version of the {@link com.google.android.apps.dashclock.api.DashClockExtension}
* protocol used by the extension.
*/
public ExtensionListing protocolVersion(int protocolVersion) {
mProtocolVersion = protocolVersion;
return this;
}
/**
* Returns whether this extension is compatible to the host application; that is whether
* the version of the {@link com.google.android.apps.dashclock.api.DashClockExtension}
* protocol used by the extension matches what is used by the host application.
*/
public boolean compatible() {
return mCompatible;
}
/**
* Sets whether this extension is considered compatible to the host application.
*/
public ExtensionListing compatible(boolean compatible) {
mCompatible = compatible;
return this;
}
/**
* Returns if the data of the ExtensionInfo is available to all hosts or only for the
* DashClock app.
*/
public boolean worldReadable() {
return mWorldReadable;
}
/**
* Sets if the data of the ExtensionInfo is available to all hosts or only for the
* DashClock app.
*/
public ExtensionListing worldReadable(boolean worldReadable) {
mWorldReadable = worldReadable;
return this;
}
/**
* Returns the label of the extension.
*/
public String title() {
return mTitle;
}
/**
* Sets the label of the extension.
*/
public ExtensionListing title(String title) {
mTitle = title;
return this;
}
/**
* Returns a description of the extension.
*/
public String description() {
return mDescription;
}
/**
* Sets a description of the extension.
*/
public ExtensionListing description(String description) {
mDescription = description;
return this;
}
/**
* Returns the ID of the drawable resource within the extension's package that represents this
* data. Default 0.
*/
public int icon() {
return mIcon;
}
/**
* Sets the ID of the drawable resource within the extension's package that represents this
* data. Default 0.
*/
public ExtensionListing icon(int icon) {
mIcon = icon;
return this;
}
/**
* Returns the full qualified component name of the settings class to configure
* the extension.
*/
public ComponentName settingsActivity() {
return mSettingsActivity;
}
/**
* Sets the full qualified component name of the settings class to configure
* the extension.
*/
public ExtensionListing settingsActivity(ComponentName settingsActivity) {
this.mSettingsActivity = settingsActivity;
return this;
}
/**
* @see android.os.Parcelable
*/
public static final Creator<ExtensionListing> CREATOR
= new Creator<ExtensionListing>() {
public ExtensionListing createFromParcel(Parcel in) {
return new ExtensionListing(in);
}
public ExtensionListing[] newArray(int size) {
return new ExtensionListing[size];
}
};
private ExtensionListing(Parcel in) {
int parcelableVersion = in.readInt();
// Version 1 below
if (parcelableVersion >= 1) {
mComponentName = ComponentName.readFromParcel(in);
mProtocolVersion = in.readInt();
mCompatible = in.readInt() == 1;
mWorldReadable = in.readInt() == 1;
mTitle = in.readString();
mDescription = in.readString();
mIcon = in.readInt();
boolean hasSettings = in.readInt() == 1;
if (hasSettings) {
mSettingsActivity = ComponentName.readFromParcel(in);
}
}
}
@Override
public void writeToParcel(Parcel parcel, int i) {
/**
* NOTE: When adding fields in the process of updating this API, make sure to bump
* {@link #PARCELABLE_VERSION}.
*/
parcel.writeInt(PARCELABLE_VERSION);
// Version 1 below
mComponentName.writeToParcel(parcel, 0);
parcel.writeInt(mProtocolVersion);
parcel.writeInt(mCompatible ? 1 : 0);
parcel.writeInt(mWorldReadable ? 1 : 0);
parcel.writeString(mTitle);
parcel.writeString(mDescription);
parcel.writeInt(mIcon);
parcel.writeInt(mSettingsActivity != null ? 1 : 0);
if (mSettingsActivity != null) {
mSettingsActivity.writeToParcel(parcel, 0);
}
}
}

View File

@ -0,0 +1,206 @@
/*
* *************************************************************************
* PluginService.java
* **************************************************************************
* Copyright © 2015 VLC authors and VideoLAN
* Author: Geoffrey Métais
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* ***************************************************************************
*/
package org.videolan.vlc.plugin;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import org.videolan.vlc.VLCApplication;
import org.videolan.vlc.media.MediaUtils;
import org.videolan.vlc.media.MediaWrapper;
import org.videolan.vlc.plugin.api.IExtensionHost;
import org.videolan.vlc.plugin.api.IExtensionService;
import org.videolan.vlc.plugin.api.VLCExtensionItem;
import java.util.List;
public class PluginService extends Service {
private static final String TAG = "VLC/PluginService";
public static final String ACTION_EXTENSION = "org.videolan.vlc.Extension";
public static final int PROTOCOLE_VERSION = 1;
private static final int PLAY_MEDIA = 42;
private final IBinder mBinder = new LocalBinder();
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "service onCreate");
getAvailableExtensions();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
return START_NOT_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "service onBind");
return mBinder;
}
public class LocalBinder extends Binder {
public PluginService getService() {
return PluginService.this;
}
}
public List<String> getAvailableExtensions() {
PackageManager pm = VLCApplication.getAppContext().getPackageManager();
List<ResolveInfo> resolveInfos = pm.queryIntentServices(
new Intent(ACTION_EXTENSION), PackageManager.GET_META_DATA);
for (ResolveInfo resolveInfo : resolveInfos) {
ExtensionListing info = new ExtensionListing();
info.componentName(new ComponentName(resolveInfo.serviceInfo.packageName,
resolveInfo.serviceInfo.name));
info.title(resolveInfo.loadLabel(pm).toString());
Bundle metaData = resolveInfo.serviceInfo.metaData;
if (metaData != null) {
info.compatible(metaData.getInt("protocolVersion") == PROTOCOLE_VERSION);
info.worldReadable(metaData.getBoolean("worldReadable", false));
info.description(metaData.getString("description"));
String settingsActivity = metaData.getString("settingsActivity");
if (!TextUtils.isEmpty(settingsActivity)) {
info.settingsActivity(ComponentName.unflattenFromString(
resolveInfo.serviceInfo.packageName + "/" + settingsActivity));
}
}
info.icon(resolveInfo.getIconResource());
//availableExtensions.add(info); TODO
Log.d(TAG, "componentName "+info.componentName().toString());
Log.d(TAG, " - title "+info.title());
Log.d(TAG, " - protocolVersion "+info.protocolVersion());
Log.d(TAG, " - settingsActivity "+info.settingsActivity());
connectService(info);
}
return null;
}
private void connectService(ExtensionListing info) {
final Connection conn = new Connection();
ComponentName cn = info.componentName();
conn.componentName = cn;
conn.hostInterface = makeHostInterface(conn);
conn.serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
conn.ready = true;
conn.binder = IExtensionService.Stub.asInterface(service);
try {
conn.binder.onInitialize(conn.hostInterface);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
unbindService(conn.serviceConnection);
}
};
try {
if (!bindService(new Intent().setComponent(cn), conn.serviceConnection,
Context.BIND_AUTO_CREATE)) {
Log.e(TAG, "Error binding to extension " + cn.flattenToShortString());
// return null;
}
} catch (SecurityException e) {
Log.e(TAG, "Error binding to extension " + cn.flattenToShortString(), e);
// return null;
}
}
private IExtensionHost makeHostInterface(Connection conn) {
return new IExtensionHost.Stub(){
@Override
public void updateList(List<VLCExtensionItem> items) throws RemoteException {
//TODO
}
@Override
public void playUri(Uri uri, String title) throws RemoteException {
Log.d(TAG, "play media "+title);
Log.d(TAG, " - uri is: "+uri);
MediaWrapper media = new MediaWrapper(uri);
media.setTitle(title);
mHandler.obtainMessage(PLAY_MEDIA, media).sendToTarget();
}
};
}
private static class Connection {
boolean ready = false;
ComponentName componentName;
ServiceConnection serviceConnection;
IExtensionService binder;
IExtensionHost hostInterface;
ContentObserver contentObserver;
/**
* Only access on the async thread. The pair is (collapse token, operation)
*/
// final Queue<Pair<Object, Operation>> deferredOps
// = new LinkedList<Pair<Object, Operation>>();
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case PLAY_MEDIA:
MediaWrapper media = (MediaWrapper) msg.obj;
MediaUtils.openMediaNoUi(PluginService.this, media);
break;
}
}
};
}