Home | History | Annotate | Download | only in ims
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package android.telephony.ims;
     18 
     19 import android.annotation.SystemApi;
     20 import android.app.Service;
     21 import android.content.Intent;
     22 import android.os.IBinder;
     23 import android.os.RemoteException;
     24 import android.telephony.CarrierConfigManager;
     25 import android.telephony.ims.aidl.IImsConfig;
     26 import android.telephony.ims.aidl.IImsMmTelFeature;
     27 import android.telephony.ims.aidl.IImsRcsFeature;
     28 import android.telephony.ims.aidl.IImsRegistration;
     29 import android.telephony.ims.aidl.IImsServiceController;
     30 import android.telephony.ims.aidl.IImsServiceControllerListener;
     31 import android.telephony.ims.feature.ImsFeature;
     32 import android.telephony.ims.feature.MmTelFeature;
     33 import android.telephony.ims.feature.RcsFeature;
     34 import android.telephony.ims.stub.ImsConfigImplBase;
     35 import android.telephony.ims.stub.ImsFeatureConfiguration;
     36 import android.telephony.ims.stub.ImsRegistrationImplBase;
     37 import android.util.Log;
     38 import android.util.SparseArray;
     39 
     40 import com.android.ims.internal.IImsFeatureStatusCallback;
     41 import com.android.internal.annotations.VisibleForTesting;
     42 
     43 import static android.Manifest.permission.MODIFY_PHONE_STATE;
     44 
     45 /**
     46  * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
     47  * ImsService must register the service in their AndroidManifest to be detected by the framework.
     48  * First, the application must declare that they use the "android.permission.BIND_IMS_SERVICE"
     49  * permission. Then, the ImsService definition in the manifest must follow the following format:
     50  *
     51  * ...
     52  * <service android:name=".EgImsService"
     53  *     android:permission="android.permission.BIND_IMS_SERVICE" >
     54  *     ...
     55  *     <intent-filter>
     56  *         <action android:name="android.telephony.ims.ImsService" />
     57  *     </intent-filter>
     58  * </service>
     59  * ...
     60  *
     61  * The telephony framework will then bind to the ImsService you have defined in your manifest
     62  * if you are either:
     63  * 1) Defined as the default ImsService for the device in the device overlay using
     64  *    "config_ims_package".
     65  * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using
     66  *    {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}.
     67  *
     68  * There are two ways to define to the platform which {@link ImsFeature}s this {@link ImsService}
     69  * supports, dynamic or static definitions.
     70  *
     71  * In the static definition, the {@link ImsFeature}s that are supported are defined in the service
     72  * definition of the AndroidManifest.xml file as metadata:
     73  * <!-- Apps must declare which features they support as metadata. The different categories are
     74  *      defined below. In this example, the MMTEL_FEATURE feature is supported. -->
     75  * <meta-data android:name="android.telephony.ims.MMTEL_FEATURE" android:value="true" />
     76  *
     77  * The features that are currently supported in an ImsService are:
     78  * - RCS_FEATURE: This ImsService implements the RcsFeature class.
     79  * - MMTEL_FEATURE: This ImsService implements the MmTelFeature class.
     80  * - EMERGENCY_MMTEL_FEATURE: This ImsService supports Emergency Calling for MMTEL, must be
     81  *   declared along with the MMTEL_FEATURE. If this is not specified, the framework will use
     82  *   circuit switch for emergency calling.
     83  *
     84  * In the dynamic definition, the supported features are not specified in the service definition
     85  * of the AndroidManifest. Instead, the framework binds to this service and calls
     86  * {@link #querySupportedImsFeatures()}. The {@link ImsService} then returns an
     87  * {@link ImsFeatureConfiguration}, which the framework uses to initialize the supported
     88  * {@link ImsFeature}s. If at any time, the list of supported {@link ImsFeature}s changes,
     89  * {@link #onUpdateSupportedImsFeatures(ImsFeatureConfiguration)} can be called to tell the
     90  * framework of the changes.
     91  *
     92  * @hide
     93  */
     94 @SystemApi
     95 public class ImsService extends Service {
     96 
     97     private static final String LOG_TAG = "ImsService";
     98 
     99     /**
    100      * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService.
    101      * @hide
    102      */
    103     public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService";
    104 
    105     // A map of slot Id -> map of features (indexed by ImsFeature feature id) corresponding to that
    106     // slot.
    107     // We keep track of this to facilitate cleanup of the IImsFeatureStatusCallback and
    108     // call ImsFeature#onFeatureRemoved.
    109     private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();
    110 
    111     private IImsServiceControllerListener mListener;
    112 
    113 
    114     /**
    115      * Listener that notifies the framework of ImsService changes.
    116      * @hide
    117      */
    118     public static class Listener extends IImsServiceControllerListener.Stub {
    119         /**
    120          * The IMS features that this ImsService supports has changed.
    121          * @param c a new {@link ImsFeatureConfiguration} containing {@link ImsFeature.FeatureType}s
    122          *   that this ImsService supports. This may trigger the addition/removal of feature
    123          *   in this service.
    124          */
    125         public void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) {
    126         }
    127     }
    128 
    129     /**
    130      * @hide
    131      */
    132     protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
    133         @Override
    134         public void setListener(IImsServiceControllerListener l) {
    135             mListener = l;
    136         }
    137 
    138         @Override
    139         public IImsMmTelFeature createMmTelFeature(int slotId, IImsFeatureStatusCallback c) {
    140             return createMmTelFeatureInternal(slotId, c);
    141         }
    142 
    143         @Override
    144         public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) {
    145             return createRcsFeatureInternal(slotId, c);
    146         }
    147 
    148         @Override
    149         public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c) {
    150             ImsService.this.removeImsFeature(slotId, featureType, c);
    151         }
    152 
    153         @Override
    154         public ImsFeatureConfiguration querySupportedImsFeatures() {
    155             return ImsService.this.querySupportedImsFeatures();
    156         }
    157 
    158         @Override
    159         public void notifyImsServiceReadyForFeatureCreation() {
    160             ImsService.this.readyForFeatureCreation();
    161         }
    162 
    163         @Override
    164         public IImsConfig getConfig(int slotId) {
    165             ImsConfigImplBase c = ImsService.this.getConfig(slotId);
    166             return c != null ? c.getIImsConfig() : null;
    167         }
    168 
    169         @Override
    170         public IImsRegistration getRegistration(int slotId) {
    171             ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
    172             return r != null ? r.getBinder() : null;
    173         }
    174 
    175         @Override
    176         public void enableIms(int slotId) {
    177             ImsService.this.enableIms(slotId);
    178         }
    179 
    180         @Override
    181         public void disableIms(int slotId) {
    182             ImsService.this.disableIms(slotId);
    183         }
    184     };
    185 
    186     /**
    187      * @hide
    188      */
    189     @Override
    190     public IBinder onBind(Intent intent) {
    191         if(SERVICE_INTERFACE.equals(intent.getAction())) {
    192             Log.i(LOG_TAG, "ImsService Bound.");
    193             return mImsServiceController;
    194         }
    195         return null;
    196     }
    197 
    198     /**
    199      * @hide
    200      */
    201     @VisibleForTesting
    202     public SparseArray<ImsFeature> getFeatures(int slotId) {
    203         return mFeaturesBySlot.get(slotId);
    204     }
    205 
    206     private IImsMmTelFeature createMmTelFeatureInternal(int slotId,
    207             IImsFeatureStatusCallback c) {
    208         MmTelFeature f = createMmTelFeature(slotId);
    209         if (f != null) {
    210             setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL, c);
    211             return f.getBinder();
    212         } else {
    213             Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
    214             return null;
    215         }
    216     }
    217 
    218     private IImsRcsFeature createRcsFeatureInternal(int slotId,
    219             IImsFeatureStatusCallback c) {
    220         RcsFeature f = createRcsFeature(slotId);
    221         if (f != null) {
    222             setupFeature(f, slotId, ImsFeature.FEATURE_RCS, c);
    223             return f.getBinder();
    224         } else {
    225             Log.e(LOG_TAG, "createRcsFeatureInternal: null feature returned.");
    226             return null;
    227         }
    228     }
    229 
    230     private void setupFeature(ImsFeature f, int slotId, int featureType,
    231             IImsFeatureStatusCallback c) {
    232         f.addImsFeatureStatusCallback(c);
    233         f.initialize(this, slotId);
    234         addImsFeature(slotId, featureType, f);
    235     }
    236 
    237     private void addImsFeature(int slotId, int featureType, ImsFeature f) {
    238         synchronized (mFeaturesBySlot) {
    239             // Get SparseArray for Features, by querying slot Id
    240             SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
    241             if (features == null) {
    242                 // Populate new SparseArray of features if it doesn't exist for this slot yet.
    243                 features = new SparseArray<>();
    244                 mFeaturesBySlot.put(slotId, features);
    245             }
    246             features.put(featureType, f);
    247         }
    248     }
    249 
    250     private void removeImsFeature(int slotId, int featureType,
    251             IImsFeatureStatusCallback c) {
    252         synchronized (mFeaturesBySlot) {
    253             // get ImsFeature associated with the slot/feature
    254             SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
    255             if (features == null) {
    256                 Log.w(LOG_TAG, "Can not remove ImsFeature. No ImsFeatures exist on slot "
    257                         + slotId);
    258                 return;
    259             }
    260             ImsFeature f = features.get(featureType);
    261             if (f == null) {
    262                 Log.w(LOG_TAG, "Can not remove ImsFeature. No feature with type "
    263                         + featureType + " exists on slot " + slotId);
    264                 return;
    265             }
    266             f.removeImsFeatureStatusCallback(c);
    267             f.onFeatureRemoved();
    268             features.remove(featureType);
    269         }
    270     }
    271 
    272     /**
    273      * When called, provide the {@link ImsFeatureConfiguration} that this {@link ImsService}
    274      * currently supports. This will trigger the framework to set up the {@link ImsFeature}s that
    275      * correspond to the {@link ImsFeature}s configured here.
    276      *
    277      * Use {@link #onUpdateSupportedImsFeatures(ImsFeatureConfiguration)} to change the supported
    278      * {@link ImsFeature}s.
    279      *
    280      * @return an {@link ImsFeatureConfiguration} containing Features this ImsService supports.
    281      */
    282     public ImsFeatureConfiguration querySupportedImsFeatures() {
    283         // Return empty for base implementation
    284         return new ImsFeatureConfiguration();
    285     }
    286 
    287     /**
    288      * Updates the framework with a new {@link ImsFeatureConfiguration} containing the updated
    289      * features, that this {@link ImsService} supports. This may trigger the framework to add/remove
    290      * new ImsFeatures, depending on the configuration.
    291      */
    292     public final void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c)
    293             throws RemoteException {
    294         if (mListener == null) {
    295             throw new IllegalStateException("Framework is not ready");
    296         }
    297         mListener.onUpdateSupportedImsFeatures(c);
    298     }
    299 
    300     /**
    301      * The ImsService has been bound and is ready for ImsFeature creation based on the Features that
    302      * the ImsService has registered for with the framework, either in the manifest or via
    303      * {@link #querySupportedImsFeatures()}.
    304      *
    305      * The ImsService should use this signal instead of onCreate/onBind or similar to perform
    306      * feature initialization because the framework may bind to this service multiple times to
    307      * query the ImsService's {@link ImsFeatureConfiguration} via
    308      * {@link #querySupportedImsFeatures()}before creating features.
    309      */
    310     public void readyForFeatureCreation() {
    311     }
    312 
    313     /**
    314      * The framework has enabled IMS for the slot specified, the ImsService should register for IMS
    315      * and perform all appropriate initialization to bring up all ImsFeatures.
    316      */
    317     public void enableIms(int slotId) {
    318     }
    319 
    320     /**
    321      * The framework has disabled IMS for the slot specified. The ImsService must deregister for IMS
    322      * and set capability status to false for all ImsFeatures.
    323      */
    324     public void disableIms(int slotId) {
    325     }
    326 
    327     /**
    328      * When called, the framework is requesting that a new {@link MmTelFeature} is created for the
    329      * specified slot.
    330      *
    331      * @param slotId The slot ID that the MMTEL Feature is being created for.
    332      * @return The newly created {@link MmTelFeature} associated with the slot or null if the
    333      * feature is not supported.
    334      */
    335     public MmTelFeature createMmTelFeature(int slotId) {
    336         return null;
    337     }
    338 
    339     /**
    340      * When called, the framework is requesting that a new {@link RcsFeature} is created for the
    341      * specified slot.
    342      *
    343      * @param slotId The slot ID that the RCS Feature is being created for.
    344      * @return The newly created {@link RcsFeature} associated with the slot or null if the feature
    345      * is not supported.
    346      */
    347     public RcsFeature createRcsFeature(int slotId) {
    348         return null;
    349     }
    350 
    351     /**
    352      * Return the {@link ImsConfigImplBase} implementation associated with the provided slot. This
    353      * will be used by the platform to get/set specific IMS related configurations.
    354      *
    355      * @param slotId The slot that the IMS configuration is associated with.
    356      * @return ImsConfig implementation that is associated with the specified slot.
    357      */
    358     public ImsConfigImplBase getConfig(int slotId) {
    359         return new ImsConfigImplBase();
    360     }
    361 
    362     /**
    363      * Return the {@link ImsRegistrationImplBase} implementation associated with the provided slot.
    364      *
    365      * @param slotId The slot that is associated with the IMS Registration.
    366      * @return the ImsRegistration implementation associated with the slot.
    367      */
    368     public ImsRegistrationImplBase getRegistration(int slotId) {
    369         return new ImsRegistrationImplBase();
    370     }
    371 }