Home | History | Annotate | Download | only in feature
      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.feature;
     18 
     19 import android.annotation.IntDef;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.os.IInterface;
     23 import android.os.RemoteException;
     24 import android.telephony.SubscriptionManager;
     25 import android.util.Log;
     26 
     27 import com.android.ims.internal.IImsFeatureStatusCallback;
     28 
     29 import java.lang.annotation.Retention;
     30 import java.lang.annotation.RetentionPolicy;
     31 import java.util.Collections;
     32 import java.util.Iterator;
     33 import java.util.Set;
     34 import java.util.WeakHashMap;
     35 
     36 /**
     37  * Base class for all IMS features that are supported by the framework.
     38  * @hide
     39  */
     40 public abstract class ImsFeature {
     41 
     42     private static final String LOG_TAG = "ImsFeature";
     43 
     44     /**
     45      * Action to broadcast when ImsService is up.
     46      * Internal use only.
     47      * Only defined here separately compatibility purposes with the old ImsService.
     48      * @hide
     49      */
     50     public static final String ACTION_IMS_SERVICE_UP =
     51             "com.android.ims.IMS_SERVICE_UP";
     52 
     53     /**
     54      * Action to broadcast when ImsService is down.
     55      * Internal use only.
     56      * Only defined here separately for compatibility purposes with the old ImsService.
     57      * @hide
     58      */
     59     public static final String ACTION_IMS_SERVICE_DOWN =
     60             "com.android.ims.IMS_SERVICE_DOWN";
     61 
     62     /**
     63      * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
     64      * A long value; the phone ID corresponding to the IMS service coming up or down.
     65      * Only defined here separately for compatibility purposes with the old ImsService.
     66      * @hide
     67      */
     68     public static final String EXTRA_PHONE_ID = "android:phone_id";
     69 
     70     // Invalid feature value
     71     public static final int INVALID = -1;
     72     // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
     73     // defined values in ImsServiceClass for compatibility purposes.
     74     public static final int EMERGENCY_MMTEL = 0;
     75     public static final int MMTEL = 1;
     76     public static final int RCS = 2;
     77     // Total number of features defined
     78     public static final int MAX = 3;
     79 
     80     // Integer values defining the state of the ImsFeature at any time.
     81     @IntDef(flag = true,
     82             value = {
     83                     STATE_NOT_AVAILABLE,
     84                     STATE_INITIALIZING,
     85                     STATE_READY,
     86             })
     87     @Retention(RetentionPolicy.SOURCE)
     88     public @interface ImsState {}
     89     public static final int STATE_NOT_AVAILABLE = 0;
     90     public static final int STATE_INITIALIZING = 1;
     91     public static final int STATE_READY = 2;
     92 
     93     private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap(
     94             new WeakHashMap<IImsFeatureStatusCallback, Boolean>());
     95     private @ImsState int mState = STATE_NOT_AVAILABLE;
     96     private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
     97     protected Context mContext;
     98 
     99     public void setContext(Context context) {
    100         mContext = context;
    101     }
    102 
    103     public void setSlotId(int slotId) {
    104         mSlotId = slotId;
    105     }
    106 
    107     public int getFeatureState() {
    108         return mState;
    109     }
    110 
    111     protected final void setFeatureState(@ImsState int state) {
    112         if (mState != state) {
    113             mState = state;
    114             notifyFeatureState(state);
    115         }
    116     }
    117 
    118     public void addImsFeatureStatusCallback(IImsFeatureStatusCallback c) {
    119         if (c == null) {
    120             return;
    121         }
    122         try {
    123             // If we have just connected, send queued status.
    124             c.notifyImsFeatureStatus(mState);
    125             // Add the callback if the callback completes successfully without a RemoteException.
    126             synchronized (mStatusCallbacks) {
    127                 mStatusCallbacks.add(c);
    128             }
    129         } catch (RemoteException e) {
    130             Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
    131         }
    132     }
    133 
    134     public void removeImsFeatureStatusCallback(IImsFeatureStatusCallback c) {
    135         if (c == null) {
    136             return;
    137         }
    138         synchronized (mStatusCallbacks) {
    139             mStatusCallbacks.remove(c);
    140         }
    141     }
    142 
    143     /**
    144      * Internal method called by ImsFeature when setFeatureState has changed.
    145      * @param state
    146      */
    147     private void notifyFeatureState(@ImsState int state) {
    148         synchronized (mStatusCallbacks) {
    149             for (Iterator<IImsFeatureStatusCallback> iter = mStatusCallbacks.iterator();
    150                  iter.hasNext(); ) {
    151                 IImsFeatureStatusCallback callback = iter.next();
    152                 try {
    153                     Log.i(LOG_TAG, "notifying ImsFeatureState=" + state);
    154                     callback.notifyImsFeatureStatus(state);
    155                 } catch (RemoteException e) {
    156                     // remove if the callback is no longer alive.
    157                     iter.remove();
    158                     Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
    159                 }
    160             }
    161         }
    162         sendImsServiceIntent(state);
    163     }
    164 
    165     /**
    166      * Provide backwards compatibility using deprecated service UP/DOWN intents.
    167      */
    168     private void sendImsServiceIntent(@ImsState int state) {
    169         if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
    170             return;
    171         }
    172         Intent intent;
    173         switch (state) {
    174             case ImsFeature.STATE_NOT_AVAILABLE:
    175             case ImsFeature.STATE_INITIALIZING:
    176                 intent = new Intent(ACTION_IMS_SERVICE_DOWN);
    177                 break;
    178             case ImsFeature.STATE_READY:
    179                 intent = new Intent(ACTION_IMS_SERVICE_UP);
    180                 break;
    181             default:
    182                 intent = new Intent(ACTION_IMS_SERVICE_DOWN);
    183         }
    184         intent.putExtra(EXTRA_PHONE_ID, mSlotId);
    185         mContext.sendBroadcast(intent);
    186     }
    187 
    188     /**
    189      * Called when the feature is ready to use.
    190      */
    191     public abstract void onFeatureReady();
    192 
    193     /**
    194      * Called when the feature is being removed and must be cleaned up.
    195      */
    196     public abstract void onFeatureRemoved();
    197 
    198     /**
    199      * @return Binder instance
    200      */
    201     public abstract IInterface getBinder();
    202 }
    203