Merge "Adds @hide ImsService APIs"

This commit is contained in:
Treehugger Robot
2017-02-17 19:21:45 +00:00
committed by Gerrit Code Review
13 changed files with 1471 additions and 4 deletions

View File

@@ -435,6 +435,7 @@ LOCAL_SRC_FILES += \
telephony/java/com/android/ims/internal/IImsEcbm.aidl \
telephony/java/com/android/ims/internal/IImsEcbmListener.aidl \
telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl \
telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl \
telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl \
telephony/java/com/android/ims/internal/IImsService.aidl \
telephony/java/com/android/ims/internal/IImsServiceController.aidl \

View File

@@ -0,0 +1,430 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.telephony.ims;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.CarrierConfigManager;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MMTelFeature;
import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
import android.util.SparseArray;
import com.android.ims.ImsCallProfile;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsCallSessionListener;
import com.android.ims.internal.IImsConfig;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsFeatureStatusCallback;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsServiceController;
import com.android.ims.internal.IImsServiceFeatureListener;
import com.android.ims.internal.IImsUt;
import com.android.internal.annotations.VisibleForTesting;
/**
* Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
* ImsService must register the service in their AndroidManifest to be detected by the framework.
* First, the application must declare that they use the "android.permission.BIND_IMS_SERVICE"
* permission. Then, the ImsService definition in the manifest must follow the following format:
*
* ...
* <service android:name=".EgImsService"
* android:permission="android.permission.BIND_IMS_SERVICE" >
* <!-- Apps must declare which features they support as metadata. The different categories are
* defined below. In this example, the RCS_FEATURE feature is supported. -->
* <meta-data android:name="android.telephony.ims.RCS_FEATURE" android:value="true" />
* <intent-filter>
* <action android:name="android.telephony.ims.ImsService" />
* </intent-filter>
* </service>
* ...
*
* The telephony framework will then bind to the ImsService you have defined in your manifest
* if you are either:
* 1) Defined as the default ImsService for the device in the device overlay using
* "config_ims_package".
* 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using
* {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}.
*
* The features that are currently supported in an ImsService are:
* - RCS_FEATURE: This ImsService implements the {@link RcsFeature} class.
* - MMTEL_FEATURE: This ImsService implements the {@link MMTelFeature} class.
* - EMERGENCY_MMTEL_FEATURE: This ImsService implements the {@link MMTelFeature} class and will be
* available to place emergency calls at all times. This MUST be implemented by the default
* ImsService provided in the device overlay.
*
* @hide
*/
public abstract class ImsService extends ImsServiceBase {
private static final String LOG_TAG = "ImsService";
/**
* The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService.
*/
public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService";
// A map of slot Id -> Set of features corresponding to that slot.
private final SparseArray<SparseArray<ImsFeature>> mFeatures = new SparseArray<>();
// Implements all supported features as a flat interface.
protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
@Override
public void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c)
throws RemoteException {
synchronized (mFeatures) {
onCreateImsFeatureInternal(slotId, feature, c);
}
}
@Override
public void removeImsFeature(int slotId, int feature) throws RemoteException {
synchronized (mFeatures) {
onRemoveImsFeatureInternal(slotId, feature);
}
}
@Override
public int startSession(int slotId, int featureType, PendingIntent incomingCallIntent,
IImsRegistrationListener listener) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
return feature.startSession(incomingCallIntent, listener);
}
}
return 0;
}
@Override
public void endSession(int slotId, int featureType, int sessionId) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
feature.endSession(sessionId);
}
}
}
@Override
public boolean isConnected(int slotId, int featureType, int sessionId, int callSessionType,
int callType) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
return feature.isConnected(sessionId, callSessionType, callType);
}
}
return false;
}
@Override
public boolean isOpened(int slotId, int featureType, int sessionId) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
return feature.isOpened(sessionId);
}
}
return false;
}
@Override
public int getFeatureStatus(int slotId, int featureType) throws RemoteException {
int status = ImsFeature.STATE_NOT_AVAILABLE;
synchronized (mFeatures) {
SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
if (featureMap != null) {
ImsFeature feature = getImsFeatureFromType(featureMap, featureType);
if (feature != null) {
status = feature.getFeatureState();
}
}
}
return status;
}
@Override
public void addRegistrationListener(int slotId, int featureType, int sessionId,
IImsRegistrationListener listener) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
feature.addRegistrationListener(sessionId, listener);
}
}
}
@Override
public void removeRegistrationListener(int slotId, int featureType, int sessionId,
IImsRegistrationListener listener) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
feature.removeRegistrationListener(sessionId, listener);
}
}
}
@Override
public ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
int callSessionType, int callType) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
return feature.createCallProfile(sessionId, callSessionType, callType);
}
}
return null;
}
@Override
public IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
ImsCallProfile profile, IImsCallSessionListener listener) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
return feature.createCallSession(sessionId, profile, listener);
}
}
return null;
}
@Override
public IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
String callId) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
return feature.getPendingCallSession(sessionId, callId);
}
}
return null;
}
@Override
public IImsUt getUtInterface(int slotId, int featureType, int sessionId)
throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
return feature.getUtInterface(sessionId);
}
}
return null;
}
@Override
public IImsConfig getConfigInterface(int slotId, int featureType, int sessionId)
throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
return feature.getConfigInterface(sessionId);
}
}
return null;
}
@Override
public void turnOnIms(int slotId, int featureType, int sessionId) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
feature.turnOnIms(sessionId);
}
}
}
@Override
public void turnOffIms(int slotId, int featureType, int sessionId) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
feature.turnOffIms(sessionId);
}
}
}
@Override
public IImsEcbm getEcbmInterface(int slotId, int featureType, int sessionId)
throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
return feature.getEcbmInterface(sessionId);
}
}
return null;
}
@Override
public void setUiTTYMode(int slotId, int featureType, int sessionId, int uiTtyMode,
Message onComplete) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
feature.setUiTTYMode(sessionId, uiTtyMode, onComplete);
}
}
}
@Override
public IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType,
int sessionId) throws RemoteException {
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
return feature.getMultiEndpointInterface(sessionId);
}
}
return null;
}
};
@Override
public IBinder onBind(Intent intent) {
if(SERVICE_INTERFACE.equals(intent.getAction())) {
return mImsServiceController;
}
return null;
}
/**
* Called from the ImsResolver to create the requested ImsFeature, as defined by the slot and
* featureType
* @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
* @param featureType An integer representing the type of ImsFeature being created. This is
* defined in {@link ImsFeature}.
*/
// Be sure to lock on mFeatures before accessing this method
private void onCreateImsFeatureInternal(int slotId, int featureType,
IImsFeatureStatusCallback c) {
SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
if (featureMap == null) {
featureMap = new SparseArray<>();
mFeatures.put(slotId, featureMap);
}
ImsFeature f = makeImsFeature(slotId, featureType);
if (f != null) {
f.setImsFeatureStatusCallback(c);
featureMap.put(featureType, f);
}
}
/**
* Called from the ImsResolver to remove an existing ImsFeature, as defined by the slot and
* featureType.
* @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
* @param featureType An integer representing the type of ImsFeature being removed. This is
* defined in {@link ImsFeature}.
*/
// Be sure to lock on mFeatures before accessing this method
private void onRemoveImsFeatureInternal(int slotId, int featureType) {
SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
if (featureMap == null) {
return;
}
ImsFeature featureToRemove = getImsFeatureFromType(featureMap, featureType);
if (featureToRemove != null) {
featureMap.remove(featureType);
featureToRemove.notifyFeatureRemoved(slotId);
// Remove reference to Binder
featureToRemove.setImsFeatureStatusCallback(null);
}
}
// Be sure to lock on mFeatures before accessing this method
private MMTelFeature resolveMMTelFeature(int slotId, int featureType) {
SparseArray<ImsFeature> features = getImsFeatureMap(slotId);
MMTelFeature feature = null;
if (features != null) {
feature = resolveImsFeature(features, featureType, MMTelFeature.class);
}
return feature;
}
// Be sure to lock on mFeatures before accessing this method
private <T extends ImsFeature> T resolveImsFeature(SparseArray<ImsFeature> set, int featureType,
Class<T> className) {
ImsFeature feature = getImsFeatureFromType(set, featureType);
if (feature == null) {
return null;
}
try {
return className.cast(feature);
} catch (ClassCastException e)
{
Log.e(LOG_TAG, "Can not cast ImsFeature! Exception: " + e.getMessage());
}
return null;
}
@VisibleForTesting
// Be sure to lock on mFeatures before accessing this method
public SparseArray<ImsFeature> getImsFeatureMap(int slotId) {
return mFeatures.get(slotId);
}
@VisibleForTesting
// Be sure to lock on mFeatures before accessing this method
public ImsFeature getImsFeatureFromType(SparseArray<ImsFeature> set, int featureType) {
return set.get(featureType);
}
private ImsFeature makeImsFeature(int slotId, int feature) {
switch (feature) {
case ImsFeature.EMERGENCY_MMTEL: {
return onCreateEmergencyMMTelImsFeature(slotId);
}
case ImsFeature.MMTEL: {
return onCreateMMTelImsFeature(slotId);
}
case ImsFeature.RCS: {
return onCreateRcsFeature(slotId);
}
}
// Tried to create feature that is not defined.
return null;
}
/**
* @return An implementation of MMTelFeature that will be used by the system for MMTel
* functionality. Must be able to handle emergency calls at any time as well.
*/
public abstract MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId);
/**
* @return An implementation of MMTelFeature that will be used by the system for MMTel
* functionality.
*/
public abstract MMTelFeature onCreateMMTelImsFeature(int slotId);
/**
* @return An implementation of RcsFeature that will be used by the system for RCS.
*/
public abstract RcsFeature onCreateRcsFeature(int slotId);
}

