diff --git a/Android.bp b/Android.bp index ae0acade2737..492176a8704e 100644 --- a/Android.bp +++ b/Android.bp @@ -488,6 +488,8 @@ java_library { "telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl", "telephony/java/android/telephony/data/IDataService.aidl", "telephony/java/android/telephony/data/IDataServiceCallback.aidl", + "telephony/java/android/telephony/data/IQualifiedNetworksService.aidl", + "telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl", "telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl", "telephony/java/android/telephony/ims/aidl/IImsCapabilityCallback.aidl", "telephony/java/android/telephony/ims/aidl/IImsConfig.aidl", diff --git a/api/system-current.txt b/api/system-current.txt index 859ee98fc121..34010c560fe0 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5426,6 +5426,19 @@ package android.telephony.data { field public static final int RESULT_SUCCESS = 0; // 0x0 } + public abstract class QualifiedNetworksService extends android.app.Service { + ctor public QualifiedNetworksService(); + method public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityUpdater createNetworkAvailabilityUpdater(int); + field public static final java.lang.String QUALIFIED_NETWORKS_SERVICE_INTERFACE = "android.telephony.data.QualifiedNetworksService"; + } + + public abstract class QualifiedNetworksService.NetworkAvailabilityUpdater implements java.lang.AutoCloseable { + ctor public QualifiedNetworksService.NetworkAvailabilityUpdater(int); + method public abstract void close(); + method public final int getSlotIndex(); + method public final void updateQualifiedNetworkTypes(int, int[]); + } + } package android.telephony.euicc { diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl new file mode 100644 index 000000000000..9c80cb77e435 --- /dev/null +++ b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl @@ -0,0 +1,28 @@ +/* + * Copyright 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 android.telephony.data; + +import android.telephony.data.IQualifiedNetworksServiceCallback; + +/** + * {@hide} + */ +interface IQualifiedNetworksService +{ + oneway void createNetworkAvailabilityUpdater(int slotId, IQualifiedNetworksServiceCallback callback); + oneway void removeNetworkAvailabilityUpdater(int slotId); +} diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl new file mode 100644 index 000000000000..e8e1f017789f --- /dev/null +++ b/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright 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 android.telephony.data; + +/** + * The qualified networks service call back interface + * @hide + */ +oneway interface IQualifiedNetworksServiceCallback +{ + void onQualifiedNetworkTypesChanged(int apnType, in int[] qualifiedNetworkTypesList); +} diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java new file mode 100644 index 000000000000..bb89f193e03a --- /dev/null +++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java @@ -0,0 +1,286 @@ +/* + * Copyright 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 android.telephony.data; + +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.telephony.AccessNetworkConstants.AccessNetworkType; +import android.telephony.Rlog; +import android.telephony.data.ApnSetting.ApnType; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Base class of the qualified networks service. Services that extend QualifiedNetworksService must + * register the service in their AndroidManifest to be detected by the framework. They must be + * protected by the permission "android.permission.BIND_TELEPHONY_QUALIFIED_NETWORKS_SERVICE". + * The qualified networks service definition in the manifest must follow the following format: + * ... + * + * + * + * + * + * @hide + */ +@SystemApi +public abstract class QualifiedNetworksService extends Service { + private static final String TAG = QualifiedNetworksService.class.getSimpleName(); + + public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE = + "android.telephony.data.QualifiedNetworksService"; + + private static final int QNS_CREATE_NETWORK_AVAILABILITY_UPDATER = 1; + private static final int QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER = 2; + private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS = 3; + private static final int QNS_UPDATE_QUALIFIED_NETWORKS = 4; + + private final HandlerThread mHandlerThread; + + private final QualifiedNetworksServiceHandler mHandler; + + private final SparseArray mUpdaters = new SparseArray<>(); + + /** @hide */ + @VisibleForTesting + public final IQualifiedNetworksServiceWrapper mBinder = new IQualifiedNetworksServiceWrapper(); + + /** + * The abstract class of the network availability updater implementation. The vendor qualified + * network service must extend this class to report the available networks for data + * connection setup. Note that each instance of network availability updater is associated with + * one physical SIM slot. + */ + public abstract class NetworkAvailabilityUpdater implements AutoCloseable { + private final int mSlotIndex; + + private IQualifiedNetworksServiceCallback mCallback; + + /** + * Qualified networks for each APN type. Key is the {@link ApnType}, value is the array + * of available networks. + */ + private SparseArray mQualifiedNetworkTypesList = new SparseArray<>(); + + /** + * Constructor + * @param slotIndex SIM slot index the network availability updater associated with. + */ + public NetworkAvailabilityUpdater(int slotIndex) { + mSlotIndex = slotIndex; + } + + /** + * @return SIM slot index the network availability updater associated with. + */ + public final int getSlotIndex() { + return mSlotIndex; + } + + private void registerForQualifiedNetworkTypesChanged( + IQualifiedNetworksServiceCallback callback) { + mCallback = callback; + + // Force sending the qualified networks upon registered. + if (mCallback != null) { + for (int i = 0; i < mQualifiedNetworkTypesList.size(); i++) { + try { + mCallback.onQualifiedNetworkTypesChanged( + mQualifiedNetworkTypesList.keyAt(i), + mQualifiedNetworkTypesList.valueAt(i)); + } catch (RemoteException e) { + loge("Failed to call onQualifiedNetworksChanged. " + e); + } + } + } + } + + /** + * Update the qualified networks list. Network availability updater must invoke this method + * whenever the qualified networks changes. If this method is never invoked for certain + * APN type, then frameworks will always use the default (i.e. cellular) data and network + * service. + * + * @param apnType APN type of the qualified networks + * @param qualifiedNetworkTypes List of network types which are qualified for data + * connection setup for {@link @apnType} in the preferred order. Each element in the array + * is a {@link AccessNetworkType}. An empty list or null indicates no networks are qualified + * for data setup. + */ + public final void updateQualifiedNetworkTypes(@ApnType int apnType, + int[] qualifiedNetworkTypes) { + mHandler.obtainMessage(QNS_UPDATE_QUALIFIED_NETWORKS, mSlotIndex, apnType, + qualifiedNetworkTypes).sendToTarget(); + } + + private void onUpdateQualifiedNetworkTypes(@ApnType int apnType, + int[] qualifiedNetworkTypes) { + mQualifiedNetworkTypesList.put(apnType, qualifiedNetworkTypes); + if (mCallback != null) { + try { + mCallback.onQualifiedNetworkTypesChanged(apnType, qualifiedNetworkTypes); + } catch (RemoteException e) { + loge("Failed to call onQualifiedNetworksChanged. " + e); + } + } + } + + /** + * Called when the qualified networks updater is removed. The extended class should + * implement this method to perform clean up works. + */ + @Override + public abstract void close(); + } + + private class QualifiedNetworksServiceHandler extends Handler { + QualifiedNetworksServiceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message message) { + IQualifiedNetworksServiceCallback callback; + final int slotIndex = message.arg1; + NetworkAvailabilityUpdater updater = mUpdaters.get(slotIndex); + + switch (message.what) { + case QNS_CREATE_NETWORK_AVAILABILITY_UPDATER: + if (mUpdaters.get(slotIndex) != null) { + loge("Network availability updater for slot " + slotIndex + + " already existed."); + return; + } + + updater = createNetworkAvailabilityUpdater(slotIndex); + if (updater != null) { + mUpdaters.put(slotIndex, updater); + + callback = (IQualifiedNetworksServiceCallback) message.obj; + updater.registerForQualifiedNetworkTypesChanged(callback); + } else { + loge("Failed to create network availability updater. slot index = " + + slotIndex); + } + break; + + case QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER: + if (updater != null) { + updater.close(); + mUpdaters.remove(slotIndex); + } + break; + + case QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS: + for (int i = 0; i < mUpdaters.size(); i++) { + updater = mUpdaters.get(i); + if (updater != null) { + updater.close(); + } + } + mUpdaters.clear(); + break; + + case QNS_UPDATE_QUALIFIED_NETWORKS: + if (updater == null) break; + updater.onUpdateQualifiedNetworkTypes(message.arg2, (int[]) message.obj); + break; + } + } + } + + /** + * Default constructor. + */ + public QualifiedNetworksService() { + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + + mHandler = new QualifiedNetworksServiceHandler(mHandlerThread.getLooper()); + log("Qualified networks service created"); + } + + /** + * Create the instance of {@link NetworkAvailabilityUpdater}. Vendor qualified network service + * must override this method to facilitate the creation of {@link NetworkAvailabilityUpdater} + * instances. The system will call this method after binding the qualified networks service for + * each active SIM slot index. + * + * @param slotIndex SIM slot index the qualified networks service associated with. + * @return Qualified networks service instance + */ + public abstract NetworkAvailabilityUpdater createNetworkAvailabilityUpdater(int slotIndex); + + /** @hide */ + @Override + public IBinder onBind(Intent intent) { + if (intent == null || !QUALIFIED_NETWORKS_SERVICE_INTERFACE.equals(intent.getAction())) { + loge("Unexpected intent " + intent); + return null; + } + return mBinder; + } + + /** @hide */ + @Override + public boolean onUnbind(Intent intent) { + mHandler.obtainMessage(QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS).sendToTarget(); + return false; + } + + /** @hide */ + @Override + public void onDestroy() { + mHandlerThread.quit(); + } + + /** + * A wrapper around IQualifiedNetworksService that forwards calls to implementations of + * {@link QualifiedNetworksService}. + */ + private class IQualifiedNetworksServiceWrapper extends IQualifiedNetworksService.Stub { + @Override + public void createNetworkAvailabilityUpdater(int slotIndex, + IQualifiedNetworksServiceCallback callback) { + mHandler.obtainMessage(QNS_CREATE_NETWORK_AVAILABILITY_UPDATER, slotIndex, 0, + callback).sendToTarget(); + } + + @Override + public void removeNetworkAvailabilityUpdater(int slotIndex) { + mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER, slotIndex, 0) + .sendToTarget(); + } + } + + private void log(String s) { + Rlog.d(TAG, s); + } + + private void loge(String s) { + Rlog.e(TAG, s); + } +}