/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at
* src/com/vodafone360/people/VODAFONE.LICENSE.txt or
* http://github.com/360/360-Engine-for-Android
* See the License for the specific language governing permissions and
* limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each file and
* include the License file at src/com/vodafone360/people/VODAFONE.LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the fields
* enclosed by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2010 Vodafone Sales & Services Ltd. All rights reserved.
* Use is subject to license terms.
*/
package com.vodafone360.people.service.aidl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import android.app.Service;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import com.vodafone360.people.MainApplication;
import com.vodafone360.people.Settings;
import com.vodafone360.people.SettingsManager;
import com.vodafone360.people.datatypes.ContactSummary;
import com.vodafone360.people.datatypes.Identity;
import com.vodafone360.people.datatypes.LoginDetails;
import com.vodafone360.people.datatypes.RegistrationDetails;
import com.vodafone360.people.datatypes.ContactSummary.OnlineStatus;
import com.vodafone360.people.engine.presence.PresenceDbUtils;
import com.vodafone360.people.engine.presence.User;
import com.vodafone360.people.engine.presence.NetworkPresence.SocialNetwork;
import com.vodafone360.people.service.PersistSettings;
import com.vodafone360.people.service.RemoteService;
import com.vodafone360.people.service.PersistSettings.InternetAvail;
import com.vodafone360.people.service.agent.NetworkAgentState;
import com.vodafone360.people.service.interfaces.IPeopleService;
import com.vodafone360.people.utils.LogUtils;
/**
* This is an experimental AIDL API, which is currently unsupported by Vodafone
* and disabled by default.
*
* Service is used for all third party interaction with the 360 Engines. Usage
* is best explained with a code example, but the short story is that this
* class (once bound) tries to provide all the methods available from the
* IPeopleService.
*/
public class IdlPeopleInterface extends Service {
/** Reference to MainApplication. **/
private MainApplication mApplication;
/** Reference to IPeopleService. **/
private IPeopleService mPeopleService;
/**
* Map of IDatabaseSubscriber listeners. We store a list of listeners with
* unique string identifiers, as there are problems removing these from the
* list otherwise.
**/
private Map<String, IDatabaseSubscriber> mListeners;
/**
* Need a direct handle on the database for certain lookup functions.
*/
private SQLiteDatabase mDatabase;
@Override
public final void onCreate() {
super.onCreate();
LogUtils.logI("IdlPeopleInterface.onCreate() "
+ "Initialising IPC for com.vodafone360.people");
if (!SettingsManager.getBooleanProperty(Settings.ENABLE_AIDL_KEY)) {
LogUtils.logW("IdlPeopleInterface.onCreate() "
+ "AIDL is disabled at built time");
return;
}
/** Start the Service. **/
startService(new Intent(this, RemoteService.class));
mApplication = (MainApplication) getApplication();
mPeopleService = mApplication.getServiceInterface();
if (mPeopleService == null) {
LogUtils.logV("IdlPeopleInterface.onCreate() "
+ "Waiting for service to load");
mApplication.registerServiceLoadHandler(mServiceLoadedHandler);
}
if (mListeners == null) {
mListeners = new HashMap<String, IDatabaseSubscriber>();
}
}
/**
* Handler so we know when the IPeopleService has been started.
*/
private Handler mServiceLoadedHandler = new Handler() {
public void handleMessage(final Message msg) {
super.handleMessage(msg);
mApplication.unRegisterServiceLoadHandler();
onServiceLoaded();
}
};
/***
* Initialise now that the service has finally loaded.
*/
private void onServiceLoaded() {
LogUtils.logV("IdlPeopleInterface.onServiceLoaded() Service loaded");
if (!SettingsManager.getBooleanProperty(Settings.ENABLE_AIDL_KEY)) {
LogUtils.logI("IdlPeopleInterface.onStart() "
+ "AIDL disabled at build time");
return;
}
mPeopleService = mApplication.getServiceInterface();
mDatabase = mApplication.getDatabase().getReadableDatabase();
onStartListenerActivity();
}
/***
* Destroy the interface.
*
* TODO: Notify listeners that the interface has been destroyed.
*/
@Override
public final void onDestroy() {
super.onDestroy();
mPeopleService.unsubscribe(mHandler);
mPeopleService.removeEventCallback(mHandler);
}
/***
* Start the IdlPeopleInterface service.
*
* @param intent Starting intent.
* @param startId Starting identifier.
*/
@Override
public final void onStart(final Intent intent, final int startId) {
super.onStart(intent, startId);
if (!SettingsManager.getBooleanProperty(Settings.ENABLE_AIDL_KEY)) {
LogUtils.logI("IdlPeopleInterface.onStart() "
+ "AIDL disabled at build time");
return;
}
if (mPeopleService != null) {
onStartListenerActivity();
} else {
LogUtils.logW("IdlPeopleInterface.onStart() "
+ "People service should not be NULL, waiting for it to "
+ "start");
mApplication.registerServiceLoadHandler(mServiceLoadedHandler);
}
}
/***
* Subscribe listener activities, so we get notifications whenever
* anything happens in the engine.
*/
private void onStartListenerActivity() {
mPeopleService.subscribe(mHandler, -1L, true);
mPeopleService.addEventCallback(mHandler);
LogUtils.logI("IdlPeopleInterface.startListenerActivity() Notifying "
+ "listeners that the service is now ready to receive AIDL "
+ "calls");
for (Iterator<String> subscribersIterator
= mListeners.keySet().iterator();
subscribersIterator.hasNext();) {
final String listenerIdentifier = subscribersIterator.next();
final IDatabaseSubscriber listener
= mListeners.get(listenerIdentifier);
try {
listener.onServiceReady();
} catch (RemoteException e) {
LogUtils.logW("IdlPeopleInterface.startListenerActivity() "
+ "Got a RemoteException trying to contact ["
+ listenerIdentifier + "][" + listener
+ "] Removing from list of listeners");
subscribersIterator.remove();
}
}
}
/**
* Handler for incoming Engine messages. All messages are immediately
* passed on to listening third parties.
*/
private Handler mHandler = new Handler() {
/**
* We want to handle incoming events from the main engine code by
* passing them out to all 3rdParty listeners via AIDL.
*
* Two things to note:
* <li> This method is Synchronized - there are potentially many messages
* coming in from different engines. At the moment, they come from a single
* thread, but for maintenance reasons this handling is thread-safe, so that
* if a threaded mechanism is implemented in future we shouldn't have
* problem here.
* <li> The code is actually very simple - it runs through the list of
* listeners and directly passes out the Message. This is possible since
* the Message class implements the Parcelable interface, and so is meant
* to be very happy to be passed around in the way. One problem with this
* process as it stands (and this accounts for the presence of the third
* catch clause below) is that somewhere we seem to be putting Non-Parcelable
* objects into these Messages - so while we are "guaranteed" the ability
* to pass Messages directly via AIDL by the Parcelable interface, this
* isn't always the case.
*
* @param message - the message being sent to us by the engine to notify
* us of some event.
*/
@Override
public synchronized void handleMessage(final Message message) {
super.handleMessage(message);
LogUtils.logI("IdlPeopleInterface.handleMessage() Got a new "
+ "service message, sending it to subscribers - Message["
+ message.toString() + "]");
/*
* Also synchronise over the list of listeners, as the put/remove
* code for this list can be called from any number of external
* threads via AIDL.
*/
synchronized (mListeners) {
for (Iterator<String> subscribersIterator = mListeners.keySet().iterator();
subscribersIterator.hasNext();) {
/**
* Can't use iterator shorthand, as we might need to remove
* things from the list.
*/
final String listenerIdentifier = subscribersIterator.next();
final IDatabaseSubscriber listener = mListeners.get(listenerIdentifier);
LogUtils.logI("IdlPeopleInterface.handleMessage() "
+ "Sending message to [" + listenerIdentifier + "]");
try {
//Pass the message out via IDL
listener.handleEvent(message);
} catch (DeadObjectException e) {
LogUtils.logE("IdlPeopleInterface.handleMessage() "
+ "DeadObjectException while trying to contact ["
+ listenerIdentifier + "][" + listener
+ "] - Removing from list of listeners", e);
subscribersIterator.remove();
} catch (RemoteException e){
LogUtils.logE("IdlPeopleInterface.handleMessage() "
+ "RemoteException while contacting listener", e);
} catch (NullPointerException e){
LogUtils.logE("IdlPeopleInterface.handleMessage() "
+ "NullPointerException while contacting" +
" listenter. Possibly they have the wrong" +
" dependencies.", e);
} catch (java.lang.RuntimeException e) {
/** Something in the message was not Parcelable. **/
if ("Can't marshal non-Parcelable objects across processes."
.equals( e.getLocalizedMessage() )) {
/**
* Someone has packed something into the message
* that isn't Parcelable.
* TODO: Address why we're putting non-Parcelable
* objects into a Message (which is meant to
* implement the Parcelable class).
**/
LogUtils.logE("IdlPeopleInterface.handleMessage() "
+ "Tried to martial non-parcelable object", e);
} else {
/** Throw the Exception anyway. **/
LogUtils.logE("IdlPeopleInterface.handleMessage() "
+ "RuntimeException", e);
throw(e);
}
}
}
}
}
};
@Override
public final boolean onUnbind(final Intent intent) {
return super.onUnbind(intent);
}
/**
* onBind is the function called when you try to get a handle on
* and AIDL service.
*
* The documentation at:
* http://developer.android.com/guide/topics/fundamentals.html
*
* recommends that onBind be implemented in a thread-safe manner,
* so the method is synchronized.
*
* @param intent Calling Intent.
*/
@Override
public final synchronized IBinder onBind(final Intent intent) {
LogUtils.logV("IdlPeopleInterface.onBind()");
if (SettingsManager.getBooleanProperty(Settings.ENABLE_AIDL_KEY)) {
LogUtils.logV("IdlPeopleInterface.onBind() "
+ "AIDL interface enabled, so passing a "
+ "IPeopleSubscriptionService back to binder");
return new IPeopleSubscriptionService();
} else {
LogUtils.logV("IdlPeopleInterface.onBind() "
+ "AIDL service disabled at build time");
return null;
}
}
/**
* The idea is that what we're exposing via AIDL should be as close as
* possible to the IPeopleService interface. Clients should be able to
* access the services as if they were internal.
*
* This is set this up to "implement" the IPeopleService - of course it
* does this simply by forwarding requests to a IPeopleService service
* which takes the action. The reason for this model is that this service
* must track any and all changes made to the original service, so that
* clients can continue to integrate with the latest changes.
*
* This class is defined in four sections:
* <li> Functions currently implemented & available through AIDL.
* <li> Functions implemented, but available in a slightly different
* form via AIDL.
* <li> Functions not yet implemented.
* <li> Functions that will not be implemented in AIDL.
*
* Except where otherwise noted, all methods perform exactly the same
* operations as the equivalents in
* com.vodafone360.people.interfaces.IPeopleService
*/
public class IPeopleSubscriptionService extends
IDatabaseSubscriptionService.Stub implements IPeopleService,
ThirdPartyUtils {
/**
* Subscribe to find out about any events the 360 Services would like
* the UI to know about (and thus we'd like the client to know about).
* This provides a push notification system for clients to hear about
* interesting things going on.
*
* Returns:
* <li> true if the service is ready to receive requests,
* <li> false otherwise. Subscribers will be notified when the service
* is ready with a call to their "onServiceReady()" function.
*
* @param identifier Unique subscriber ID.
* @param subscriber Subscriber IDatabaseSubscriber interface.
* @return TRUE if the PeopleService is already ready.
*/
@Override
public final boolean subscribe(final String identifier,
final IDatabaseSubscriber subscriber) {
LogUtils.logV("IdlPeopleInterface.subscribe() "
+ "Adding subscriber to get push notifications");
if (identifier == null || subscriber == null) {
// Null is not a valid option for either argument
return false;
}
boolean boundAndReady = false;
// In case anyone else is also adding/removing/iterating
synchronized (mListeners) {
mListeners.put(identifier, subscriber);
}
if (mPeopleService == null) {
LogUtils.logW("IdlPeopleInterface.subscribe() "
+ "PeopleService was NULL while while trying to add ["
+ subscriber + "] to the list of subscribers.");
LogUtils.logW("IdlPeopleInterface.subscribe() Starting service"
+ " - will call back the listener when ready.");
mApplication.registerServiceLoadHandler(mServiceLoadedHandler);
boundAndReady = false;
} else {
LogUtils.logI("IdlPeopleInterface.subscribe() Service ready. "
+ "It's safe for [" + identifier + "] to make calls.");
/**
* Subscribe every time because IPeopleService is currently
* only capable of handling one subscriber.
*/
mPeopleService.subscribe(mHandler, -1L, true);
boundAndReady = true;
}
return boundAndReady;
}
/**
* Always call this when you want to finish, otherwise we have a memory
* leak (among other things).
*
* @param identifier Some unique identifier for your subscriber.
* @return TRUE if unsubscribe was successful. Only really returns
* FALSE if you couldn't be found in the list of subscribers.
*/
@Override
public final boolean unsubscribe(final String identifier) {
boolean managedToUnsubscribe = false;
/**
* Code is synchronised in case anyone else is also adding,
* removing or iterating.
*/
synchronized (mListeners) {
if (mListeners.remove(identifier) != null) {
LogUtils.logI("IdlPeopleInterface.unsubscribe()"
+ "Successfully unsubscribed");
managedToUnsubscribe = true;
} else {
LogUtils.logI("IdlPeopleInterface.unsubscribe() "
+ "Got unsubscribe call, but did not find the "
+ "identifier in the list");
managedToUnsubscribe = false;
}
}
return managedToUnsubscribe;
}
/**
* TODO: Currently doing a NullPointer check. Need to file a bug report
* about this; occasionally getting NullPointer exceptions when this
* is called, and it's not obvious why. Considering adding similar
* checks elsewhere since exceptions aren't propagated via AIDL - they
* just crash the service.
*/
@Override
public final void checkForUpdates() {
LogUtils.logI("IdlPeopleInterface.checkForUpdates()");
try {
mPeopleService.checkForUpdates();
} catch (NullPointerException e) {
LogUtils.logE("IdlPeopleInterface.checkForUpdates()"
+ "NullPointerException mPeopleService["
+ mPeopleService + "]", e);
}
}
/**
* @see com.vodafone360.people.service.interfaces.deleteIdentity()
*/
@Override
public final void deleteIdentity(final String network,
final String identityId) {
mPeopleService.deleteIdentity(network, identityId);
}
/**
* @see com.vodafone360.people.service.interfaces.downloadMeProfileFirstTime()
*/
@Override
public final void downloadMeProfileFirstTime() {
mPeopleService.downloadMeProfileFirstTime();
}
/**
* @see com.vodafone360.people.service.interfaces.fetchPrivacyStatementy()
*/
@Override
public final void fetchPrivacyStatement() {
mPeopleService.fetchPrivacyStatement();
}
/**
* @see com.vodafone360.people.service.interfaces.fetchTermsOfService()
*/
@Override
public final void fetchTermsOfService() {
mPeopleService.fetchTermsOfService();
}
/**
* @see com.vodafone360.people.service.interfaces.fetchUsernameState()
*/
@Override
public final void fetchUsernameState(final String username) {
mPeopleService.fetchUsernameState(username);
}
/**
* @see com.vodafone360.people.service.interfaces.getAvailableThirdPartyIdentities()
*/
@Override
public final ArrayList<Identity> getAvailableThirdPartyIdentities() {
return mPeopleService.getAvailableThirdPartyIdentities();
}
/**
* @see com.vodafone360.people.service.interfaces.getLoginRequired()
*/
@Override
public final boolean getLoginRequired() {
return mPeopleService.getLoginRequired();
}
/**
* @see com.vodafone360.people.service.interfaces.getMoreTimelines()
*/
@Override
public final void getMoreTimelines() {
mPeopleService.getMoreTimelines();
}
/**
* @see com.vodafone360.people.service.interfaces.getMy360AndThirdPartyChattableIdentities()
*/
@Override
public final ArrayList<Identity> getMy360AndThirdPartyChattableIdentities() {
return mPeopleService.getMy360AndThirdPartyChattableIdentities();
}
/**
* @see com.vodafone360.people.service.interfaces.getMyThirdPartyIdentities()
*/
@Override
public final ArrayList<Identity> getMyThirdPartyIdentities() {
return mPeopleService.getMyThirdPartyIdentities();
}
/**
* @see com.vodafone360.people.service.interfaces.getOlderStatuses()
*/
@Override
public final void getOlderStatuses() {
mPeopleService.getOlderStatuses();
}
/**
* @see com.vodafone360.people.database.tables
*/
public int getPresence(final long localContactID){
return com.vodafone360.people.database.tables.ContactSummaryTable.
getPresence(localContactID).ordinal();
}
/**
* @see com.vodafone360.people.service.interfaces.getPresenceList()
*/
@Override
public final void getPresenceList(final long contactId) {
mPeopleService.getPresenceList(contactId);
}
/**
* @see com.vodafone360.people.service.interfaces.getRoamingDeviceSetting()
*/
@Override
public final boolean getRoamingDeviceSetting() {
return mPeopleService.getRoamingDeviceSetting();
}
/**
* @see com.vodafone360.people.service.interfaces.getRoamingNotificationType()
*/
@Override
public final int getRoamingNotificationType() {
return mPeopleService.getRoamingNotificationType();
}
/**
* @see com.vodafone360.people.service.interfaces.getStatuses()
*/
@Override
public final void getStatuses() {
mPeopleService.getStatuses();
}
/**
* Return user presence status.
* Extra method provide to allow easy grabbing of user presence info.
*
* @param localContactId ID for contact.
* @return User presence.
*/
public User getUserPresenceStatusByLocalContactId(long localContactId) {
LogUtils.logV("IdlPeopleInterface.getUserPresenceStatusByLocalContactId() "
+ "(localContactId: " + localContactId + ")");
return PresenceDbUtils.getUserPresenceStatusByLocalContactId(
localContactId, mApplication.getDatabase());
}
/***
* @param loginDetails for user
* @see com.vodafone360.people.service.interfaces.logon()
*/
@Override
public final void logon(final LoginDetails loginDetails) {
mPeopleService.logon(loginDetails);
}
/***
* This is a workaround - The client must pass in the ordinal of the
* appropriate ENUM from PersistSettings.InternetAvail(). However the
* internal classes and AIDL don't work together correctly.
*/
public void notifyDataSettingChanged(int internetAvail) {
notifyDataSettingChanged(
PersistSettings.InternetAvail.values()[internetAvail]);
}
/**
* @see com.vodafone360.people.service.interfaces.pingUserActivity()
*/
@Override
public final void pingUserActivity() {
mPeopleService.pingUserActivity();
}
/***
* @see com.vodafone360.people.service.interfaces.register()
*/
@Override
public final void register(final RegistrationDetails details) {
mPeopleService.register(details);
}
/**
* @see com.vodafone360.people.service.interfaces.sendMessage()
*/
@Override
public final void sendMessage(final long toLocalContactId,
final String body, final int socialNetworkId) {
LogUtils.logI("IdlPeopleInterface.sendMessage()");
try {
mPeopleService.sendMessage(toLocalContactId, body, socialNetworkId);
} catch (ArrayIndexOutOfBoundsException e) {
/*
* If the user passes in an invalid socialNetworkId then it can
* cause this exception in
* NetworkPresence.SocialNetwork.getPresenceValue(int)
*
* (No stack trace as the user doesn't need to know about the
* internals in this instance).
*/
LogUtils.logE("Tried to send message to invalid social network.");
}
}
/***
* This is a workaround - The client must pass in the ordinal of the
* appropriate ENUM from ContactSummary.OnlineStatus(). However the
* internal classes and AIDL don't work together correctly.
*/
public void setAvailability(final int status) {
setAvailability(ContactSummary.OnlineStatus.values()[status]);
}
/**
* @see com.vodafone360.people.service.interfaces.setAvailability()
* Not yet supported, as function overloading is not supported in AIDL.
*/
public void setAvailability(int network, int status) {
setAvailability(SocialNetwork.values()[network],
OnlineStatus.values()[status]);
}
/**
* @see com.vodafone360.people.service.interfaces.setIdentityStatus()
*/
@Override
public final void setIdentityStatus(final String network,
final String identityId, final boolean identityStatus) {
mPeopleService.setIdentityStatus(network, identityId,
identityStatus);
}
/**
* @see com.vodafone360.people.service.interfaces.setNewUpdateFrequency()
*/
@Override
public final void setNewUpdateFrequency() {
mPeopleService.setNewUpdateFrequency();
}
/**
* @see com.vodafone360.people.service.interfaces.setShowRoamingNotificationAgain()
*/
@Override
public final void setShowRoamingNotificationAgain(
final boolean showAgain) {
mPeopleService.setShowRoamingNotificationAgain(showAgain);
}
/**
* @see com.vodafone360.people.service.interfaces.startBackgroundContactSync()
*/
@Override
public final void startBackgroundContactSync(final long delay) {
}
/**
* @see com.vodafone360.people.service.interfaces.startContactSync()
*/
@Override
public final void startContactSync() {
mPeopleService.startContactSync();
}
/**
* @see com.vodafone360.people.service.interfaces.startStatusesSync()
*/
@Override
public final void startStatusesSync() {
mPeopleService.startStatusesSync();
}
/**
* @see com.vodafone360.people.service.interfaces.updateChatNotification()
*/
@Override
public final void updateChatNotification(final long localContactId) {
mPeopleService.updateChatNotification(localContactId);
}
/**
* @see com.vodafone360.people.service.interfaces.uploadMeProfile()
*/
@Override
public final void uploadMeProfile() {
mPeopleService.uploadMeProfile();
}
/**
* @see com.vodafone360.people.service.interfaces.uploadMyStatus()
*/
@Override
public final void uploadMyStatus(final String statusText) {
mPeopleService.uploadMyStatus(statusText);
}
/**
* @see com.vodafone360.people.service.interfaces.validateIdentityCredentials()
*/
@Override
public final void validateIdentityCredentials(final boolean dryRun,
final String network, final String username,
final String password, final Bundle identityCapabilityStatus) {
mPeopleService.validateIdentityCredentials(dryRun, network, username,
password, identityCapabilityStatus);
}
/*
* These are methods that we'd like to expose, but are difficult
* through AIDL (see "substitute" versions above). The main problem is
* internal classes which require further investigation.
*/
@Override
public final void notifyDataSettingChanged(
final InternetAvail internetAvail) {
mPeopleService.notifyDataSettingChanged(internetAvail);
}
/**
* @see com.vodafone360.people.service.interfaces.setAvailability()
*/
@Override
public final void setAvailability(final OnlineStatus status) {
mPeopleService.setAvailability(status);
}
/**
* @see com.vodafone360.people.service.interfaces.setAvailability()
* Not currently working as function overloading is not supported in
* AIDL.
*/
public final void setAvailability(final SocialNetwork network,
final OnlineStatus status) {
mPeopleService.setAvailability(network, status);
}
/*
* Below are the methods I've not yet exposed - mostly because either
* they have non-primitive return types, or non-primitive arguments.
* Since most of the data types used appear to be parcelable, I'll be
* moving forward on this hopefully soon.
*
* An outstanding issue is that some classes implement the "Parcelable"
* interface, but fail to provide a "CREATOR" field - which is
* necessary for them to be dealt with properly in the AIDL. This
* functionality could be added to get these methods working.
*/
/***
* NetworkAgentState does not implement the Parcelable interface.
* Unless we change this, there is no chance for this function to be
* exposed via AIDL in its current form.
*/
@Override
public final NetworkAgentState getNetworkAgentState() {
// Not exposed via AIDL.
return null;
}
/***
* NetworkAgentState does not implement the Parcelable interface.
* Unless we change this, there is no chance for this function to be
* exposed via AIDL in its current form.
*/
@Override
public void setNetworkAgentState(final NetworkAgentState state) {
// Not exposed via AIDL.
}
/***
* Because of the different mechanism for subscription/unsubscription
* implemented by this service, these methods will remain unimplemented.
* (When a client "subscribes" they get *all* notifications).
*/
@Override
public void addEventCallback(final Handler uiHandler) {
// Not exposed via AIDL.
}
@Override
public void removeEventCallback(final Handler uiHandler) {
// Not exposed via AIDL.
}
@Override
public void subscribe(final Handler handler, final Long contactId,
final boolean chat) {
// Not exposed via AIDL.
}
@Override
public void unsubscribe(final Handler handler) {
// Not exposed via AIDL.
}
@Override
public boolean isSettingStatusOnNetworkInProgress(String network) {
return mPeopleService.isSettingStatusOnNetworkInProgress(network);
}
}
}