View File

@@ -22,7 +22,9 @@ import android.content.Intent;
import android.os.IBinder;
/**
* Base ImsService Implementation, which is used by the ImsResolver to bind.
* Base ImsService Implementation, which is used by the ImsResolver to bind. ImsServices that do not
* need to provide an ImsService implementation but still wish to be managed by the ImsResolver
* lifecycle may implement this class directly.
* @hide
*/
@SystemApi

View File

@@ -0,0 +1,316 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.telephony.ims;
import android.app.PendingIntent;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.ims.feature.IRcsFeature;
import android.telephony.ims.feature.ImsFeature;
import android.util.Log;
import com.android.ims.ImsCallProfile;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsCallSessionListener;
import com.android.ims.internal.IImsConfig;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsServiceController;
import com.android.ims.internal.IImsServiceFeatureListener;
import com.android.ims.internal.IImsUt;
/**
* A container of the IImsServiceController binder, which implements all of the ImsFeatures that
* the platform currently supports: MMTel and RCS.
* @hide
*/
public class ImsServiceProxy extends ImsServiceProxyCompat implements IRcsFeature {
protected String LOG_TAG = "ImsServiceProxy";
private final int mSupportedFeature;
// Start by assuming the proxy is available for usage.
private boolean mIsAvailable = true;
// ImsFeature Status from the ImsService. Cached.
private Integer mFeatureStatusCached = null;
private ImsServiceProxy.INotifyStatusChanged mStatusCallback;
private final Object mLock = new Object();
public interface INotifyStatusChanged {
void notifyStatusChanged();
}
private final IImsServiceFeatureListener mListenerBinder =
new IImsServiceFeatureListener.Stub() {
@Override
public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
// The feature has been re-enabled. This may happen when the service crashes.
synchronized (mLock) {
if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
Log.i(LOG_TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
feature);
mIsAvailable = true;
}
}
}
@Override
public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
synchronized (mLock) {
if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
Log.i(LOG_TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
feature);
mIsAvailable = false;
}
}
}
@Override
public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
synchronized (mLock) {
Log.i(LOG_TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
" status: " + status);
if (mSlotId == slotId && feature == mSupportedFeature) {
mFeatureStatusCached = status;
}
}
if (mStatusCallback != null) {
mStatusCallback.notifyStatusChanged();
}
}
};
public ImsServiceProxy(int slotId, IBinder binder, int featureType) {
super(slotId, binder);
mSupportedFeature = featureType;
}
public ImsServiceProxy(int slotId, int featureType) {
super(slotId, null /*IBinder*/);
mSupportedFeature = featureType;
}
public IImsServiceFeatureListener getListener() {
return mListenerBinder;
}
public void setBinder(IBinder binder) {
mBinder = binder;
}
@Override
public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
return getServiceInterface(mBinder).startSession(mSlotId, mSupportedFeature,
incomingCallIntent, listener);
}
}
@Override
public void endSession(int sessionId) throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
getServiceInterface(mBinder).endSession(mSlotId, mSupportedFeature, sessionId);
}
}
@Override
public boolean isConnected(int sessionId, int callServiceType, int callType)
throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
return getServiceInterface(mBinder).isConnected(mSlotId, mSupportedFeature, sessionId,
callServiceType, callType);
}
}
@Override
public boolean isOpened(int sessionId) throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature, sessionId);
}
}
@Override
public void addRegistrationListener(int sessionId, IImsRegistrationListener listener)
throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
getServiceInterface(mBinder).addRegistrationListener(mSlotId, mSupportedFeature,
sessionId, listener);
}
}
@Override
public void removeRegistrationListener(int sessionId, IImsRegistrationListener listener)
throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
getServiceInterface(mBinder).removeRegistrationListener(mSlotId, mSupportedFeature,
sessionId, listener);
}
}
@Override
public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
return getServiceInterface(mBinder).createCallProfile(mSlotId, mSupportedFeature,
sessionId, callServiceType, callType);
}
}
@Override
public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
IImsCallSessionListener listener) throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
return getServiceInterface(mBinder).createCallSession(mSlotId, mSupportedFeature,
sessionId, profile, listener);
}
}
@Override
public IImsCallSession getPendingCallSession(int sessionId, String callId)
throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
return getServiceInterface(mBinder).getPendingCallSession(mSlotId, mSupportedFeature,
sessionId, callId);
}
}
@Override
public IImsUt getUtInterface(int sessionId) throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature,
sessionId);
}
}
@Override
public IImsConfig getConfigInterface(int sessionId) throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature,
sessionId);
}
}
@Override
public void turnOnIms(int sessionId) throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature, sessionId);
}
}
@Override
public void turnOffIms(int sessionId) throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature, sessionId);
}
}
@Override
public IImsEcbm getEcbmInterface(int sessionId) throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature,
sessionId);
}
}
@Override
public void setUiTTYMode(int sessionId, int uiTtyMode, Message onComplete)
throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
getServiceInterface(mBinder).setUiTTYMode(mSlotId, mSupportedFeature, sessionId,
uiTtyMode, onComplete);
}
}
@Override
public IImsMultiEndpoint getMultiEndpointInterface(int sessionId) throws RemoteException {
synchronized (mLock) {
checkBinderConnection();
return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
mSupportedFeature, sessionId);
}
}
@Override
public int getFeatureStatus() {
synchronized (mLock) {
if (mFeatureStatusCached != null) {
return mFeatureStatusCached;
}
}
// Don't synchronize on Binder call.
Integer status = retrieveFeatureStatus();
synchronized (mLock) {
if (status == null) {
return ImsFeature.STATE_NOT_AVAILABLE;
}
// Cache only non-null value for feature status.
mFeatureStatusCached = status;
}
return status;
}
/**
* Internal method used to retrieve the feature status from the corresponding ImsService.
*/
private Integer retrieveFeatureStatus() {
if (mBinder != null) {
try {
return getServiceInterface(mBinder).getFeatureStatus(mSlotId, mSupportedFeature);
} catch (RemoteException e) {
// Status check failed, don't update cache
}
}
return null;
}
/**
* @param c Callback that will fire when the feature status has changed.
*/
public void setStatusCallback(INotifyStatusChanged c) {
mStatusCallback = c;
}
@Override
public boolean isBinderAlive() {
return mIsAvailable && getFeatureStatus() == ImsFeature.STATE_READY && mBinder != null &&
mBinder.isBinderAlive();
}
private IImsServiceController getServiceInterface(IBinder b) {
return IImsServiceController.Stub.asInterface(b);
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.telephony.ims;
import android.app.PendingIntent;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.ims.feature.IMMTelFeature;
import android.telephony.ims.feature.ImsFeature;
import com.android.ims.ImsCallProfile;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsCallSessionListener;
import com.android.ims.internal.IImsConfig;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsService;
import com.android.ims.internal.IImsUt;
/**
* Compatibility class that implements the new ImsService IMMTelFeature interface, but
* uses the old IImsService interface to support older devices that implement the deprecated
* opt/net/ims interface.
* @hide
*/
public class ImsServiceProxyCompat implements IMMTelFeature {
protected final int mSlotId;
protected IBinder mBinder;
public ImsServiceProxyCompat(int slotId, IBinder binder) {
mSlotId = slotId;
mBinder = binder;
}
@Override
public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
throws RemoteException {
checkBinderConnection();
return getServiceInterface(mBinder).open(mSlotId, ImsFeature.MMTEL, incomingCallIntent,
listener);
}
@Override
public void endSession(int sessionId) throws RemoteException {
checkBinderConnection();
getServiceInterface(mBinder).close(sessionId);
}
@Override
public boolean isConnected(int sessionId, int callServiceType, int callType)
throws RemoteException {
checkBinderConnection();
return getServiceInterface(mBinder).isConnected(sessionId, callServiceType, callType);
}
@Override
public boolean isOpened(int sessionId) throws RemoteException {
checkBinderConnection();
return getServiceInterface(mBinder).isOpened(sessionId);
}
@Override
public void addRegistrationListener(int sessionId, IImsRegistrationListener listener)
throws RemoteException {
checkBinderConnection();
getServiceInterface(mBinder).addRegistrationListener(mSlotId, ImsFeature.MMTEL, listener);
}
@Override
public void removeRegistrationListener(int sessionId, IImsRegistrationListener listener)
throws RemoteException {
checkBinderConnection();
// Not Implemented in old ImsService. If the registration listener becomes invalid, the
// ImsService will remove.
}
@Override
public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
throws RemoteException {
checkBinderConnection();
return getServiceInterface(mBinder).createCallProfile(sessionId, callServiceType, callType);
}
@Override
public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
IImsCallSessionListener listener) throws RemoteException {
checkBinderConnection();
return getServiceInterface(mBinder).createCallSession(sessionId, profile, listener);
}
@Override
public IImsCallSession getPendingCallSession(int sessionId, String callId)
throws RemoteException {
checkBinderConnection();
return getServiceInterface(mBinder).getPendingCallSession(sessionId, callId);
}
@Override
public IImsUt getUtInterface(int sessionId) throws RemoteException {
checkBinderConnection();
return getServiceInterface(mBinder).getUtInterface(sessionId);
}
@Override
public IImsConfig getConfigInterface(int sessionId) throws RemoteException {
checkBinderConnection();
return getServiceInterface(mBinder).getConfigInterface(mSlotId);
}
@Override
public void turnOnIms(int sessionId) throws RemoteException {
checkBinderConnection();
getServiceInterface(mBinder).turnOnIms(mSlotId);
}
@Override
public void turnOffIms(int sessionId) throws RemoteException {
checkBinderConnection();
getServiceInterface(mBinder).turnOffIms(mSlotId);
}
@Override
public IImsEcbm getEcbmInterface(int sessionId) throws RemoteException {
checkBinderConnection();
return getServiceInterface(mBinder).getEcbmInterface(sessionId);
}
@Override
public void setUiTTYMode(int sessionId, int uiTtyMode, Message onComplete)
throws RemoteException {
checkBinderConnection();
getServiceInterface(mBinder).setUiTTYMode(sessionId, uiTtyMode, onComplete);
}
@Override
public IImsMultiEndpoint getMultiEndpointInterface(int sessionId) throws RemoteException {
checkBinderConnection();
return getServiceInterface(mBinder).getMultiEndpointInterface(sessionId);
}
/**
* Base implementation, always returns READY for compatibility with old ImsService.
*/
public int getFeatureStatus() {
return ImsFeature.STATE_READY;
}
/**
* @return false if the binder connection is no longer alive.
*/
public boolean isBinderAlive() {
return mBinder != null && mBinder.isBinderAlive();
}
private IImsService getServiceInterface(IBinder b) {
return IImsService.Stub.asInterface(b);
}
protected void checkBinderConnection() throws RemoteException {
if (!isBinderAlive()) {
throw new RemoteException("ImsServiceProxy is not available for that feature.");
}
}
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.telephony.ims.feature;
import android.app.PendingIntent;
import android.os.Message;
import android.os.RemoteException;
import com.android.ims.ImsCallProfile;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsCallSessionListener;
import com.android.ims.internal.IImsConfig;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsUt;
/**
* MMTel interface for an ImsService. When updating this interface, ensure that base implementations
* of your changes are also present in MMTelFeature for compatibility with older versions of the
* MMTel feature.
* @hide
*/
public interface IMMTelFeature {
/**
* Notifies the MMTel feature that you would like to start a session. This should always be
* done before making/receiving IMS calls. The IMS service will register the device to the
* operator's network with the credentials (from ISIM) periodically in order to receive calls
* from the operator's network. When the IMS service receives a new call, it will send out an
* intent with the provided action string. The intent contains a call ID extra
* {@link IImsCallSession#getCallId} and it can be used to take a call.
*
* @param incomingCallIntent When an incoming call is received, the IMS service will call
* {@link PendingIntent#send} to send back the intent to the caller with
* {@link #INCOMING_CALL_RESULT_CODE} as the result code and the intent to fill in the call ID;
* It cannot be null.
* @param listener To listen to IMS registration events; It cannot be null
* @return an integer (greater than 0) representing the session id associated with the session
* that has been started.
*/
int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
throws RemoteException;
/**
* End a previously started session using the associated sessionId.
* @param sessionId an integer (greater than 0) representing the ongoing session. See
* {@link #startSession}.
*/
void endSession(int sessionId) throws RemoteException;
/**
* Checks if the IMS service has successfully registered to the IMS network with the specified
* service & call type.
*
* @param sessionId a session id which is obtained from {@link #startSession}
* @param callServiceType a service type that is specified in {@link ImsCallProfile}
* {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
* {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
* @param callType a call type that is specified in {@link ImsCallProfile}
* {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
* {@link ImsCallProfile#CALL_TYPE_VOICE}
* {@link ImsCallProfile#CALL_TYPE_VT}
* {@link ImsCallProfile#CALL_TYPE_VS}
* @return true if the specified service id is connected to the IMS network; false otherwise
* @throws RemoteException
*/
boolean isConnected(int sessionId, int callServiceType, int callType) throws RemoteException;
/**
* Checks if the specified IMS service is opened.
*
* @param sessionId a service id which is obtained from {@link #startSession}
* @return true if the specified service id is opened; false otherwise
*/
boolean isOpened(int sessionId) throws RemoteException;
/**
* Add a new registration listener for the client associated with the session Id.
* @param sessionId a session id which is obtained from {@link #startSession}
* @param listener An implementation of IImsRegistrationListener.
*/
void addRegistrationListener(int sessionId, IImsRegistrationListener listener)
throws RemoteException;
/**
* Remove a previously registered listener using {@link #addRegistrationListener} for the client
* associated with the session Id.
* @param sessionId a session id which is obtained from {@link #startSession}
* @param listener A previously registered IImsRegistrationListener
*/
void removeRegistrationListener(int sessionId, IImsRegistrationListener listener)
throws RemoteException;
/**
* Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
*
* @param sessionId a session id which is obtained from {@link #startSession}
* @param callServiceType a service type that is specified in {@link ImsCallProfile}
* {@link ImsCallProfile#SERVICE_TYPE_NONE}
* {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
* {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
* @param callType a call type that is specified in {@link ImsCallProfile}
* {@link ImsCallProfile#CALL_TYPE_VOICE}
* {@link ImsCallProfile#CALL_TYPE_VT}
* {@link ImsCallProfile#CALL_TYPE_VT_TX}
* {@link ImsCallProfile#CALL_TYPE_VT_RX}
* {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
* {@link ImsCallProfile#CALL_TYPE_VS}
* {@link ImsCallProfile#CALL_TYPE_VS_TX}
* {@link ImsCallProfile#CALL_TYPE_VS_RX}
* @return a {@link ImsCallProfile} object
*/
ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
throws RemoteException;
/**
* Creates a {@link ImsCallSession} with the specified call profile.
* Use other methods, if applicable, instead of interacting with
* {@link ImsCallSession} directly.
*
* @param sessionId a session id which is obtained from {@link #startSession}
* @param profile a call profile to make the call
* @param listener An implementation of IImsCallSessionListener.
*/
IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
IImsCallSessionListener listener) throws RemoteException;
/**
* Retrieves the call session associated with a pending call.
*
* @param sessionId a session id which is obtained from {@link #startSession}
* @param callId a call id to make the call
*/
IImsCallSession getPendingCallSession(int sessionId, String callId) throws RemoteException;
/**
* @return The Ut interface for the supplementary service configuration.
*/
IImsUt getUtInterface(int sessionId) throws RemoteException;
/**
* @return The config interface for IMS Configuration
*/
IImsConfig getConfigInterface(int sessionId) throws RemoteException;
/**
* Signal the MMTelFeature to turn on IMS when it has been turned off using {@link #turnOffIms}
* @param sessionId a session id which is obtained from {@link #startSession}
*/
void turnOnIms(int sessionId) throws RemoteException;
/**
* Signal the MMTelFeature to turn off IMS when it has been turned on using {@link #turnOnIms}
* @param sessionId a session id which is obtained from {@link #startSession}
*/
void turnOffIms(int sessionId) throws RemoteException;
/**
* @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
*/
IImsEcbm getEcbmInterface(int sessionId) throws RemoteException;
/**
* Sets the current UI TTY mode for the MMTelFeature.
* @param sessionId a session id which is obtained from {@link #startSession}
* @param uiTtyMode An integer containing the new UI TTY Mode.
* @param onComplete A {@link Message} to be used when the mode has been set.
* @throws RemoteException
*/
void setUiTTYMode(int sessionId, int uiTtyMode, Message onComplete) throws RemoteException;
/**
* @return MultiEndpoint interface for DEP notifications
*/
IImsMultiEndpoint getMultiEndpointInterface(int sessionId) throws RemoteException;
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.telephony.ims.feature;
/**
* Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
* in the framework.
* @hide
*/
public interface IRcsFeature {
}

View File

@@ -16,18 +16,112 @@
package android.telephony.ims.feature;
import android.annotation.IntDef;
import android.os.RemoteException;
import android.util.Log;
import com.android.ims.internal.IImsFeatureStatusCallback;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
/**
* Base class for all IMS features that are supported by the framework.
* @hide
*/
public class ImsFeature {
public abstract class ImsFeature {
private static final String LOG_TAG = "ImsFeature";
// Invalid feature value
public static final int INVALID = -1;
// ImsFeatures that are defined in the Manifests
// ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
// defined values in ImsServiceClass for compatibility purposes.
public static final int EMERGENCY_MMTEL = 0;
public static final int MMTEL = 1;
public static final int RCS = 2;
// Total number of features defined
public static final int MAX = 3;
// Integer values defining the state of the ImsFeature at any time.
@IntDef(flag = true,
value = {
STATE_NOT_AVAILABLE,
STATE_INITIALIZING,
STATE_READY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ImsState {}
public static final int STATE_NOT_AVAILABLE = 0;
public static final int STATE_INITIALIZING = 1;
public static final int STATE_READY = 2;
private List<INotifyFeatureRemoved> mRemovedListeners = new ArrayList<>();
private IImsFeatureStatusCallback mStatusCallback;
private @ImsState int mState = STATE_NOT_AVAILABLE;
public interface INotifyFeatureRemoved {
void onFeatureRemoved(int slotId);
}
public void addFeatureRemovedListener(INotifyFeatureRemoved listener) {
synchronized (mRemovedListeners) {
mRemovedListeners.add(listener);
}
}
public void removeFeatureRemovedListener(INotifyFeatureRemoved listener) {
synchronized (mRemovedListeners) {
mRemovedListeners.remove(listener);
}
}
// Not final for testing.
public void notifyFeatureRemoved(int slotId) {
synchronized (mRemovedListeners) {
mRemovedListeners.forEach(l -> l.onFeatureRemoved(slotId));
onFeatureRemoved();
}
}
public int getFeatureState() {
return mState;
}
protected final void setFeatureState(@ImsState int state) {
if (mState != state) {
mState = state;
notifyFeatureState(state);
}
}
// Not final for testing.
public void setImsFeatureStatusCallback(IImsFeatureStatusCallback c) {
mStatusCallback = c;
// If we have just connected, send queued status.
notifyFeatureState(mState);
}
/**
* Internal method called by ImsFeature when setFeatureState has changed.
* @param state
*/
private void notifyFeatureState(@ImsState int state) {
if (mStatusCallback != null) {
try {
Log.i(LOG_TAG, "notifying ImsFeatureState");
mStatusCallback.notifyImsFeatureStatus(state);
} catch (RemoteException e) {
mStatusCallback = null;
Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
}
}
}
/**
* Called when the feature is being removed and must be cleaned up.
*/
public abstract void onFeatureRemoved();
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.telephony.ims.feature;
import android.app.PendingIntent;
import android.os.Message;
import com.android.ims.ImsCallProfile;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsCallSessionListener;
import com.android.ims.internal.IImsConfig;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsUt;
import java.util.ArrayList;
import java.util.List;
/**
* Base implementation, which implements all methods in IMMTelFeature. Any class wishing to use
* MMTelFeature should extend this class and implement all methods that the service supports.
*
* @hide
*/
public class MMTelFeature extends ImsFeature implements IMMTelFeature {
@Override
public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener) {
return 0;
}
@Override
public void endSession(int sessionId) {
}
@Override
public boolean isConnected(int sessionId, int callSessionType, int callType) {
return false;
}
@Override
public boolean isOpened(int sessionId) {
return false;
}
@Override
public void addRegistrationListener(int sessionId, IImsRegistrationListener listener) {
}
@Override
public void removeRegistrationListener(int sessionId, IImsRegistrationListener listener) {
}
@Override
public ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType) {
return null;
}
@Override
public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
IImsCallSessionListener listener) {
return null;
}
@Override
public IImsCallSession getPendingCallSession(int sessionId, String callId) {
return null;
}
@Override
public IImsUt getUtInterface(int sessionId) {
return null;
}
@Override
public IImsConfig getConfigInterface(int sessionId) {
return null;
}
@Override
public void turnOnIms(int sessionId) {
}
@Override
public void turnOffIms(int sessionId) {
}
@Override
public IImsEcbm getEcbmInterface(int sessionId) {
return null;
}
@Override
public void setUiTTYMode(int sessionId, int uiTtyMode, Message onComplete) {
}
@Override
public IImsMultiEndpoint getMultiEndpointInterface(int sessionId) {
return null;
}
@Override
public void onFeatureRemoved() {
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.telephony.ims.feature;
/**
* Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
* this class and provide implementations of the IRcsFeature methods that they support.
* @hide
*/
public class RcsFeature extends ImsFeature implements IRcsFeature {
public RcsFeature() {
super();
}
@Override
public void onFeatureRemoved() {
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ims.internal;
/**
* Interface from ImsFeature in the ImsService to ImsServiceController.
* {@hide}
*/
oneway interface IImsFeatureStatusCallback {
void notifyImsFeatureStatus(int featureStatus);
}

View File

@@ -16,10 +16,50 @@
package com.android.ims.internal;
import android.app.PendingIntent;
import com.android.ims.ImsCallProfile;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsCallSessionListener;
import com.android.ims.internal.IImsConfig;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsFeatureStatusCallback;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsUt;
import android.os.Message;
/**
* See ImsService and IMMTelFeature for more information.
* {@hide}
*/
interface IImsServiceController {
void createImsFeature(int slotId, int feature);
// ImsService Control
void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c);
void removeImsFeature(int slotId, int feature);
// MMTel Feature
int startSession(int slotId, int featureType, in PendingIntent incomingCallIntent,
in IImsRegistrationListener listener);
void endSession(int slotId, int featureType, int sessionId);
boolean isConnected(int slotId, int featureType, int sessionId, int callSessionType, int callType);
boolean isOpened(int slotId, int featureType, int sessionId);
int getFeatureStatus(int slotId, int featureType);
void addRegistrationListener(int slotId, int featureType, int sessionId,
in IImsRegistrationListener listener);
void removeRegistrationListener(int slotId, int featureType, int sessionId,
in IImsRegistrationListener listener);
ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId, int callSessionType, int callType);
IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
in ImsCallProfile profile, IImsCallSessionListener listener);
IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
String callId);
IImsUt getUtInterface(int slotId, int featureType, int sessionId);
IImsConfig getConfigInterface(int slotId, int featureType, int sessionId);
void turnOnIms(int slotId, int featureType, int sessionId);
void turnOffIms(int slotId, int featureType, int sessionId);
IImsEcbm getEcbmInterface(int slotId, int featureType, int sessionId);
void setUiTTYMode(int slotId, int featureType, int sessionId, int uiTtyMode,
in Message onComplete);
IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType, int sessionId);
}

View File

@@ -17,9 +17,11 @@
package com.android.ims.internal;
/**
* Interface from ImsResolver to ImsServiceProxy in ImsManager.
* {@hide}
*/
oneway interface IImsServiceFeatureListener {
void imsFeatureCreated(int slotId, int feature);
void imsFeatureRemoved(int slotId, int feature);
void imsStatusChanged(int slotId, int feature, int status);
}