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.compat.stub;
18 
19 import android.annotation.UnsupportedAppUsage;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.RemoteException;
23 import android.util.Log;
24 
25 import com.android.ims.ImsConfig;
26 import com.android.ims.ImsConfigListener;
27 import com.android.ims.internal.IImsConfig;
28 import com.android.internal.annotations.VisibleForTesting;
29 
30 import java.lang.ref.WeakReference;
31 import java.util.HashMap;
32 
33 
34 /**
35  * Base implementation of ImsConfig.
36  * Override the methods that your implementation of ImsConfig supports.
37  *
38  * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
39  * will break other implementations of ImsConfig maintained by other ImsServices.
40  *
41  * Provides APIs to get/set the IMS service feature/capability/parameters.
42  * The config items include:
43  * 1) Items provisioned by the operator.
44  * 2) Items configured by user. Mainly service feature class.
45  *
46  * The inner class {@link ImsConfigStub} implements methods of IImsConfig AIDL interface.
47  * The IImsConfig AIDL interface is called by ImsConfig, which may exist in many other processes.
48  * ImsConfigImpl access to the configuration parameters may be arbitrarily slow, especially in
49  * during initialization, or times when a lot of configuration parameters are being set/get
50  * (such as during boot up or SIM card change). By providing a cache in ImsConfigStub, we can speed
51  * up access to these configuration parameters, so a query to the ImsConfigImpl does not have to be
52  * performed every time.
53  * @hide
54  */
55 
56 public class ImsConfigImplBase {
57 
58     static final private String TAG = "ImsConfigImplBase";
59 
60     ImsConfigStub mImsConfigStub;
61 
62     @UnsupportedAppUsage
ImsConfigImplBase(Context context)63     public ImsConfigImplBase(Context context) {
64         mImsConfigStub = new ImsConfigStub(this, context);
65     }
66 
67     /**
68      * Gets the value for ims service/capabilities parameters from the provisioned
69      * value storage. Synchronous blocking call.
70      *
71      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
72      * @return value in Integer format.
73      */
getProvisionedValue(int item)74     public int getProvisionedValue(int item) throws RemoteException {
75         return -1;
76     }
77 
78     /**
79      * Gets the value for ims service/capabilities parameters from the provisioned
80      * value storage. Synchronous blocking call.
81      *
82      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
83      * @return value in String format.
84      */
getProvisionedStringValue(int item)85     public String getProvisionedStringValue(int item) throws RemoteException {
86         return null;
87     }
88 
89     /**
90      * Sets the value for IMS service/capabilities parameters by the operator device
91      * management entity. It sets the config item value in the provisioned storage
92      * from which the master value is derived. Synchronous blocking call.
93      *
94      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
95      * @param value in Integer format.
96      * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
97      */
setProvisionedValue(int item, int value)98     public int setProvisionedValue(int item, int value) throws RemoteException {
99         return ImsConfig.OperationStatusConstants.FAILED;
100     }
101 
102     /**
103      * Sets the value for IMS service/capabilities parameters by the operator device
104      * management entity. It sets the config item value in the provisioned storage
105      * from which the master value is derived.  Synchronous blocking call.
106      *
107      * @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
108      * @param value in String format.
109      * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
110      */
setProvisionedStringValue(int item, String value)111     public int setProvisionedStringValue(int item, String value) throws RemoteException {
112         return ImsConfig.OperationStatusConstants.FAILED;
113     }
114 
115     /**
116      * Gets the value of the specified IMS feature item for specified network type.
117      * This operation gets the feature config value from the master storage (i.e. final
118      * value). Asynchronous non-blocking call.
119      *
120      * @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
121      * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
122      * @param listener feature value returned asynchronously through listener.
123      */
getFeatureValue(int feature, int network, ImsConfigListener listener)124     public void getFeatureValue(int feature, int network, ImsConfigListener listener)
125             throws RemoteException {
126     }
127 
128     /**
129      * Sets the value for IMS feature item for specified network type.
130      * This operation stores the user setting in setting db from which master db
131      * is derived.
132      *
133      * @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
134      * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
135      * @param value as defined in com.android.ims.ImsConfig#FeatureValueConstants.
136      * @param listener, provided if caller needs to be notified for set result.
137      */
setFeatureValue(int feature, int network, int value, ImsConfigListener listener)138     public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
139             throws RemoteException {
140     }
141 
142     /**
143      * Gets the value for IMS VoLTE provisioned.
144      * This should be the same as the operator provisioned value if applies.
145      */
getVolteProvisioned()146     public boolean getVolteProvisioned() throws RemoteException {
147         return false;
148     }
149 
150     /**
151      * Gets the value for IMS feature item video quality.
152      *
153      * @param listener Video quality value returned asynchronously through listener.
154      */
getVideoQuality(ImsConfigListener listener)155     public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
156     }
157 
158     /**
159      * Sets the value for IMS feature item video quality.
160      *
161      * @param quality, defines the value of video quality.
162      * @param listener, provided if caller needs to be notified for set result.
163      */
setVideoQuality(int quality, ImsConfigListener listener)164     public void setVideoQuality(int quality, ImsConfigListener listener) throws RemoteException {
165     }
166 
167     @UnsupportedAppUsage
getIImsConfig()168     public IImsConfig getIImsConfig() { return mImsConfigStub; }
169 
170     /**
171      * Updates provisioning value and notifies the framework of the change.
172      * Doesn't call #setProvisionedValue and assumes the result succeeded.
173      * This should only be used by modem when they implicitly changed provisioned values.
174      *
175      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
176      * @param value in Integer format.
177      */
notifyProvisionedValueChanged(int item, int value)178     public final void notifyProvisionedValueChanged(int item, int value) {
179         mImsConfigStub.updateCachedValue(item, value, true);
180     }
181 
182     /**
183      * Updates provisioning value and notifies the framework of the change.
184      * Doesn't call #setProvisionedValue and assumes the result succeeded.
185      * This should only be used by modem when they implicitly changed provisioned values.
186      *
187      * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
188      * @param value in String format.
189      */
notifyProvisionedValueChanged(int item, String value)190     public final void notifyProvisionedValueChanged(int item, String value) {
191         mImsConfigStub.updateCachedValue(item, value, true);
192     }
193 
194     /**
195      * Implements the IImsConfig AIDL interface, which is called by potentially many processes
196      * in order to get/set configuration parameters.
197      *
198      * It holds an object of ImsConfigImplBase class which is usually extended by ImsConfigImpl
199      * with actual implementations from vendors. This class caches provisioned values from
200      * ImsConfigImpl layer because queries through ImsConfigImpl can be slow. When query goes in,
201      * it first checks cache layer. If missed, it will call the vendor implementation of
202      * ImsConfigImplBase API.
203      * and cache the return value if the set succeeds.
204      *
205      * Provides APIs to get/set the IMS service feature/capability/parameters.
206      * The config items include:
207      * 1) Items provisioned by the operator.
208      * 2) Items configured by user. Mainly service feature class.
209      *
210      * @hide
211      */
212     @VisibleForTesting
213     static public class ImsConfigStub extends IImsConfig.Stub {
214         Context mContext;
215         WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference;
216         private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>();
217         private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>();
218 
219         @VisibleForTesting
ImsConfigStub(ImsConfigImplBase imsConfigImplBase, Context context)220         public ImsConfigStub(ImsConfigImplBase imsConfigImplBase, Context context) {
221             mContext = context;
222             mImsConfigImplBaseWeakReference =
223                     new WeakReference<ImsConfigImplBase>(imsConfigImplBase);
224         }
225 
226         /**
227          * Gets the value for ims service/capabilities parameters. It first checks its local cache,
228          * if missed, it will call ImsConfigImplBase.getProvisionedValue.
229          * Synchronous blocking call.
230          *
231          * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
232          * @return value in Integer format.
233          */
234         @Override
getProvisionedValue(int item)235         public synchronized int getProvisionedValue(int item) throws RemoteException {
236             if (mProvisionedIntValue.containsKey(item)) {
237                 return mProvisionedIntValue.get(item);
238             } else {
239                 int retVal = getImsConfigImpl().getProvisionedValue(item);
240                 if (retVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
241                     updateCachedValue(item, retVal, false);
242                 }
243                 return retVal;
244             }
245         }
246 
247         /**
248          * Gets the value for ims service/capabilities parameters. It first checks its local cache,
249          * if missed, it will call #ImsConfigImplBase.getProvisionedValue.
250          * Synchronous blocking call.
251          *
252          * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
253          * @return value in String format.
254          */
255         @Override
getProvisionedStringValue(int item)256         public synchronized String getProvisionedStringValue(int item) throws RemoteException {
257             if (mProvisionedIntValue.containsKey(item)) {
258                 return mProvisionedStringValue.get(item);
259             } else {
260                 String retVal = getImsConfigImpl().getProvisionedStringValue(item);
261                 if (retVal != null) {
262                     updateCachedValue(item, retVal, false);
263                 }
264                 return retVal;
265             }
266         }
267 
268         /**
269          * Sets the value for IMS service/capabilities parameters by the operator device
270          * management entity. It sets the config item value in the provisioned storage
271          * from which the master value is derived, and write it into local cache.
272          * Synchronous blocking call.
273          *
274          * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
275          * @param value in Integer format.
276          * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
277          */
278         @Override
setProvisionedValue(int item, int value)279         public synchronized int setProvisionedValue(int item, int value) throws RemoteException {
280             mProvisionedIntValue.remove(item);
281             int retVal = getImsConfigImpl().setProvisionedValue(item, value);
282             if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
283                 updateCachedValue(item, value, true);
284             } else {
285                 Log.d(TAG, "Set provision value of " + item +
286                         " to " + value + " failed with error code " + retVal);
287             }
288 
289             return retVal;
290         }
291 
292         /**
293          * Sets the value for IMS service/capabilities parameters by the operator device
294          * management entity. It sets the config item value in the provisioned storage
295          * from which the master value is derived, and write it into local cache.
296          * Synchronous blocking call.
297          *
298          * @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
299          * @param value in String format.
300          * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
301          */
302         @Override
setProvisionedStringValue(int item, String value)303         public synchronized int setProvisionedStringValue(int item, String value)
304                 throws RemoteException {
305             mProvisionedStringValue.remove(item);
306             int retVal = getImsConfigImpl().setProvisionedStringValue(item, value);
307             if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
308                 updateCachedValue(item, value, true);
309             }
310 
311             return retVal;
312         }
313 
314         /**
315          * Wrapper function to call ImsConfigImplBase.getFeatureValue.
316          */
317         @Override
getFeatureValue(int feature, int network, ImsConfigListener listener)318         public void getFeatureValue(int feature, int network, ImsConfigListener listener)
319                 throws RemoteException {
320             getImsConfigImpl().getFeatureValue(feature, network, listener);
321         }
322 
323         /**
324          * Wrapper function to call ImsConfigImplBase.setFeatureValue.
325          */
326         @Override
setFeatureValue(int feature, int network, int value, ImsConfigListener listener)327         public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
328                 throws RemoteException {
329             getImsConfigImpl().setFeatureValue(feature, network, value, listener);
330         }
331 
332         /**
333          * Wrapper function to call ImsConfigImplBase.getVolteProvisioned.
334          */
335         @Override
getVolteProvisioned()336         public boolean getVolteProvisioned() throws RemoteException {
337             return getImsConfigImpl().getVolteProvisioned();
338         }
339 
340         /**
341          * Wrapper function to call ImsConfigImplBase.getVideoQuality.
342          */
343         @Override
getVideoQuality(ImsConfigListener listener)344         public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
345             getImsConfigImpl().getVideoQuality(listener);
346         }
347 
348         /**
349          * Wrapper function to call ImsConfigImplBase.setVideoQuality.
350          */
351         @Override
setVideoQuality(int quality, ImsConfigListener listener)352         public void setVideoQuality(int quality, ImsConfigListener listener)
353                 throws RemoteException {
354             getImsConfigImpl().setVideoQuality(quality, listener);
355         }
356 
getImsConfigImpl()357         private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
358             ImsConfigImplBase ref = mImsConfigImplBaseWeakReference.get();
359             if (ref == null) {
360                 throw new RemoteException("Fail to get ImsConfigImpl");
361             } else {
362                 return ref;
363             }
364         }
365 
sendImsConfigChangedIntent(int item, int value)366         private void sendImsConfigChangedIntent(int item, int value) {
367             sendImsConfigChangedIntent(item, Integer.toString(value));
368         }
369 
sendImsConfigChangedIntent(int item, String value)370         private void sendImsConfigChangedIntent(int item, String value) {
371             Intent configChangedIntent = new Intent(ImsConfig.ACTION_IMS_CONFIG_CHANGED);
372             configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item);
373             configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value);
374             if (mContext != null) {
375                 mContext.sendBroadcast(configChangedIntent);
376             }
377         }
378 
updateCachedValue(int item, int value, boolean notifyChange)379         protected synchronized void updateCachedValue(int item, int value, boolean notifyChange) {
380             mProvisionedIntValue.put(item, value);
381             if (notifyChange) {
382                 sendImsConfigChangedIntent(item, value);
383             }
384         }
385 
updateCachedValue( int item, String value, boolean notifyChange)386         protected synchronized void updateCachedValue(
387                 int item, String value, boolean notifyChange) {
388             mProvisionedStringValue.put(item, value);
389             if (notifyChange) {
390                 sendImsConfigChangedIntent(item, value);
391             }
392         }
393     }
394 }