The method ImsFeature#setFeatureState can not be called in the constructor of MmTelFeature currently, because the IMS_SERVICE_UP intent will not be sent until mContext != null. Remove this dependency and ensure addImsFeatureStatusCallback is called after ImsFeature#initialize. Bug: 130569556 Test: atest GtsTelephonyTestCases; atest FrameworksTelephonyTests Merged-In: I562246c1995365308d26f44683f75bf5c46b7405 Change-Id: Ib3ca59eeeda89c0989cfd767257a6a598a97a670
369 lines
14 KiB
Java
369 lines
14 KiB
Java
/*
|
|
* 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.annotation.SystemApi;
|
|
import android.app.Service;
|
|
import android.content.Intent;
|
|
import android.os.IBinder;
|
|
import android.os.RemoteException;
|
|
import android.telephony.CarrierConfigManager;
|
|
import android.telephony.ims.aidl.IImsConfig;
|
|
import android.telephony.ims.aidl.IImsMmTelFeature;
|
|
import android.telephony.ims.aidl.IImsRcsFeature;
|
|
import android.telephony.ims.aidl.IImsRegistration;
|
|
import android.telephony.ims.aidl.IImsServiceController;
|
|
import android.telephony.ims.aidl.IImsServiceControllerListener;
|
|
import android.telephony.ims.feature.ImsFeature;
|
|
import android.telephony.ims.feature.MmTelFeature;
|
|
import android.telephony.ims.feature.RcsFeature;
|
|
import android.telephony.ims.stub.ImsConfigImplBase;
|
|
import android.telephony.ims.stub.ImsFeatureConfiguration;
|
|
import android.telephony.ims.stub.ImsRegistrationImplBase;
|
|
import android.util.Log;
|
|
import android.util.SparseArray;
|
|
|
|
import com.android.ims.internal.IImsFeatureStatusCallback;
|
|
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" >
|
|
* ...
|
|
* <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}.
|
|
*
|
|
* There are two ways to define to the platform which {@link ImsFeature}s this {@link ImsService}
|
|
* supports, dynamic or static definitions.
|
|
*
|
|
* In the static definition, the {@link ImsFeature}s that are supported are defined in the service
|
|
* definition of the AndroidManifest.xml file as metadata:
|
|
* <!-- Apps must declare which features they support as metadata. The different categories are
|
|
* defined below. In this example, the MMTEL_FEATURE feature is supported. -->
|
|
* <meta-data android:name="android.telephony.ims.MMTEL_FEATURE" android:value="true" />
|
|
*
|
|
* The features that are currently supported in an ImsService are:
|
|
* - RCS_FEATURE: This ImsService implements the RcsFeature class.
|
|
* - MMTEL_FEATURE: This ImsService implements the MmTelFeature class.
|
|
* - EMERGENCY_MMTEL_FEATURE: This ImsService supports Emergency Calling for MMTEL, must be
|
|
* declared along with the MMTEL_FEATURE. If this is not specified, the framework will use
|
|
* circuit switch for emergency calling.
|
|
*
|
|
* In the dynamic definition, the supported features are not specified in the service definition
|
|
* of the AndroidManifest. Instead, the framework binds to this service and calls
|
|
* {@link #querySupportedImsFeatures()}. The {@link ImsService} then returns an
|
|
* {@link ImsFeatureConfiguration}, which the framework uses to initialize the supported
|
|
* {@link ImsFeature}s. If at any time, the list of supported {@link ImsFeature}s changes,
|
|
* {@link #onUpdateSupportedImsFeatures(ImsFeatureConfiguration)} can be called to tell the
|
|
* framework of the changes.
|
|
*
|
|
* @hide
|
|
*/
|
|
@SystemApi
|
|
public class ImsService extends Service {
|
|
|
|
private static final String LOG_TAG = "ImsService";
|
|
|
|
/**
|
|
* The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService.
|
|
* @hide
|
|
*/
|
|
public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService";
|
|
|
|
// A map of slot Id -> map of features (indexed by ImsFeature feature id) corresponding to that
|
|
// slot.
|
|
// We keep track of this to facilitate cleanup of the IImsFeatureStatusCallback and
|
|
// call ImsFeature#onFeatureRemoved.
|
|
private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();
|
|
|
|
private IImsServiceControllerListener mListener;
|
|
|
|
|
|
/**
|
|
* Listener that notifies the framework of ImsService changes.
|
|
* @hide
|
|
*/
|
|
public static class Listener extends IImsServiceControllerListener.Stub {
|
|
/**
|
|
* The IMS features that this ImsService supports has changed.
|
|
* @param c a new {@link ImsFeatureConfiguration} containing {@link ImsFeature.FeatureType}s
|
|
* that this ImsService supports. This may trigger the addition/removal of feature
|
|
* in this service.
|
|
*/
|
|
public void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) {
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
|
|
@Override
|
|
public void setListener(IImsServiceControllerListener l) {
|
|
mListener = l;
|
|
}
|
|
|
|
@Override
|
|
public IImsMmTelFeature createMmTelFeature(int slotId, IImsFeatureStatusCallback c) {
|
|
return createMmTelFeatureInternal(slotId, c);
|
|
}
|
|
|
|
@Override
|
|
public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) {
|
|
return createRcsFeatureInternal(slotId, c);
|
|
}
|
|
|
|
@Override
|
|
public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c) {
|
|
ImsService.this.removeImsFeature(slotId, featureType, c);
|
|
}
|
|
|
|
@Override
|
|
public ImsFeatureConfiguration querySupportedImsFeatures() {
|
|
return ImsService.this.querySupportedImsFeatures();
|
|
}
|
|
|
|
@Override
|
|
public void notifyImsServiceReadyForFeatureCreation() {
|
|
ImsService.this.readyForFeatureCreation();
|
|
}
|
|
|
|
@Override
|
|
public IImsConfig getConfig(int slotId) {
|
|
ImsConfigImplBase c = ImsService.this.getConfig(slotId);
|
|
return c != null ? c.getIImsConfig() : null;
|
|
}
|
|
|
|
@Override
|
|
public IImsRegistration getRegistration(int slotId) {
|
|
ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
|
|
return r != null ? r.getBinder() : null;
|
|
}
|
|
|
|
@Override
|
|
public void enableIms(int slotId) {
|
|
ImsService.this.enableIms(slotId);
|
|
}
|
|
|
|
@Override
|
|
public void disableIms(int slotId) {
|
|
ImsService.this.disableIms(slotId);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
@Override
|
|
public IBinder onBind(Intent intent) {
|
|
if(SERVICE_INTERFACE.equals(intent.getAction())) {
|
|
Log.i(LOG_TAG, "ImsService Bound.");
|
|
return mImsServiceController;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
@VisibleForTesting
|
|
public SparseArray<ImsFeature> getFeatures(int slotId) {
|
|
return mFeaturesBySlot.get(slotId);
|
|
}
|
|
|
|
private IImsMmTelFeature createMmTelFeatureInternal(int slotId,
|
|
IImsFeatureStatusCallback c) {
|
|
MmTelFeature f = createMmTelFeature(slotId);
|
|
if (f != null) {
|
|
setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL, c);
|
|
return f.getBinder();
|
|
} else {
|
|
Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private IImsRcsFeature createRcsFeatureInternal(int slotId,
|
|
IImsFeatureStatusCallback c) {
|
|
RcsFeature f = createRcsFeature(slotId);
|
|
if (f != null) {
|
|
setupFeature(f, slotId, ImsFeature.FEATURE_RCS, c);
|
|
return f.getBinder();
|
|
} else {
|
|
Log.e(LOG_TAG, "createRcsFeatureInternal: null feature returned.");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private void setupFeature(ImsFeature f, int slotId, int featureType,
|
|
IImsFeatureStatusCallback c) {
|
|
f.initialize(this, slotId);
|
|
f.addImsFeatureStatusCallback(c);
|
|
addImsFeature(slotId, featureType, f);
|
|
}
|
|
|
|
private void addImsFeature(int slotId, int featureType, ImsFeature f) {
|
|
synchronized (mFeaturesBySlot) {
|
|
// Get SparseArray for Features, by querying slot Id
|
|
SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
|
|
if (features == null) {
|
|
// Populate new SparseArray of features if it doesn't exist for this slot yet.
|
|
features = new SparseArray<>();
|
|
mFeaturesBySlot.put(slotId, features);
|
|
}
|
|
features.put(featureType, f);
|
|
}
|
|
}
|
|
|
|
private void removeImsFeature(int slotId, int featureType,
|
|
IImsFeatureStatusCallback c) {
|
|
synchronized (mFeaturesBySlot) {
|
|
// get ImsFeature associated with the slot/feature
|
|
SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
|
|
if (features == null) {
|
|
Log.w(LOG_TAG, "Can not remove ImsFeature. No ImsFeatures exist on slot "
|
|
+ slotId);
|
|
return;
|
|
}
|
|
ImsFeature f = features.get(featureType);
|
|
if (f == null) {
|
|
Log.w(LOG_TAG, "Can not remove ImsFeature. No feature with type "
|
|
+ featureType + " exists on slot " + slotId);
|
|
return;
|
|
}
|
|
f.removeImsFeatureStatusCallback(c);
|
|
f.onFeatureRemoved();
|
|
features.remove(featureType);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* When called, provide the {@link ImsFeatureConfiguration} that this {@link ImsService}
|
|
* currently supports. This will trigger the framework to set up the {@link ImsFeature}s that
|
|
* correspond to the {@link ImsFeature}s configured here.
|
|
*
|
|
* Use {@link #onUpdateSupportedImsFeatures(ImsFeatureConfiguration)} to change the supported
|
|
* {@link ImsFeature}s.
|
|
*
|
|
* @return an {@link ImsFeatureConfiguration} containing Features this ImsService supports.
|
|
*/
|
|
public ImsFeatureConfiguration querySupportedImsFeatures() {
|
|
// Return empty for base implementation
|
|
return new ImsFeatureConfiguration();
|
|
}
|
|
|
|
/**
|
|
* Updates the framework with a new {@link ImsFeatureConfiguration} containing the updated
|
|
* features, that this {@link ImsService} supports. This may trigger the framework to add/remove
|
|
* new ImsFeatures, depending on the configuration.
|
|
*/
|
|
public final void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c)
|
|
throws RemoteException {
|
|
if (mListener == null) {
|
|
throw new IllegalStateException("Framework is not ready");
|
|
}
|
|
mListener.onUpdateSupportedImsFeatures(c);
|
|
}
|
|
|
|
/**
|
|
* The ImsService has been bound and is ready for ImsFeature creation based on the Features that
|
|
* the ImsService has registered for with the framework, either in the manifest or via
|
|
* {@link #querySupportedImsFeatures()}.
|
|
*
|
|
* The ImsService should use this signal instead of onCreate/onBind or similar to perform
|
|
* feature initialization because the framework may bind to this service multiple times to
|
|
* query the ImsService's {@link ImsFeatureConfiguration} via
|
|
* {@link #querySupportedImsFeatures()}before creating features.
|
|
*/
|
|
public void readyForFeatureCreation() {
|
|
}
|
|
|
|
/**
|
|
* The framework has enabled IMS for the slot specified, the ImsService should register for IMS
|
|
* and perform all appropriate initialization to bring up all ImsFeatures.
|
|
*/
|
|
public void enableIms(int slotId) {
|
|
}
|
|
|
|
/**
|
|
* The framework has disabled IMS for the slot specified. The ImsService must deregister for IMS
|
|
* and set capability status to false for all ImsFeatures.
|
|
*/
|
|
public void disableIms(int slotId) {
|
|
}
|
|
|
|
/**
|
|
* When called, the framework is requesting that a new {@link MmTelFeature} is created for the
|
|
* specified slot.
|
|
*
|
|
* @param slotId The slot ID that the MMTEL Feature is being created for.
|
|
* @return The newly created {@link MmTelFeature} associated with the slot or null if the
|
|
* feature is not supported.
|
|
*/
|
|
public MmTelFeature createMmTelFeature(int slotId) {
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* When called, the framework is requesting that a new {@link RcsFeature} is created for the
|
|
* specified slot.
|
|
*
|
|
* @param slotId The slot ID that the RCS Feature is being created for.
|
|
* @return The newly created {@link RcsFeature} associated with the slot or null if the feature
|
|
* is not supported.
|
|
*/
|
|
public RcsFeature createRcsFeature(int slotId) {
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Return the {@link ImsConfigImplBase} implementation associated with the provided slot. This
|
|
* will be used by the platform to get/set specific IMS related configurations.
|
|
*
|
|
* @param slotId The slot that the IMS configuration is associated with.
|
|
* @return ImsConfig implementation that is associated with the specified slot.
|
|
*/
|
|
public ImsConfigImplBase getConfig(int slotId) {
|
|
return new ImsConfigImplBase();
|
|
}
|
|
|
|
/**
|
|
* Return the {@link ImsRegistrationImplBase} implementation associated with the provided slot.
|
|
*
|
|
* @param slotId The slot that is associated with the IMS Registration.
|
|
* @return the ImsRegistration implementation associated with the slot.
|
|
*/
|
|
public ImsRegistrationImplBase getRegistration(int slotId) {
|
|
return new ImsRegistrationImplBase();
|
|
}
|
|
} |