/*
* Copyright (c) 2010 Sony Ericsson
*
* 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 com.sonyericsson.extras.liveview.plugins;
import com.sonyericsson.extras.liveview.IPluginServiceCallbackV1;
import com.sonyericsson.extras.liveview.IPluginServiceV1;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.util.Log;
/**
* Base implementation of the plug-in service.
*/
public abstract class AbstractPluginService extends Service {
// Template menu icon file name.
private static final String TEMPLATE_MENU_ICON = "plugin_icon.png";
// There should only be one instance of the service
protected static boolean alreadyRunning = false;
// Plugin name
protected String mPluginName = null;
// Current plugin Id
protected int mPluginId = 0;
// LiveView adapter reference
protected LiveViewAdapter mLiveViewAdapter = null;
// Menu icon that will be shown in LiveView unit
protected String mMenuIcon = null;
// Launcher intent for the implemented service
protected String mServiceIntent = null;
// Current shared preferences.
protected SharedPreferences mSharedPreferences = null;
/**
* Defines what type of plugin this is.
*
* @return is sandbox plugin
*/
protected abstract boolean isSandboxPlugin();
/**
* Extenders of PluginService must implement this. Called by
* ServiceConnection.onServiceConnected.
*
* @param className
* @param service
*/
protected abstract void onServiceConnectedExtended(ComponentName className, IBinder service);
/**
* Extenders of PluginService must implement this. Called by
* ServiceConnection.onServiceDisconnected.
*
* @param className
*/
protected abstract void onServiceDisconnectedExtended(ComponentName className);
/**
* Extenders of PluginService must implement this. Called by
* OnSharedPreferenceChangeListener.onSharedPreferenceChanged.
*
* @param pref
* @param key
*/
protected abstract void onSharedPreferenceChangedExtended(SharedPreferences pref, String key);
/**
* Extenders of PluginService must implement this. Called by
* OnSharedPreferenceChangeListener.onSharedPreferenceChanged.
*/
protected abstract void startWork();
/**
* Extenders of PluginService must implement this. Called by
* OnSharedPreferenceChangeListener.onSharedPreferenceChanged.
*/
protected abstract void stopWork();
/**
* LiveView callback interface method.
*
* Will start plugin.
*/
protected abstract void startPlugin();
/**
* LiveView callback interface method.
*
* Will stop plugin.
*/
protected abstract void stopPlugin();
/**
* LiveView callback interface method.
*
* Button has been pressed on the LiveView device.
*/
protected abstract void button(String buttonType, boolean doublepress, boolean longpress);
/**
* LiveView callback interface method.
*
* Gives the display capabilites of the LiveView device.
*/
protected abstract void displayCaps(int displayWidthPx, int displayHeigthPx);
/**
* LiveView callback interface method.
*
* Called when thrown out by framework.
*/
protected abstract void onUnregistered() throws RemoteException;
/**
* LiveView callback interface method.
*
* Open in phone function called from the LiveView device.
*/
protected abstract void openInPhone(String openInPhoneAction);
/**
* LiveView callback interface method.
*
* Gives an indication what the current state of the LiveView device screen.
* 0 = off, 1 = on
*/
protected abstract void screenMode(int mode);
/**
* LiveView callback interface method.
*/
private class LiveViewCallback extends IPluginServiceCallbackV1.Stub {
Handler mCallbackHandler = new Handler();
@Override
public void startPlugin() throws RemoteException {
mCallbackHandler.post(new Runnable() {
public void run() {
AbstractPluginService.this.startPlugin();
}
});
}
@Override
public void stopPlugin() throws RemoteException {
mCallbackHandler.post(new Runnable() {
public void run() {
AbstractPluginService.this.stopPlugin();
}
});
}
@Override
public String getPluginName() throws RemoteException {
return mPluginName;
}
@Override
public void button(final String buttonType, final boolean doublepress,
final boolean longpress) throws RemoteException {
mCallbackHandler.post(new Runnable() {
public void run() {
AbstractPluginService.this.button(buttonType, doublepress, longpress);
}
});
}
@Override
public void displayCaps(final int displayWidthPx, final int displayHeigthPx)
throws RemoteException {
mCallbackHandler.post(new Runnable() {
public void run() {
AbstractPluginService.this.displayCaps(displayWidthPx, displayHeigthPx);
}
});
}
@Override
public void onUnregistered() throws RemoteException {
AbstractPluginService.this.onUnregistered();
}
@Override
public void openInPhone(final String openInPhoneAction) throws RemoteException {
mCallbackHandler.post(new Runnable() {
public void run() {
AbstractPluginService.this.openInPhone(openInPhoneAction);
}
});
}
@Override
public void screenMode(final int mode) throws RemoteException {
mCallbackHandler.post(new Runnable() {
public void run() {
AbstractPluginService.this.screenMode(mode);
}
});
}
}
/**
* Check if service is already running.
*
* @return running?
*/
public static boolean isAlreadyRunning() {
return alreadyRunning;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(PluginConstants.LOG_TAG, "Enter AbstractPluginService.onCreate.");
// Load menu icon
int iconId = PluginUtils.getDynamicResourceId(this, "icon", "drawable");
mMenuIcon = PluginUtils.storeIconToFile(this, getResources(), iconId, TEMPLATE_MENU_ICON);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(PluginConstants.LOG_TAG, "Enter AbstractPluginService.onDestroy.");
// Unbind from LiveView service
if (mServiceConnection != null) {
unbindService(mServiceConnection);
}
// No longer a running service
alreadyRunning = false;
}
@Override
public void onStart(final Intent intent, final int startId) {
super.onStart(intent, startId);
Log.d(PluginConstants.LOG_TAG, "Enter AbstractPluginService.onStart.");
if (isAlreadyRunning()) {
Log.d(PluginConstants.LOG_TAG, "Already started.");
} else {
// Init
mPluginName = PluginUtils.getDynamicResourceString(this,
PluginConstants.RESOURCE_STRING_PLUGIN_NAME);
mServiceIntent = PluginUtils.getDynamicResourceString(this,
PluginConstants.RESOURCE_STRING_INTENT_SERVICE);
// Get shared preferences
setPreferences();
// Register preference listener
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener(mPrefChangeListener);
// Bind to LiveView
connectToLiveView();
// Singleton
alreadyRunning = true;
}
}
@Override
public IBinder onBind(final Intent intent) {
Log.d(PluginConstants.LOG_TAG, "Enter AbstractPluginService.onBind.");
return null;
}
/**
* The service connection that is used to bind the plugin to the LiveView
* service.
*
* When connected to the service, the plugin is registered. When
* disconnected to the service, the plugin is unregistered.
*/
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(final ComponentName className, IBinder service) {
Log.d(PluginConstants.LOG_TAG,
"Enter AbstractPluginService.ServiceConnection.onServiceConnected.");
IPluginServiceV1 liveViewService = IPluginServiceV1.Stub.asInterface(service);
// Init adapter
mLiveViewAdapter = new LiveViewAdapter(liveViewService);
LiveViewCallback lvCallback = new LiveViewCallback();
// Install plugin
try {
mPluginId = mLiveViewAdapter.installPlugin(lvCallback, mMenuIcon, mPluginName,
isSandboxPlugin(), getPackageName(), mServiceIntent);
} catch (RemoteException re) {
Log.e(PluginConstants.LOG_TAG, "Failed to install plugin. Stop self.");
stopSelf();
}
Log.d(PluginConstants.LOG_TAG, "Plugin registered. mPluginId: " + mPluginId
+ " isSandbox? " + isSandboxPlugin());
// Call specific plugin implementation
onServiceConnectedExtended(className, service);
}
@Override
public void onServiceDisconnected(ComponentName className) {
Log.d(PluginConstants.LOG_TAG,
"Enter AbstractPluginService.ServiceConnection.onServiceDisconnected.");
stopSelf();
}
};
/**
* The preference listener. Implement this to get awareness of user
* preference changes. Is registered in onStart.
*/
protected OnSharedPreferenceChangeListener mPrefChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// Update preferences
setPreferences(prefs);
if (key.equals(PluginConstants.PREFERENCES_PLUGIN_ENABLED)) {
boolean pluginEnabled = prefs.getBoolean(
PluginConstants.PREFERENCES_PLUGIN_ENABLED, false);
if (pluginEnabled) {
startWork();
} else {
stopWork();
}
Log.d(PluginConstants.LOG_TAG, "Preferences changed - enabled: " + pluginEnabled);
}
// Call custom plugin implementation
onSharedPreferenceChangedExtended(prefs, key);
}
};
/**
* Connects to the LiveView service.
*/
private void connectToLiveView() {
boolean result = bindService(new Intent(PluginConstants.LIVEVIEW_SERVICE_BIND_INTENT),
mServiceConnection, 0);
if (result) {
Log.d(PluginConstants.LOG_TAG, "Bound to LiveView.");
} else {
Log.d(PluginConstants.LOG_TAG, "No bind.");
stopSelf();
}
}
/**
* Fetches and sets the shared preferences.
*/
private void setPreferences() {
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
}
/**
* Sets the shared preferences.
*/
private void setPreferences(SharedPreferences prefs) {
mSharedPreferences = prefs;
}
}