Home | History | Annotate | Download | only in compat
      1 /*
      2  * Copyright (C) 2018 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.compat;
     18 
     19 import android.annotation.Nullable;
     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.compat.feature.ImsFeature;
     26 import android.telephony.ims.compat.feature.MMTelFeature;
     27 import android.telephony.ims.compat.feature.RcsFeature;
     28 import android.util.Log;
     29 import android.util.SparseArray;
     30 
     31 import com.android.ims.internal.IImsFeatureStatusCallback;
     32 import com.android.ims.internal.IImsMMTelFeature;
     33 import com.android.ims.internal.IImsRcsFeature;
     34 import com.android.ims.internal.IImsServiceController;
     35 import com.android.internal.annotations.VisibleForTesting;
     36 
     37 /**
     38  * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
     39  * ImsService must register the service in their AndroidManifest to be detected by the framework.
     40  * First, the application must declare that they use the "android.permission.BIND_IMS_SERVICE"
     41  * permission. Then, the ImsService definition in the manifest must follow the following format:
     42  *
     43  * ...
     44  * <service android:name=".EgImsService"
     45  *     android:permission="android.permission.BIND_IMS_SERVICE" >
     46  *     <!-- Apps must declare which features they support as metadata. The different categories are
     47  *     defined below. In this example, the RCS_FEATURE feature is supported. -->
     48  *     <meta-data android:name="android.telephony.ims.RCS_FEATURE" android:value="true" />
     49  *     <intent-filter>
     50  *         <action android:name="android.telephony.ims.compat.ImsService" />
     51  *     </intent-filter>
     52  * </service>
     53  * ...
     54  *
     55  * The telephony framework will then bind to the ImsService you have defined in your manifest
     56  * if you are either:
     57  * 1) Defined as the default ImsService for the device in the device overlay using
     58  *    "config_ims_package".
     59  * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using
     60  *    {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}.
     61  *
     62  * The features that are currently supported in an ImsService are:
     63  * - RCS_FEATURE: This ImsService implements the RcsFeature class.
     64  * - MMTEL_FEATURE: This ImsService implements the MMTelFeature class.
     65  * - EMERGENCY_MMTEL_FEATURE: This ImsService implements the MMTelFeature class and will be
     66  *   available to place emergency calls at all times. This MUST be implemented by the default
     67  *   ImsService provided in the device overlay.
     68  *   @hide
     69  */
     70 public class ImsService extends Service {
     71 
     72     private static final String LOG_TAG = "ImsService(Compat)";
     73 
     74     /**
     75      * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService.
     76      * @hide
     77      */
     78     public static final String SERVICE_INTERFACE = "android.telephony.ims.compat.ImsService";
     79 
     80     // A map of slot Id -> map of features (indexed by ImsFeature feature id) corresponding to that
     81     // slot.
     82     // We keep track of this to facilitate cleanup of the IImsFeatureStatusCallback and
     83     // call ImsFeature#onFeatureRemoved.
     84     private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();
     85 
     86     /**
     87      * @hide
     88      */
     89     protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
     90 
     91         @Override
     92         public IImsMMTelFeature createEmergencyMMTelFeature(int slotId,
     93                 IImsFeatureStatusCallback c) {
     94             return createEmergencyMMTelFeatureInternal(slotId, c);
     95         }
     96 
     97         @Override
     98         public IImsMMTelFeature createMMTelFeature(int slotId, IImsFeatureStatusCallback c) {
     99             return createMMTelFeatureInternal(slotId, c);
    100         }
    101 
    102         @Override
    103         public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) {
    104             return createRcsFeatureInternal(slotId, c);
    105         }
    106 
    107         @Override
    108         public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c)
    109                 throws RemoteException {
    110             ImsService.this.removeImsFeature(slotId, featureType, c);
    111         }
    112     };
    113 
    114     /**
    115      * @hide
    116      */
    117     @Override
    118     public IBinder onBind(Intent intent) {
    119         if(SERVICE_INTERFACE.equals(intent.getAction())) {
    120             Log.i(LOG_TAG, "ImsService(Compat) Bound.");
    121             return mImsServiceController;
    122         }
    123         return null;
    124     }
    125 
    126     /**
    127      * @hide
    128      */
    129     @VisibleForTesting
    130     public SparseArray<ImsFeature> getFeatures(int slotId) {
    131         return mFeaturesBySlot.get(slotId);
    132     }
    133 
    134     private IImsMMTelFeature createEmergencyMMTelFeatureInternal(int slotId,
    135             IImsFeatureStatusCallback c) {
    136         MMTelFeature f = onCreateEmergencyMMTelImsFeature(slotId);
    137         if (f != null) {
    138             setupFeature(f, slotId, ImsFeature.EMERGENCY_MMTEL, c);
    139             return f.getBinder();
    140         } else {
    141             return null;
    142         }
    143     }
    144 
    145     private IImsMMTelFeature createMMTelFeatureInternal(int slotId,
    146             IImsFeatureStatusCallback c) {
    147         MMTelFeature f = onCreateMMTelImsFeature(slotId);
    148         if (f != null) {
    149             setupFeature(f, slotId, ImsFeature.MMTEL, c);
    150             return f.getBinder();
    151         } else {
    152             return null;
    153         }
    154     }
    155 
    156     private IImsRcsFeature createRcsFeatureInternal(int slotId,
    157             IImsFeatureStatusCallback c) {
    158         RcsFeature f = onCreateRcsFeature(slotId);
    159         if (f != null) {
    160             setupFeature(f, slotId, ImsFeature.RCS, c);
    161             return f.getBinder();
    162         } else {
    163             return null;
    164         }
    165     }
    166 
    167     private void setupFeature(ImsFeature f, int slotId, int featureType,
    168             IImsFeatureStatusCallback c) {
    169         f.setContext(this);
    170         f.setSlotId(slotId);
    171         f.addImsFeatureStatusCallback(c);
    172         addImsFeature(slotId, featureType, f);
    173         // TODO: Remove once new onFeatureReady AIDL is merged in.
    174         f.onFeatureReady();
    175     }
    176 
    177     private void addImsFeature(int slotId, int featureType, ImsFeature f) {
    178         synchronized (mFeaturesBySlot) {
    179             // Get SparseArray for Features, by querying slot Id
    180             SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
    181             if (features == null) {
    182                 // Populate new SparseArray of features if it doesn't exist for this slot yet.
    183                 features = new SparseArray<>();
    184                 mFeaturesBySlot.put(slotId, features);
    185             }
    186             features.put(featureType, f);
    187         }
    188     }
    189 
    190     private void removeImsFeature(int slotId, int featureType,
    191             IImsFeatureStatusCallback c) {
    192         synchronized (mFeaturesBySlot) {
    193             // get ImsFeature associated with the slot/feature
    194             SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
    195             if (features == null) {
    196                 Log.w(LOG_TAG, "Can not remove ImsFeature. No ImsFeatures exist on slot "
    197                         + slotId);
    198                 return;
    199             }
    200             ImsFeature f = features.get(featureType);
    201             if (f == null) {
    202                 Log.w(LOG_TAG, "Can not remove ImsFeature. No feature with type "
    203                         + featureType + " exists on slot " + slotId);
    204                 return;
    205             }
    206             f.removeImsFeatureStatusCallback(c);
    207             f.onFeatureRemoved();
    208             features.remove(featureType);
    209         }
    210     }
    211 
    212     /**
    213      * @return An implementation of MMTelFeature that will be used by the system for MMTel
    214      * functionality. Must be able to handle emergency calls at any time as well.
    215      * @hide
    216      */
    217     public @Nullable MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId) {
    218         return null;
    219     }
    220 
    221     /**
    222      * @return An implementation of MMTelFeature that will be used by the system for MMTel
    223      * functionality.
    224      * @hide
    225      */
    226     public @Nullable MMTelFeature onCreateMMTelImsFeature(int slotId) {
    227         return null;
    228     }
    229 
    230     /**
    231      * @return An implementation of RcsFeature that will be used by the system for RCS.
    232      * @hide
    233      */
    234     public @Nullable RcsFeature onCreateRcsFeature(int slotId) {
    235         return null;
    236     }
    237 }
    238