blob: cbeeeadf83e10e48a29dd6e8f3ac9ac29614c164 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.telephony.ims;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.telephony.ims.aidl.IImsServiceController;
import android.telephony.ims.stub.ImsFeatureConfiguration;
import android.util.Log;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Manages the querying of multiple ImsServices asynchronously in order to retrieve the ImsFeatures
* they support.
*/
public class ImsServiceFeatureQueryManager {
private final class ImsServiceFeatureQuery implements ServiceConnection {
private static final String LOG_TAG = "ImsServiceFeatureQuery";
private final ComponentName mName;
private final String mIntentFilter;
ImsServiceFeatureQuery(ComponentName name, String intentFilter) {
mName = name;
mIntentFilter = intentFilter;
}
/**
* Starts the bind to the ImsService specified ComponentName.
* @return true if binding started, false if it failed and will not recover.
*/
public boolean start() {
Log.d(LOG_TAG, "start: intent filter=" + mIntentFilter + ", name=" + mName);
Intent imsServiceIntent = new Intent(mIntentFilter).setComponent(mName);
int serviceFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
| Context.BIND_IMPORTANT;
boolean bindStarted = mContext.bindService(imsServiceIntent, this, serviceFlags);
if (!bindStarted) {
// Docs say to unbind if this fails.
cleanup();
}
return bindStarted;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(LOG_TAG, "onServiceConnected for component: " + name);
if (service != null) {
queryImsFeatures(IImsServiceController.Stub.asInterface(service));
} else {
Log.w(LOG_TAG, "onServiceConnected: " + name + " binder null, cleaning up.");
cleanup();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.w(LOG_TAG, "onServiceDisconnected for component: " + name);
}
private void queryImsFeatures(IImsServiceController controller) {
ImsFeatureConfiguration config;
try {
config = controller.querySupportedImsFeatures();
} catch (Exception e) {
Log.w(LOG_TAG, "queryImsFeatures - error: " + e);
cleanup();
mListener.onError(mName);
return;
}
Set<ImsFeatureConfiguration.FeatureSlotPair> servicePairs = config.getServiceFeatures();
// Complete, remove from active queries and notify.
cleanup();
mListener.onComplete(mName, servicePairs);
}
private void cleanup() {
mContext.unbindService(this);
synchronized (mLock) {
mActiveQueries.remove(mName);
}
}
}
public interface Listener {
/**
* Called when a query has completed.
* @param name The Package Name of the query
* @param features A Set of slotid->feature pairs that the ImsService supports.
*/
void onComplete(ComponentName name, Set<ImsFeatureConfiguration.FeatureSlotPair> features);
/**
* Called when a query has failed and should be retried.
*/
void onError(ComponentName name);
}
// Maps an active ImsService query (by Package Name String) its query.
private final Map<ComponentName, ImsServiceFeatureQuery> mActiveQueries = new HashMap<>();
private final Context mContext;
private final Listener mListener;
private final Object mLock = new Object();
public ImsServiceFeatureQueryManager(Context context, Listener listener) {
mContext = context;
mListener = listener;
}
/**
* Starts an ImsService feature query for the ComponentName and Intent specified.
* @param name The ComponentName of the ImsService being queried.
* @param intentFilter The Intent filter that the ImsService specified.
* @return true if the query started, false if it was unable to start.
*/
public boolean startQuery(ComponentName name, String intentFilter) {
synchronized (mLock) {
if (mActiveQueries.containsKey(name)) {
// We already have an active query, wait for it to return.
return true;
}
ImsServiceFeatureQuery query = new ImsServiceFeatureQuery(name, intentFilter);
mActiveQueries.put(name, query);
return query.start();
}
}
/**
* @return true if there are any active queries, false if the manager is idle.
*/
public boolean isQueryInProgress() {
synchronized (mLock) {
return !mActiveQueries.isEmpty();
}
}
}