• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
18 
19 import android.app.PendingIntent;
20 import android.os.IBinder;
21 import android.os.Message;
22 import android.os.RemoteException;
23 import android.telephony.ims.feature.IRcsFeature;
24 import android.telephony.ims.feature.ImsFeature;
25 import android.util.Log;
26 
27 import com.android.ims.ImsCallProfile;
28 import com.android.ims.internal.IImsCallSession;
29 import com.android.ims.internal.IImsCallSessionListener;
30 import com.android.ims.internal.IImsConfig;
31 import com.android.ims.internal.IImsEcbm;
32 import com.android.ims.internal.IImsMultiEndpoint;
33 import com.android.ims.internal.IImsRegistrationListener;
34 import com.android.ims.internal.IImsServiceController;
35 import com.android.ims.internal.IImsServiceFeatureListener;
36 import 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 
44 public 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 {
notifyStatusChanged()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 
ImsServiceProxy(int slotId, IBinder binder, int featureType)101     public ImsServiceProxy(int slotId, IBinder binder, int featureType) {
102         super(slotId, binder);
103         mSupportedFeature = featureType;
104     }
105 
ImsServiceProxy(int slotId, int featureType)106     public ImsServiceProxy(int slotId, int featureType) {
107         super(slotId, null /*IBinder*/);
108         mSupportedFeature = featureType;
109     }
110 
getListener()111     public IImsServiceFeatureListener getListener() {
112         return mListenerBinder;
113     }
114 
setBinder(IBinder binder)115     public void setBinder(IBinder binder) {
116         mBinder = binder;
117     }
118 
119     @Override
startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)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
endSession(int sessionId)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
isConnected(int callServiceType, int callType)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
isOpened()148     public boolean isOpened() throws RemoteException {
149         synchronized (mLock) {
150             checkServiceIsReady();
151             return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature);
152         }
153     }
154 
155     @Override
addRegistrationListener(IImsRegistrationListener listener)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
removeRegistrationListener(IImsRegistrationListener listener)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
createCallProfile(int sessionId, int callServiceType, int callType)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
createCallSession(int sessionId, ImsCallProfile profile, IImsCallSessionListener listener)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
getPendingCallSession(int sessionId, String callId)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
getUtInterface()206     public IImsUt getUtInterface() throws RemoteException {
207         synchronized (mLock) {
208             checkServiceIsReady();
209             return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature);
210         }
211     }
212 
213     @Override
getConfigInterface()214     public IImsConfig getConfigInterface() throws RemoteException {
215         synchronized (mLock) {
216             checkServiceIsReady();
217             return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature);
218         }
219     }
220 
221     @Override
turnOnIms()222     public void turnOnIms() throws RemoteException {
223         synchronized (mLock) {
224             checkServiceIsReady();
225             getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature);
226         }
227     }
228 
229     @Override
turnOffIms()230     public void turnOffIms() throws RemoteException {
231         synchronized (mLock) {
232             checkServiceIsReady();
233             getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature);
234         }
235     }
236 
237     @Override
getEcbmInterface()238     public IImsEcbm getEcbmInterface() throws RemoteException {
239         synchronized (mLock) {
240             checkServiceIsReady();
241             return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature);
242         }
243     }
244 
245     @Override
setUiTTYMode(int uiTtyMode, Message onComplete)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
getMultiEndpointInterface()256     public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
257         synchronized (mLock) {
258             checkServiceIsReady();
259             return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
260                     mSupportedFeature);
261         }
262     }
263 
264     @Override
getFeatureStatus()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      */
retrieveFeatureStatus()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      */
setStatusCallback(INotifyStatusChanged c)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      */
isBinderReady()315     public boolean isBinderReady() {
316         return isBinderAlive() && getFeatureStatus() == ImsFeature.STATE_READY;
317     }
318 
319     @Override
isBinderAlive()320     public boolean isBinderAlive() {
321         return mIsAvailable && mBinder != null && mBinder.isBinderAlive();
322     }
323 
checkServiceIsReady()324     protected void checkServiceIsReady() throws RemoteException {
325         if (!isBinderReady()) {
326             throw new RemoteException("ImsServiceProxy is not ready to accept commands.");
327         }
328     }
329 
getServiceInterface(IBinder b)330     private IImsServiceController getServiceInterface(IBinder b) {
331         return IImsServiceController.Stub.asInterface(b);
332     }
333 }
334