ImsServiceProxy.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;
18
19import android.app.PendingIntent;
20import android.os.IBinder;
21import android.os.Message;
22import android.os.RemoteException;
23import android.telephony.ims.feature.IRcsFeature;
24import android.telephony.ims.feature.ImsFeature;
25import android.util.Log;
26
27import com.android.ims.ImsCallProfile;
28import com.android.ims.internal.IImsCallSession;
29import com.android.ims.internal.IImsCallSessionListener;
30import com.android.ims.internal.IImsConfig;
31import com.android.ims.internal.IImsEcbm;
32import com.android.ims.internal.IImsMultiEndpoint;
33import com.android.ims.internal.IImsRegistrationListener;
34import com.android.ims.internal.IImsServiceController;
35import com.android.ims.internal.IImsServiceFeatureListener;
36import com.android.ims.internal.IImsUt;
37
38/**
39 * A container of the IImsServiceController binder, which implements all of the ImsFeatures that
40 * the platform currently supports: MMTel and RCS.
41 * @hide
42 */
43
44public class ImsServiceProxy extends ImsServiceProxyCompat implements IRcsFeature {
45
46    protected String LOG_TAG = "ImsServiceProxy";
47    private final int mSupportedFeature;
48
49    // Start by assuming the proxy is available for usage.
50    private boolean mIsAvailable = true;
51    // ImsFeature Status from the ImsService. Cached.
52    private Integer mFeatureStatusCached = null;
53    private ImsServiceProxy.INotifyStatusChanged mStatusCallback;
54    private final Object mLock = new Object();
55
56    public interface INotifyStatusChanged {
57        void notifyStatusChanged();
58    }
59
60    private final IImsServiceFeatureListener mListenerBinder =
61            new IImsServiceFeatureListener.Stub() {
62
63        @Override
64        public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
65            // The feature has been re-enabled. This may happen when the service crashes.
66            synchronized (mLock) {
67                if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
68                    Log.i(LOG_TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
69                            feature);
70                    mIsAvailable = true;
71                }
72            }
73        }
74
75        @Override
76        public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
77            synchronized (mLock) {
78                if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
79                    Log.i(LOG_TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
80                            feature);
81                    mIsAvailable = false;
82                }
83            }
84        }
85
86        @Override
87        public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
88            synchronized (mLock) {
89                Log.i(LOG_TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
90                        " status: " + status);
91                if (mSlotId == slotId && feature == mSupportedFeature) {
92                    mFeatureStatusCached = status;
93                }
94            }
95            if (mStatusCallback != null) {
96                mStatusCallback.notifyStatusChanged();
97            }
98        }
99    };
100
101    public ImsServiceProxy(int slotId, IBinder binder, int featureType) {
102        super(slotId, binder);
103        mSupportedFeature = featureType;
104    }
105
106    public ImsServiceProxy(int slotId, int featureType) {
107        super(slotId, null /*IBinder*/);
108        mSupportedFeature = featureType;
109    }
110
111    public IImsServiceFeatureListener getListener() {
112        return mListenerBinder;
113    }
114
115    public void setBinder(IBinder binder) {
116        mBinder = binder;
117    }
118
119    @Override
120    public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
121            throws RemoteException {
122        synchronized (mLock) {
123            checkServiceIsReady();
124            return getServiceInterface(mBinder).startSession(mSlotId, mSupportedFeature,
125                    incomingCallIntent, listener);
126        }
127    }
128
129    @Override
130    public void endSession(int sessionId) throws RemoteException {
131        synchronized (mLock) {
132            checkServiceIsReady();
133            getServiceInterface(mBinder).endSession(mSlotId, mSupportedFeature, sessionId);
134        }
135    }
136
137    @Override
138    public boolean isConnected(int callServiceType, int callType)
139            throws RemoteException {
140        synchronized (mLock) {
141            checkServiceIsReady();
142            return getServiceInterface(mBinder).isConnected(mSlotId, mSupportedFeature,
143                    callServiceType, callType);
144        }
145    }
146
147    @Override
148    public boolean isOpened() throws RemoteException {
149        synchronized (mLock) {
150            checkServiceIsReady();
151            return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature);
152        }
153    }
154
155    @Override
156    public void addRegistrationListener(IImsRegistrationListener listener)
157    throws RemoteException {
158        synchronized (mLock) {
159            checkServiceIsReady();
160            getServiceInterface(mBinder).addRegistrationListener(mSlotId, mSupportedFeature,
161                    listener);
162        }
163    }
164
165    @Override
166    public void removeRegistrationListener(IImsRegistrationListener listener)
167            throws RemoteException {
168        synchronized (mLock) {
169            checkServiceIsReady();
170            getServiceInterface(mBinder).removeRegistrationListener(mSlotId, mSupportedFeature,
171                    listener);
172        }
173    }
174
175    @Override
176    public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
177            throws RemoteException {
178        synchronized (mLock) {
179            checkServiceIsReady();
180            return getServiceInterface(mBinder).createCallProfile(mSlotId, mSupportedFeature,
181                    sessionId, callServiceType, callType);
182        }
183    }
184
185    @Override
186    public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
187            IImsCallSessionListener listener) throws RemoteException {
188        synchronized (mLock) {
189            checkServiceIsReady();
190            return getServiceInterface(mBinder).createCallSession(mSlotId, mSupportedFeature,
191                    sessionId, profile, listener);
192        }
193    }
194
195    @Override
196    public IImsCallSession getPendingCallSession(int sessionId, String callId)
197            throws RemoteException {
198        synchronized (mLock) {
199            checkServiceIsReady();
200            return getServiceInterface(mBinder).getPendingCallSession(mSlotId, mSupportedFeature,
201                    sessionId, callId);
202        }
203    }
204
205    @Override
206    public IImsUt getUtInterface() throws RemoteException {
207        synchronized (mLock) {
208            checkServiceIsReady();
209            return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature);
210        }
211    }
212
213    @Override
214    public IImsConfig getConfigInterface() throws RemoteException {
215        synchronized (mLock) {
216            checkServiceIsReady();
217            return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature);
218        }
219    }
220
221    @Override
222    public void turnOnIms() throws RemoteException {
223        synchronized (mLock) {
224            checkServiceIsReady();
225            getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature);
226        }
227    }
228
229    @Override
230    public void turnOffIms() throws RemoteException {
231        synchronized (mLock) {
232            checkServiceIsReady();
233            getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature);
234        }
235    }
236
237    @Override
238    public IImsEcbm getEcbmInterface() throws RemoteException {
239        synchronized (mLock) {
240            checkServiceIsReady();
241            return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature);
242        }
243    }
244
245    @Override
246    public void setUiTTYMode(int uiTtyMode, Message onComplete)
247            throws RemoteException {
248        synchronized (mLock) {
249            checkServiceIsReady();
250            getServiceInterface(mBinder).setUiTTYMode(mSlotId, mSupportedFeature, uiTtyMode,
251                    onComplete);
252        }
253    }
254
255    @Override
256    public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
257        synchronized (mLock) {
258            checkServiceIsReady();
259            return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
260                    mSupportedFeature);
261        }
262    }
263
264    @Override
265    public int getFeatureStatus() {
266        synchronized (mLock) {
267            if (isBinderAlive() && mFeatureStatusCached != null) {
268                Log.i(LOG_TAG, "getFeatureStatus - returning cached: " + mFeatureStatusCached);
269                return mFeatureStatusCached;
270            }
271        }
272        // Don't synchronize on Binder call.
273        Integer status = retrieveFeatureStatus();
274        synchronized (mLock) {
275            if (status == null) {
276                return ImsFeature.STATE_NOT_AVAILABLE;
277            }
278            // Cache only non-null value for feature status.
279            mFeatureStatusCached = status;
280        }
281        Log.i(LOG_TAG, "getFeatureStatus - returning " + status);
282        return status;
283    }
284
285    /**
286     * Internal method used to retrieve the feature status from the corresponding ImsService.
287     */
288    private Integer retrieveFeatureStatus() {
289        if (mBinder != null) {
290            try {
291                return getServiceInterface(mBinder).getFeatureStatus(mSlotId, mSupportedFeature);
292            } catch (RemoteException e) {
293                // Status check failed, don't update cache
294            }
295        }
296        return null;
297    }
298
299    /**
300     * @param c Callback that will fire when the feature status has changed.
301     */
302    public void setStatusCallback(INotifyStatusChanged c) {
303        mStatusCallback = c;
304    }
305
306    /**
307     * @return Returns true if the ImsService is ready to take commands, false otherwise. If this
308     * method returns false, it doesn't mean that the Binder connection is not available (use
309     * {@link #isBinderReady()} to check that), but that the ImsService is not accepting commands
310     * at this time.
311     *
312     * For example, for DSDS devices, only one slot can be {@link ImsFeature#STATE_READY} to take
313     * commands at a time, so the other slot must stay at {@link ImsFeature#STATE_NOT_AVAILABLE}.
314     */
315    public boolean isBinderReady() {
316        return isBinderAlive() && getFeatureStatus() == ImsFeature.STATE_READY;
317    }
318
319    @Override
320    public boolean isBinderAlive() {
321        return mIsAvailable && mBinder != null && mBinder.isBinderAlive();
322    }
323
324    protected void checkServiceIsReady() throws RemoteException {
325        if (!isBinderReady()) {
326            throw new RemoteException("ImsServiceProxy is not ready to accept commands.");
327        }
328    }
329
330    private IImsServiceController getServiceInterface(IBinder b) {
331        return IImsServiceController.Stub.asInterface(b);
332    }
333}
334