15f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger/* 25f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * Copyright (C) 2018 The Android Open Source Project 35f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * 45f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * Licensed under the Apache License, Version 2.0 (the "License"); 55f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * you may not use this file except in compliance with the License. 65f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * You may obtain a copy of the License at 75f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * 85f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * http://www.apache.org/licenses/LICENSE-2.0 95f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * 105f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * Unless required by applicable law or agreed to in writing, software 115f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * distributed under the License is distributed on an "AS IS" BASIS, 125f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * See the License for the specific language governing permissions and 145f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * limitations under the License. 155f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger */ 165f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 175f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerpackage com.android.internal.telephony.ims; 185f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 195f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport android.content.ComponentName; 205f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport android.content.Context; 215f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport android.content.Intent; 225f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport android.content.ServiceConnection; 235f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport android.os.IBinder; 245f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport android.os.RemoteException; 255f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport android.telephony.ims.aidl.IImsServiceController; 265f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport android.telephony.ims.stub.ImsFeatureConfiguration; 275f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport android.util.Log; 285f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 295f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport java.util.HashMap; 305f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport java.util.Map; 315f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerimport java.util.Set; 325f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 335f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger/** 345f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * Manages the querying of multiple ImsServices asynchronously in order to retrieve the ImsFeatures 355f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * they support. 365f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger */ 375f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 385f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebingerpublic class ImsServiceFeatureQueryManager { 395f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 405f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger private final class ImsServiceFeatureQuery implements ServiceConnection { 415f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 425f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger private static final String LOG_TAG = "ImsServiceFeatureQuery"; 435f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 445f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger private final ComponentName mName; 455f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger private final String mIntentFilter; 465f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 475f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger ImsServiceFeatureQuery(ComponentName name, String intentFilter) { 485f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger mName = name; 495f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger mIntentFilter = intentFilter; 505f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 515f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 525f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger /** 535f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * Starts the bind to the ImsService specified ComponentName. 545f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * @return true if binding started, false if it failed and will not recover. 555f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger */ 565f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger public boolean start() { 575f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger Log.d(LOG_TAG, "start: intent filter=" + mIntentFilter + ", name=" + mName); 585f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger Intent imsServiceIntent = new Intent(mIntentFilter).setComponent(mName); 595f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger int serviceFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE 605f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger | Context.BIND_IMPORTANT; 615f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger boolean bindStarted = mContext.bindService(imsServiceIntent, this, serviceFlags); 625f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger if (!bindStarted) { 635f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger // Docs say to unbind if this fails. 645f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger cleanup(); 655f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 665f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger return bindStarted; 675f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 685f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 695f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger @Override 705f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger public void onServiceConnected(ComponentName name, IBinder service) { 715f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger Log.i(LOG_TAG, "onServiceConnected for component: " + name); 725f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger if (service != null) { 735f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger queryImsFeatures(IImsServiceController.Stub.asInterface(service)); 745f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } else { 755f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger Log.w(LOG_TAG, "onServiceConnected: " + name + " binder null, cleaning up."); 765f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger cleanup(); 775f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 785f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 795f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 805f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger @Override 815f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger public void onServiceDisconnected(ComponentName name) { 825f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger Log.w(LOG_TAG, "onServiceDisconnected for component: " + name); 835f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 845f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 855f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger private void queryImsFeatures(IImsServiceController controller) { 865f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger ImsFeatureConfiguration config; 875f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger try { 885f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger config = controller.querySupportedImsFeatures(); 895f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } catch (RemoteException e) { 905f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger Log.w(LOG_TAG, "queryImsFeatures - error: " + e); 915f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger cleanup(); 925f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger mListener.onError(mName); 935f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger return; 945f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 955f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger Set<ImsFeatureConfiguration.FeatureSlotPair> servicePairs = config.getServiceFeatures(); 965f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger // Complete, remove from active queries and notify. 975f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger cleanup(); 985f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger mListener.onComplete(mName, servicePairs); 995f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1005f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 1015f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger private void cleanup() { 1025f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger mContext.unbindService(this); 1035f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger synchronized (mLock) { 1045f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger mActiveQueries.remove(mName); 1055f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1065f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1075f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1085f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 1095f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger public interface Listener { 1105f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger /** 1115f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * Called when a query has completed. 1125f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * @param name The Package Name of the query 1135f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * @param features A Set of slotid->feature pairs that the ImsService supports. 1145f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger */ 1155f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger void onComplete(ComponentName name, Set<ImsFeatureConfiguration.FeatureSlotPair> features); 1165f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 1175f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger /** 1185f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * Called when a query has failed and should be retried. 1195f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger */ 1205f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger void onError(ComponentName name); 1215f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1225f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 1235f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger // Maps an active ImsService query (by Package Name String) its query. 1245f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger private final Map<ComponentName, ImsServiceFeatureQuery> mActiveQueries = new HashMap<>(); 1255f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger private final Context mContext; 1265f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger private final Listener mListener; 1275f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger private final Object mLock = new Object(); 1285f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 1295f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger public ImsServiceFeatureQueryManager(Context context, Listener listener) { 1305f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger mContext = context; 1315f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger mListener = listener; 1325f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1335f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 1345f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger /** 1355f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * Starts an ImsService feature query for the ComponentName and Intent specified. 1365f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * @param name The ComponentName of the ImsService being queried. 1375f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * @param intentFilter The Intent filter that the ImsService specified. 1385f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * @return true if the query started, false if it was unable to start. 1395f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger */ 1405f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger public boolean startQuery(ComponentName name, String intentFilter) { 1415f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger synchronized (mLock) { 1425f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger if (mActiveQueries.containsKey(name)) { 1435f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger // We already have an active query, wait for it to return. 1445f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger return true; 1455f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1465f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger ImsServiceFeatureQuery query = new ImsServiceFeatureQuery(name, intentFilter); 1475f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger mActiveQueries.put(name, query); 1485f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger return query.start(); 1495f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1505f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1515f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger 1525f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger /** 1535f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger * @return true if there are any active queries, false if the manager is idle. 1545f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger */ 1555f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger public boolean isQueryInProgress() { 1565f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger synchronized (mLock) { 1575f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger return !mActiveQueries.isEmpty(); 1585f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1595f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger } 1605f6a521925b16e8c5f6dfdfa7dad928f65dfc362Brad Ebinger} 161