Home | History | Annotate | Download | only in stub
      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.stub;
     18 
     19 import android.annotation.IntDef;
     20 import android.annotation.SystemApi;
     21 import android.net.Uri;
     22 import android.os.RemoteCallbackList;
     23 import android.os.RemoteException;
     24 import android.telephony.ims.aidl.IImsRegistration;
     25 import android.telephony.ims.aidl.IImsRegistrationCallback;
     26 import android.util.Log;
     27 
     28 import android.telephony.ims.ImsReasonInfo;
     29 
     30 import com.android.internal.annotations.VisibleForTesting;
     31 
     32 import java.lang.annotation.Retention;
     33 import java.lang.annotation.RetentionPolicy;
     34 
     35 /**
     36  * Controls IMS registration for this ImsService and notifies the framework when the IMS
     37  * registration for this ImsService has changed status.
     38  * @hide
     39  */
     40 @SystemApi
     41 public class ImsRegistrationImplBase {
     42 
     43     private static final String LOG_TAG = "ImsRegistrationImplBase";
     44 
     45     /**
     46      * @hide
     47      */
     48     // Defines the underlying radio technology type that we have registered for IMS over.
     49     @IntDef(flag = true,
     50             value = {
     51                     REGISTRATION_TECH_NONE,
     52                     REGISTRATION_TECH_LTE,
     53                     REGISTRATION_TECH_IWLAN
     54             })
     55     @Retention(RetentionPolicy.SOURCE)
     56     public @interface ImsRegistrationTech {}
     57     /**
     58      * No registration technology specified, used when we are not registered.
     59      */
     60     public static final int REGISTRATION_TECH_NONE = -1;
     61     /**
     62      * IMS is registered to IMS via LTE.
     63      */
     64     public static final int REGISTRATION_TECH_LTE = 0;
     65     /**
     66      * IMS is registered to IMS via IWLAN.
     67      */
     68     public static final int REGISTRATION_TECH_IWLAN = 1;
     69 
     70     // Registration states, used to notify new ImsRegistrationImplBase#Callbacks of the current
     71     // state.
     72     // The unknown state is set as the initialization state. This is so that we do not call back
     73     // with NOT_REGISTERED in the case where the ImsService has not updated the registration state
     74     // yet.
     75     private static final int REGISTRATION_STATE_UNKNOWN = -1;
     76     private static final int REGISTRATION_STATE_NOT_REGISTERED = 0;
     77     private static final int REGISTRATION_STATE_REGISTERING = 1;
     78     private static final int REGISTRATION_STATE_REGISTERED = 2;
     79 
     80     /**
     81      * Callback class for receiving Registration callback events.
     82      * @hide
     83      */
     84     public static class Callback {
     85         /**
     86          * Notifies the framework when the IMS Provider is connected to the IMS network.
     87          *
     88          * @param imsRadioTech the radio access technology. Valid values are defined in
     89          * {@link ImsRegistrationTech}.
     90          */
     91         public void onRegistered(@ImsRegistrationTech int imsRadioTech) {
     92         }
     93 
     94         /**
     95          * Notifies the framework when the IMS Provider is trying to connect the IMS network.
     96          *
     97          * @param imsRadioTech the radio access technology. Valid values are defined in
     98          * {@link ImsRegistrationTech}.
     99          */
    100         public void onRegistering(@ImsRegistrationTech int imsRadioTech) {
    101         }
    102 
    103         /**
    104          * Notifies the framework when the IMS Provider is disconnected from the IMS network.
    105          *
    106          * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
    107          */
    108         public void onDeregistered(ImsReasonInfo info) {
    109         }
    110 
    111         /**
    112          * A failure has occurred when trying to handover registration to another technology type,
    113          * defined in {@link ImsRegistrationTech}
    114          *
    115          * @param imsRadioTech The {@link ImsRegistrationTech} type that has failed
    116          * @param info A {@link ImsReasonInfo} that identifies the reason for failure.
    117          */
    118         public void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech,
    119                 ImsReasonInfo info) {
    120         }
    121 
    122         /**
    123          * Returns a list of subscriber {@link Uri}s associated with this IMS subscription when
    124          * it changes.
    125          * @param uris new array of subscriber {@link Uri}s that are associated with this IMS
    126          *         subscription.
    127          */
    128         public void onSubscriberAssociatedUriChanged(Uri[] uris) {
    129 
    130         }
    131     }
    132 
    133     private final IImsRegistration mBinder = new IImsRegistration.Stub() {
    134 
    135         @Override
    136         public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException {
    137             return getConnectionType();
    138         }
    139 
    140         @Override
    141         public void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
    142             ImsRegistrationImplBase.this.addRegistrationCallback(c);
    143         }
    144 
    145         @Override
    146         public void removeRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
    147             ImsRegistrationImplBase.this.removeRegistrationCallback(c);
    148         }
    149     };
    150 
    151     private final RemoteCallbackList<IImsRegistrationCallback> mCallbacks
    152             = new RemoteCallbackList<>();
    153     private final Object mLock = new Object();
    154     // Locked on mLock
    155     private @ImsRegistrationTech
    156     int mConnectionType = REGISTRATION_TECH_NONE;
    157     // Locked on mLock
    158     private int mRegistrationState = REGISTRATION_STATE_UNKNOWN;
    159     // Locked on mLock, create unspecified disconnect cause.
    160     private ImsReasonInfo mLastDisconnectCause = new ImsReasonInfo();
    161 
    162     /**
    163      * @hide
    164      */
    165     public final IImsRegistration getBinder() {
    166         return mBinder;
    167     }
    168 
    169     private void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
    170         mCallbacks.register(c);
    171         updateNewCallbackWithState(c);
    172     }
    173 
    174     private void removeRegistrationCallback(IImsRegistrationCallback c) {
    175         mCallbacks.unregister(c);
    176     }
    177 
    178     /**
    179      * Notify the framework that the device is connected to the IMS network.
    180      *
    181      * @param imsRadioTech the radio access technology. Valid values are defined as
    182      * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
    183      */
    184     public final void onRegistered(@ImsRegistrationTech int imsRadioTech) {
    185         updateToState(imsRadioTech, REGISTRATION_STATE_REGISTERED);
    186         mCallbacks.broadcast((c) -> {
    187             try {
    188                 c.onRegistered(imsRadioTech);
    189             } catch (RemoteException e) {
    190                 Log.w(LOG_TAG, e + " " + "onRegistrationConnected() - Skipping " +
    191                         "callback.");
    192             }
    193         });
    194     }
    195 
    196     /**
    197      * Notify the framework that the device is trying to connect the IMS network.
    198      *
    199      * @param imsRadioTech the radio access technology. Valid values are defined as
    200      * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
    201      */
    202     public final void onRegistering(@ImsRegistrationTech int imsRadioTech) {
    203         updateToState(imsRadioTech, REGISTRATION_STATE_REGISTERING);
    204         mCallbacks.broadcast((c) -> {
    205             try {
    206                 c.onRegistering(imsRadioTech);
    207             } catch (RemoteException e) {
    208                 Log.w(LOG_TAG, e + " " + "onRegistrationProcessing() - Skipping " +
    209                         "callback.");
    210             }
    211         });
    212     }
    213 
    214     /**
    215      * Notify the framework that the device is disconnected from the IMS network.
    216      * <p>
    217      * Note: Prior to calling {@link #onDeregistered(ImsReasonInfo)}, you should ensure that any
    218      * changes to {@link android.telephony.ims.feature.ImsFeature} capability availability is sent
    219      * to the framework.  For example,
    220      * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}
    221      * and
    222      * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}
    223      * may be set to unavailable to ensure the framework knows these services are no longer
    224      * available due to de-registration.  If you do not report capability changes impacted by
    225      * de-registration, the framework will not know which features are no longer available as a
    226      * result.
    227      *
    228      * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
    229      */
    230     public final void onDeregistered(ImsReasonInfo info) {
    231         updateToDisconnectedState(info);
    232         mCallbacks.broadcast((c) -> {
    233             try {
    234                 c.onDeregistered(info);
    235             } catch (RemoteException e) {
    236                 Log.w(LOG_TAG, e + " " + "onRegistrationDisconnected() - Skipping " +
    237                         "callback.");
    238             }
    239         });
    240     }
    241 
    242     /**
    243      * Notify the framework that the handover from the current radio technology to the technology
    244      * defined in {@code imsRadioTech} has failed.
    245      * @param imsRadioTech The technology that has failed to be changed. Valid values are
    246      * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
    247      * @param info The {@link ImsReasonInfo} for the failure to change technology.
    248      */
    249     public final void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech,
    250             ImsReasonInfo info) {
    251         mCallbacks.broadcast((c) -> {
    252             try {
    253                 c.onTechnologyChangeFailed(imsRadioTech, info);
    254             } catch (RemoteException e) {
    255                 Log.w(LOG_TAG, e + " " + "onRegistrationChangeFailed() - Skipping " +
    256                         "callback.");
    257             }
    258         });
    259     }
    260 
    261     /**
    262      * The this device's subscriber associated {@link Uri}s have changed, which are used to filter
    263      * out this device's {@link Uri}s during conference calling.
    264      * @param uris
    265      */
    266     public final void onSubscriberAssociatedUriChanged(Uri[] uris) {
    267         mCallbacks.broadcast((c) -> {
    268             try {
    269                 c.onSubscriberAssociatedUriChanged(uris);
    270             } catch (RemoteException e) {
    271                 Log.w(LOG_TAG, e + " " + "onSubscriberAssociatedUriChanged() - Skipping " +
    272                         "callback.");
    273             }
    274         });
    275     }
    276 
    277     private void updateToState(@ImsRegistrationTech int connType, int newState) {
    278         synchronized (mLock) {
    279             mConnectionType = connType;
    280             mRegistrationState = newState;
    281             mLastDisconnectCause = null;
    282         }
    283     }
    284 
    285     private void updateToDisconnectedState(ImsReasonInfo info) {
    286         synchronized (mLock) {
    287             updateToState(REGISTRATION_TECH_NONE, REGISTRATION_STATE_NOT_REGISTERED);
    288             if (info != null) {
    289                 mLastDisconnectCause = info;
    290             } else {
    291                 Log.w(LOG_TAG, "updateToDisconnectedState: no ImsReasonInfo provided.");
    292                 mLastDisconnectCause = new ImsReasonInfo();
    293             }
    294         }
    295     }
    296 
    297     /**
    298      * @return the current registration connection type. Valid values are
    299      * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}
    300      * @hide
    301      */
    302     @VisibleForTesting
    303     public final @ImsRegistrationTech int getConnectionType() {
    304         synchronized (mLock) {
    305             return mConnectionType;
    306         }
    307     }
    308 
    309     /**
    310      * @param c the newly registered callback that will be updated with the current registration
    311      *         state.
    312      */
    313     private void updateNewCallbackWithState(IImsRegistrationCallback c) throws RemoteException {
    314         int state;
    315         ImsReasonInfo disconnectInfo;
    316         synchronized (mLock) {
    317             state = mRegistrationState;
    318             disconnectInfo = mLastDisconnectCause;
    319         }
    320         switch (state) {
    321             case REGISTRATION_STATE_NOT_REGISTERED: {
    322                 c.onDeregistered(disconnectInfo);
    323                 break;
    324             }
    325             case REGISTRATION_STATE_REGISTERING: {
    326                 c.onRegistering(getConnectionType());
    327                 break;
    328             }
    329             case REGISTRATION_STATE_REGISTERED: {
    330                 c.onRegistered(getConnectionType());
    331                 break;
    332             }
    333             case REGISTRATION_STATE_UNKNOWN: {
    334                 // Do not callback if the state has not been updated yet by the ImsService.
    335                 break;
    336             }
    337         }
    338     }
    339 }
    340