diff --git a/Android.bp b/Android.bp index 4d781125f56ae..67124618b6cc1 100644 --- a/Android.bp +++ b/Android.bp @@ -473,6 +473,8 @@ java_library { "telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl", "telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl", "telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl", + "telephony/java/android/telephony/INetworkService.aidl", + "telephony/java/android/telephony/INetworkServiceCallback.aidl", "telephony/java/com/android/ims/internal/IImsCallSession.aidl", "telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl", "telephony/java/com/android/ims/internal/IImsConfig.aidl", diff --git a/api/current.txt b/api/current.txt index a1e60e5f2588e..7954bf5539871 100644 --- a/api/current.txt +++ b/api/current.txt @@ -39890,6 +39890,7 @@ package android.telephony { field public static final int EUTRAN = 3; // 0x3 field public static final int GERAN = 1; // 0x1 field public static final int IWLAN = 5; // 0x5 + field public static final int UNKNOWN = 0; // 0x0 field public static final int UTRAN = 2; // 0x2 } diff --git a/api/system-current.txt b/api/system-current.txt index e0f8ecf13b052..1dd7c6df8cf9a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3967,6 +3967,63 @@ package android.telephony { field public static final java.lang.String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming"; } + public class NetworkRegistrationState implements android.os.Parcelable { + ctor public NetworkRegistrationState(int, int, int, int, int, boolean, int[], android.telephony.CellIdentity); + ctor protected NetworkRegistrationState(android.os.Parcel); + method public int describeContents(); + method public int getAccessNetworkTechnology(); + method public int[] getAvailableServices(); + method public int getDomain(); + method public int getRegState(); + method public int getTransportType(); + method public boolean isEmergencyEnabled(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + field public static final int DOMAIN_CS = 1; // 0x1 + field public static final int DOMAIN_PS = 2; // 0x2 + field public static final int REG_STATE_DENIED = 3; // 0x3 + field public static final int REG_STATE_HOME = 1; // 0x1 + field public static final int REG_STATE_NOT_REG_NOT_SEARCHING = 0; // 0x0 + field public static final int REG_STATE_NOT_REG_SEARCHING = 2; // 0x2 + field public static final int REG_STATE_ROAMING = 5; // 0x5 + field public static final int REG_STATE_UNKNOWN = 4; // 0x4 + field public static final int SERVICE_TYPE_DATA = 2; // 0x2 + field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5 + field public static final int SERVICE_TYPE_SMS = 3; // 0x3 + field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4 + field public static final int SERVICE_TYPE_VOICE = 1; // 0x1 + } + + public abstract class NetworkService extends android.app.Service { + method protected abstract android.telephony.NetworkService.NetworkServiceProvider createNetworkServiceProvider(int); + field public static final java.lang.String NETWORK_SERVICE_EXTRA_SLOT_ID = "android.telephony.extra.SLOT_ID"; + field public static final java.lang.String NETWORK_SERVICE_INTERFACE = "android.telephony.NetworkService"; + } + + public class NetworkService.NetworkServiceProvider { + ctor public NetworkService.NetworkServiceProvider(int); + method public void getNetworkRegistrationState(int, android.telephony.NetworkServiceCallback); + method public final int getSlotId(); + method public final void notifyNetworkRegistrationStateChanged(); + method protected void onDestroy(); + } + + public class NetworkServiceCallback { + method public void onGetNetworkRegistrationStateComplete(int, android.telephony.NetworkRegistrationState); + field public static final int RESULT_ERROR_BUSY = 3; // 0x3 + field public static final int RESULT_ERROR_FAILED = 5; // 0x5 + field public static final int RESULT_ERROR_ILLEGAL_STATE = 4; // 0x4 + field public static final int RESULT_ERROR_INVALID_ARG = 2; // 0x2 + field public static final int RESULT_ERROR_UNSUPPORTED = 1; // 0x1 + field public static final int RESULT_SUCCESS = 0; // 0x0 + } + + public class ServiceState implements android.os.Parcelable { + method public java.util.List getNetworkRegistrationStates(); + method public java.util.List getNetworkRegistrationStates(int); + method public android.telephony.NetworkRegistrationState getNetworkRegistrationStates(int, int); + } + public final class SmsManager { method public void sendMultipartTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.util.List, java.util.List, java.util.List); method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent); diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java index 703f96d0fe741..7cd16128b8955 100644 --- a/telephony/java/android/telephony/AccessNetworkConstants.java +++ b/telephony/java/android/telephony/AccessNetworkConstants.java @@ -24,6 +24,7 @@ import android.annotation.SystemApi; public final class AccessNetworkConstants { public static final class AccessNetworkType { + public static final int UNKNOWN = 0; public static final int GERAN = 1; public static final int UTRAN = 2; public static final int EUTRAN = 3; diff --git a/telephony/java/android/telephony/INetworkService.aidl b/telephony/java/android/telephony/INetworkService.aidl new file mode 100644 index 0000000000000..d810d58a59da5 --- /dev/null +++ b/telephony/java/android/telephony/INetworkService.aidl @@ -0,0 +1,29 @@ +/* + * Copyright 2017 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; + +import android.telephony.INetworkServiceCallback; + +/** + * {@hide} + */ +oneway interface INetworkService +{ + void getNetworkRegistrationState(int domain, INetworkServiceCallback callback); + void registerForNetworkRegistrationStateChanged(INetworkServiceCallback callback); + void unregisterForNetworkRegistrationStateChanged(INetworkServiceCallback callback); +} diff --git a/telephony/java/android/telephony/INetworkServiceCallback.aidl b/telephony/java/android/telephony/INetworkServiceCallback.aidl new file mode 100644 index 0000000000000..520598ff91440 --- /dev/null +++ b/telephony/java/android/telephony/INetworkServiceCallback.aidl @@ -0,0 +1,29 @@ +/* + * Copyright 2017 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; + +import android.telephony.NetworkRegistrationState; + +/** + * Network service call back interface + * @hide + */ +oneway interface INetworkServiceCallback +{ + void onGetNetworkRegistrationStateComplete(int result, in NetworkRegistrationState state); + void onNetworkStateChanged(); +} diff --git a/telephony/java/android/telephony/NetworkRegistrationState.aidl b/telephony/java/android/telephony/NetworkRegistrationState.aidl new file mode 100644 index 0000000000000..98cba77206033 --- /dev/null +++ b/telephony/java/android/telephony/NetworkRegistrationState.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2017 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; + +parcelable NetworkRegistrationState; diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java new file mode 100644 index 0000000000000..e0510694d4adf --- /dev/null +++ b/telephony/java/android/telephony/NetworkRegistrationState.java @@ -0,0 +1,258 @@ +/* + * Copyright 2017 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; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.Objects; + +/** + * Description of a mobile network registration state + * @hide + */ +@SystemApi +public class NetworkRegistrationState implements Parcelable { + /** + * Network domain + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "DOMAIN_", value = {DOMAIN_CS, DOMAIN_PS}) + public @interface Domain {} + + /** Circuit switching domain */ + public static final int DOMAIN_CS = 1; + /** Packet switching domain */ + public static final int DOMAIN_PS = 2; + + /** + * Registration state + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "REG_STATE_", + value = {REG_STATE_NOT_REG_NOT_SEARCHING, REG_STATE_HOME, REG_STATE_NOT_REG_SEARCHING, + REG_STATE_DENIED, REG_STATE_UNKNOWN, REG_STATE_ROAMING}) + public @interface RegState {} + + /** Not registered. The device is not currently searching a new operator to register */ + public static final int REG_STATE_NOT_REG_NOT_SEARCHING = 0; + /** Registered on home network */ + public static final int REG_STATE_HOME = 1; + /** Not registered. The device is currently searching a new operator to register */ + public static final int REG_STATE_NOT_REG_SEARCHING = 2; + /** Registration denied */ + public static final int REG_STATE_DENIED = 3; + /** Registration state is unknown */ + public static final int REG_STATE_UNKNOWN = 4; + /** Registered on roaming network */ + public static final int REG_STATE_ROAMING = 5; + + /** + * Supported service type + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "SERVICE_TYPE_", + value = {SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS, SERVICE_TYPE_VIDEO, + SERVICE_TYPE_EMERGENCY}) + public @interface ServiceType {} + + public static final int SERVICE_TYPE_VOICE = 1; + public static final int SERVICE_TYPE_DATA = 2; + public static final int SERVICE_TYPE_SMS = 3; + public static final int SERVICE_TYPE_VIDEO = 4; + public static final int SERVICE_TYPE_EMERGENCY = 5; + + /** {@link AccessNetworkConstants.TransportType}*/ + private final int mTransportType; + + @Domain + private final int mDomain; + + @RegState + private final int mRegState; + + private final int mAccessNetworkTechnology; + + private final int mReasonForDenial; + + private final boolean mEmergencyOnly; + + private final int[] mAvailableServices; + + @Nullable + private final CellIdentity mCellIdentity; + + + /** + * @param transportType Transport type. Must be {@link AccessNetworkConstants.TransportType} + * @param domain Network domain. Must be DOMAIN_CS or DOMAIN_PS. + * @param regState Network registration state. + * @param accessNetworkTechnology See TelephonyManager NETWORK_TYPE_XXXX. + * @param reasonForDenial Reason for denial if the registration state is DENIED. + * @param availableServices The supported service. + * @param cellIdentity The identity representing a unique cell + */ + public NetworkRegistrationState(int transportType, int domain, int regState, + int accessNetworkTechnology, int reasonForDenial, boolean emergencyOnly, + int[] availableServices, @Nullable CellIdentity cellIdentity) { + mTransportType = transportType; + mDomain = domain; + mRegState = regState; + mAccessNetworkTechnology = accessNetworkTechnology; + mReasonForDenial = reasonForDenial; + mAvailableServices = availableServices; + mCellIdentity = cellIdentity; + mEmergencyOnly = emergencyOnly; + } + + protected NetworkRegistrationState(Parcel source) { + mTransportType = source.readInt(); + mDomain = source.readInt(); + mRegState = source.readInt(); + mAccessNetworkTechnology = source.readInt(); + mReasonForDenial = source.readInt(); + mEmergencyOnly = source.readBoolean(); + mAvailableServices = source.createIntArray(); + mCellIdentity = source.readParcelable(CellIdentity.class.getClassLoader()); + } + + /** + * @return The transport type. + */ + public int getTransportType() { return mTransportType; } + + /** + * @return The network domain. + */ + public @Domain int getDomain() { return mDomain; } + + /** + * @return The registration state. + */ + public @RegState int getRegState() { + return mRegState; + } + + /** + * @return Whether emergency is enabled. + */ + public boolean isEmergencyEnabled() { return mEmergencyOnly; } + + /** + * @return List of available service types. + */ + public int[] getAvailableServices() { return mAvailableServices; } + + /** + * @return The access network technology. Must be one of TelephonyManager.NETWORK_TYPE_XXXX. + */ + public int getAccessNetworkTechnology() { + return mAccessNetworkTechnology; + } + + @Override + public int describeContents() { + return 0; + } + + private static String regStateToString(int regState) { + switch (regState) { + case REG_STATE_NOT_REG_NOT_SEARCHING: return "NOT_REG_NOT_SEARCHING"; + case REG_STATE_HOME: return "HOME"; + case REG_STATE_NOT_REG_SEARCHING: return "NOT_REG_SEARCHING"; + case REG_STATE_DENIED: return "DENIED"; + case REG_STATE_UNKNOWN: return "UNKNOWN"; + case REG_STATE_ROAMING: return "ROAMING"; + } + return "Unknown reg state " + regState; + } + + @Override + public String toString() { + return new StringBuilder("NetworkRegistrationState{") + .append("transportType=").append(mTransportType) + .append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS") + .append(" regState=").append(regStateToString(mRegState)) + .append(" accessNetworkTechnology=") + .append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology)) + .append(" reasonForDenial=").append(mReasonForDenial) + .append(" emergencyEnabled=").append(mEmergencyOnly) + .append(" supportedServices=").append(mAvailableServices) + .append(" cellIdentity=").append(mCellIdentity) + .append("}").toString(); + } + + @Override + public int hashCode() { + return Objects.hash(mTransportType, mDomain, mRegState, mAccessNetworkTechnology, + mReasonForDenial, mEmergencyOnly, mAvailableServices, mCellIdentity); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || !(o instanceof NetworkRegistrationState)) { + return false; + } + + NetworkRegistrationState other = (NetworkRegistrationState) o; + return mTransportType == other.mTransportType + && mDomain == other.mDomain + && mRegState == other.mRegState + && mAccessNetworkTechnology == other.mAccessNetworkTechnology + && mReasonForDenial == other.mReasonForDenial + && mEmergencyOnly == other.mEmergencyOnly + && (mAvailableServices == other.mAvailableServices + || Arrays.equals(mAvailableServices, other.mAvailableServices)) + && mCellIdentity == other.mCellIdentity; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mTransportType); + dest.writeInt(mDomain); + dest.writeInt(mRegState); + dest.writeInt(mAccessNetworkTechnology); + dest.writeInt(mReasonForDenial); + dest.writeBoolean(mEmergencyOnly); + dest.writeIntArray(mAvailableServices); + dest.writeParcelable(mCellIdentity, 0); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public NetworkRegistrationState createFromParcel(Parcel source) { + return new NetworkRegistrationState(source); + } + + @Override + public NetworkRegistrationState[] newArray(int size) { + return new NetworkRegistrationState[size]; + } + }; +} diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java new file mode 100644 index 0000000000000..6b3584c1309ff --- /dev/null +++ b/telephony/java/android/telephony/NetworkService.java @@ -0,0 +1,314 @@ +/* + * Copyright 2017 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; + +import android.annotation.CallSuper; +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.util.SparseArray; + +import java.util.ArrayList; +import java.util.List; + +/** + * Base class of network service. Services that extend NetworkService must register the service in + * their AndroidManifest to be detected by the framework. They must be protected by the permission + * "android.permission.BIND_NETWORK_SERVICE". The network service definition in the manifest must + * follow the following format: + * ... + * + * + * + * + * + * @hide + */ +@SystemApi +public abstract class NetworkService extends Service { + + private final String TAG = NetworkService.class.getSimpleName(); + + public static final String NETWORK_SERVICE_INTERFACE = "android.telephony.NetworkService"; + public static final String NETWORK_SERVICE_EXTRA_SLOT_ID = "android.telephony.extra.SLOT_ID"; + + private static final int NETWORK_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE = 1; + private static final int NETWORK_SERVICE_GET_REGISTRATION_STATE = 2; + private static final int NETWORK_SERVICE_REGISTER_FOR_STATE_CHANGE = 3; + private static final int NETWORK_SERVICE_UNREGISTER_FOR_STATE_CHANGE = 4; + private static final int NETWORK_SERVICE_INDICATION_NETWORK_STATE_CHANGED = 5; + + + private final HandlerThread mHandlerThread; + + private final NetworkServiceHandler mHandler; + + private final SparseArray mServiceMap = new SparseArray<>(); + + private final SparseArray mBinderMap = new SparseArray<>(); + + /** + * The abstract class of the actual network service implementation. The network service provider + * must extend this class to support network connection. Note that each instance of network + * service is associated with one physical SIM slot. + */ + public class NetworkServiceProvider { + private final int mSlotId; + + private final List + mNetworkRegistrationStateChangedCallbacks = new ArrayList<>(); + + public NetworkServiceProvider(int slotId) { + mSlotId = slotId; + } + + /** + * @return SIM slot id the network service associated with. + */ + public final int getSlotId() { + return mSlotId; + } + + /** + * API to get network registration state. The result will be passed to the callback. + * @param domain + * @param callback + * @return SIM slot id the network service associated with. + */ + public void getNetworkRegistrationState(int domain, NetworkServiceCallback callback) { + callback.onGetNetworkRegistrationStateComplete( + NetworkServiceCallback.RESULT_ERROR_UNSUPPORTED, null); + } + + public final void notifyNetworkRegistrationStateChanged() { + mHandler.obtainMessage(NETWORK_SERVICE_INDICATION_NETWORK_STATE_CHANGED, + mSlotId, 0, null).sendToTarget(); + } + + private void registerForStateChanged(INetworkServiceCallback callback) { + synchronized (mNetworkRegistrationStateChangedCallbacks) { + mNetworkRegistrationStateChangedCallbacks.add(callback); + } + } + + private void unregisterForStateChanged(INetworkServiceCallback callback) { + synchronized (mNetworkRegistrationStateChangedCallbacks) { + mNetworkRegistrationStateChangedCallbacks.remove(callback); + } + } + + private void notifyStateChangedToCallbacks() { + for (INetworkServiceCallback callback : mNetworkRegistrationStateChangedCallbacks) { + try { + callback.onNetworkStateChanged(); + } catch (RemoteException exception) { + // Doing nothing. + } + } + } + + /** + * Called when the instance of network service is destroyed (e.g. got unbind or binder died). + */ + @CallSuper + protected void onDestroy() { + mNetworkRegistrationStateChangedCallbacks.clear(); + } + } + + private class NetworkServiceHandler extends Handler { + + NetworkServiceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message message) { + final int slotId = message.arg1; + final INetworkServiceCallback callback = (INetworkServiceCallback) message.obj; + NetworkServiceProvider service; + + synchronized (mServiceMap) { + service = mServiceMap.get(slotId); + } + + switch (message.what) { + case NETWORK_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE: + service = createNetworkServiceProvider(message.arg1); + if (service != null) { + mServiceMap.put(slotId, service); + } + break; + case NETWORK_SERVICE_GET_REGISTRATION_STATE: + if (service == null) break; + int domainId = message.arg2; + service.getNetworkRegistrationState(domainId, + new NetworkServiceCallback(callback)); + + break; + case NETWORK_SERVICE_REGISTER_FOR_STATE_CHANGE: + if (service == null) break; + service.registerForStateChanged(callback); + break; + case NETWORK_SERVICE_UNREGISTER_FOR_STATE_CHANGE: + if (service == null) break; + service.unregisterForStateChanged(callback); + break; + case NETWORK_SERVICE_INDICATION_NETWORK_STATE_CHANGED: + if (service == null) break; + service.notifyStateChangedToCallbacks(); + break; + default: + break; + } + } + } + + /** @hide */ + protected NetworkService() { + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + + mHandler = new NetworkServiceHandler(mHandlerThread.getLooper()); + log("network service created"); + } + + /** + * Create the instance of {@link NetworkServiceProvider}. Network service provider must override + * this method to facilitate the creation of {@link NetworkServiceProvider} instances. The system + * will call this method after binding the network service for each active SIM slot id. + * + * @param slotId SIM slot id the network service associated with. + * @return Network service object + */ + protected abstract NetworkServiceProvider createNetworkServiceProvider(int slotId); + + /** @hide */ + @Override + public IBinder onBind(Intent intent) { + if (intent == null || !NETWORK_SERVICE_INTERFACE.equals(intent.getAction())) { + loge("Unexpected intent " + intent); + return null; + } + + int slotId = intent.getIntExtra( + NETWORK_SERVICE_EXTRA_SLOT_ID, SubscriptionManager.INVALID_SIM_SLOT_INDEX); + + if (!SubscriptionManager.isValidSlotIndex(slotId)) { + loge("Invalid slot id " + slotId); + return null; + } + + log("onBind: slot id=" + slotId); + + INetworkServiceWrapper binder = mBinderMap.get(slotId); + if (binder == null) { + Message msg = mHandler.obtainMessage( + NETWORK_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE); + msg.arg1 = slotId; + msg.sendToTarget(); + + binder = new INetworkServiceWrapper(slotId); + mBinderMap.put(slotId, binder); + } + + return binder; + } + + /** @hide */ + @Override + public boolean onUnbind(Intent intent) { + int slotId = intent.getIntExtra(NETWORK_SERVICE_EXTRA_SLOT_ID, + SubscriptionManager.INVALID_SIM_SLOT_INDEX); + if (mBinderMap.get(slotId) != null) { + NetworkServiceProvider serviceImpl; + synchronized (mServiceMap) { + serviceImpl = mServiceMap.get(slotId); + } + // We assume only one component might bind to the service. So if onUnbind is ever + // called, we destroy the serviceImpl. + if (serviceImpl != null) { + serviceImpl.onDestroy(); + } + mBinderMap.remove(slotId); + } + + return false; + } + + /** @hide */ + @Override + public void onDestroy() { + synchronized (mServiceMap) { + for (int i = 0; i < mServiceMap.size(); i++) { + NetworkServiceProvider serviceImpl = mServiceMap.get(i); + if (serviceImpl != null) { + serviceImpl.onDestroy(); + } + } + mServiceMap.clear(); + } + + mHandlerThread.quit(); + } + + /** + * A wrapper around INetworkService that forwards calls to implementations of + * {@link NetworkService}. + */ + private class INetworkServiceWrapper extends INetworkService.Stub { + + private final int mSlotId; + + INetworkServiceWrapper(int slotId) { + mSlotId = slotId; + } + + @Override + public void getNetworkRegistrationState(int domain, INetworkServiceCallback callback) { + mHandler.obtainMessage(NETWORK_SERVICE_GET_REGISTRATION_STATE, mSlotId, + domain, callback).sendToTarget(); + } + + @Override + public void registerForNetworkRegistrationStateChanged(INetworkServiceCallback callback) { + mHandler.obtainMessage(NETWORK_SERVICE_REGISTER_FOR_STATE_CHANGE, mSlotId, + 0, callback).sendToTarget(); + } + + @Override + public void unregisterForNetworkRegistrationStateChanged(INetworkServiceCallback callback) { + mHandler.obtainMessage(NETWORK_SERVICE_UNREGISTER_FOR_STATE_CHANGE, mSlotId, + 0, callback).sendToTarget(); + } + } + + private final void log(String s) { + Rlog.d(TAG, s); + } + + private final void loge(String s) { + Rlog.e(TAG, s); + } +} \ No newline at end of file diff --git a/telephony/java/android/telephony/NetworkServiceCallback.java b/telephony/java/android/telephony/NetworkServiceCallback.java new file mode 100644 index 0000000000000..92ebf367025ca --- /dev/null +++ b/telephony/java/android/telephony/NetworkServiceCallback.java @@ -0,0 +1,88 @@ +/* + * Copyright 2017 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; + +import android.annotation.IntDef; +import android.annotation.SystemApi; +import android.os.RemoteException; +import android.telephony.NetworkService.NetworkServiceProvider; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; + +/** + * Network service callback. Object of this class is passed to NetworkServiceProvider upon + * calling getNetworkRegistrationState, to receive asynchronous feedback from NetworkServiceProvider + * upon onGetNetworkRegistrationStateComplete. It's like a wrapper of INetworkServiceCallback + * because INetworkServiceCallback can't be a parameter type in public APIs. + * + * @hide + */ +@SystemApi +public class NetworkServiceCallback { + + private static final String mTag = NetworkServiceCallback.class.getSimpleName(); + + /** + * Result of network requests + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({RESULT_SUCCESS, RESULT_ERROR_UNSUPPORTED, RESULT_ERROR_INVALID_ARG, RESULT_ERROR_BUSY, + RESULT_ERROR_ILLEGAL_STATE, RESULT_ERROR_FAILED}) + public @interface Result {} + + /** Request is completed successfully */ + public static final int RESULT_SUCCESS = 0; + /** Request is not support */ + public static final int RESULT_ERROR_UNSUPPORTED = 1; + /** Request contains invalid arguments */ + public static final int RESULT_ERROR_INVALID_ARG = 2; + /** Service is busy */ + public static final int RESULT_ERROR_BUSY = 3; + /** Request sent in illegal state */ + public static final int RESULT_ERROR_ILLEGAL_STATE = 4; + /** Request failed */ + public static final int RESULT_ERROR_FAILED = 5; + + private final WeakReference mCallback; + + /** @hide */ + public NetworkServiceCallback(INetworkServiceCallback callback) { + mCallback = new WeakReference<>(callback); + } + + /** + * Called to indicate result of + * {@link NetworkServiceProvider#getNetworkRegistrationState(int, NetworkServiceCallback)} + * + * @param result Result status like {@link NetworkServiceCallback#RESULT_SUCCESS} or + * {@link NetworkServiceCallback#RESULT_ERROR_UNSUPPORTED} + * @param state The state information to be returned to callback. + */ + public void onGetNetworkRegistrationStateComplete(int result, NetworkRegistrationState state) { + INetworkServiceCallback callback = mCallback.get(); + if (callback != null) { + try { + callback.onGetNetworkRegistrationStateComplete(result, state); + } catch (RemoteException e) { + Rlog.e(mTag, "Failed to onGetNetworkRegistrationStateComplete on the remote"); + } + } + } +} \ No newline at end of file diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index d4b4b88081d6b..77706e8fc54f8 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.IntDef; +import android.annotation.SystemApi; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -25,6 +26,9 @@ import android.text.TextUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + /** * Contains phone state and service related information. * @@ -286,6 +290,8 @@ public class ServiceState implements Parcelable { * Reference: 3GPP TS 36.104 5.4.3 */ private int mLteEarfcnRsrpBoost = 0; + private List mNetworkRegistrationStates = new ArrayList<>(); + /** * get String description of roaming type * @hide @@ -366,6 +372,7 @@ public class ServiceState implements Parcelable { mIsDataRoamingFromRegistration = s.mIsDataRoamingFromRegistration; mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation; mLteEarfcnRsrpBoost = s.mLteEarfcnRsrpBoost; + mNetworkRegistrationStates = new ArrayList<>(s.mNetworkRegistrationStates); } /** @@ -396,6 +403,8 @@ public class ServiceState implements Parcelable { mIsDataRoamingFromRegistration = in.readInt() != 0; mIsUsingCarrierAggregation = in.readInt() != 0; mLteEarfcnRsrpBoost = in.readInt(); + mNetworkRegistrationStates = new ArrayList<>(); + in.readList(mNetworkRegistrationStates, NetworkRegistrationState.class.getClassLoader()); } public void writeToParcel(Parcel out, int flags) { @@ -423,6 +432,7 @@ public class ServiceState implements Parcelable { out.writeInt(mIsDataRoamingFromRegistration ? 1 : 0); out.writeInt(mIsUsingCarrierAggregation ? 1 : 0); out.writeInt(mLteEarfcnRsrpBoost); + out.writeList(mNetworkRegistrationStates); } public int describeContents() { @@ -751,13 +761,14 @@ public class ServiceState implements Parcelable { s.mCdmaDefaultRoamingIndicator) && mIsEmergencyOnly == s.mIsEmergencyOnly && mIsDataRoamingFromRegistration == s.mIsDataRoamingFromRegistration - && mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation); + && mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation) + && mNetworkRegistrationStates.containsAll(s.mNetworkRegistrationStates); } /** * Convert radio technology to String * - * @param radioTechnology + * @param rt radioTechnology * @return String representation of the RAT * * @hide @@ -884,6 +895,7 @@ public class ServiceState implements Parcelable { .append(", mIsDataRoamingFromRegistration=").append(mIsDataRoamingFromRegistration) .append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation) .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost) + .append(", mNetworkRegistrationStates=").append(mNetworkRegistrationStates) .append("}").toString(); } @@ -913,6 +925,7 @@ public class ServiceState implements Parcelable { mIsDataRoamingFromRegistration = false; mIsUsingCarrierAggregation = false; mLteEarfcnRsrpBoost = 0; + mNetworkRegistrationStates = new ArrayList<>(); } public void setStateOutOfService() { @@ -1394,4 +1407,52 @@ public class ServiceState implements Parcelable { return newSs; } + + /** + * Get all of the available network registration states. + * + * @return List of registration states + * @hide + */ + @SystemApi + public List getNetworkRegistrationStates() { + return mNetworkRegistrationStates; + } + + /** + * Get the network registration states with given transport type. + * + * @param transportType The transport type. See {@link AccessNetworkConstants.TransportType} + * @return List of registration states. + * @hide + */ + @SystemApi + public List getNetworkRegistrationStates(int transportType) { + List list = new ArrayList<>(); + for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) { + if (networkRegistrationState.getTransportType() == transportType) { + list.add(networkRegistrationState); + } + } + return list; + } + + /** + * Get the network registration states with given transport type and domain. + * + * @param transportType The transport type. See {@link AccessNetworkConstants.TransportType} + * @param domain The network domain. Must be DOMAIN_CS or DOMAIN_PS. + * @return The matching NetworkRegistrationState. + * @hide + */ + @SystemApi + public NetworkRegistrationState getNetworkRegistrationStates(int transportType, int domain) { + for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) { + if (networkRegistrationState.getTransportType() == transportType + && networkRegistrationState.getDomain() == domain) { + return networkRegistrationState; + } + } + return null; + } }