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