OSDN Git Service

Added data service interface
authorJack Yu <jackyu@google.com>
Tue, 28 Nov 2017 01:36:29 +0000 (17:36 -0800)
committerJack Yu <jackyu@google.com>
Wed, 17 Jan 2018 17:51:30 +0000 (09:51 -0800)
The interface for mobile data service. This is the base class
for vendor or first party data service provider to implement
the data service for cellular or IWLAN data support.

Test: Manual
bug: 64132030
Change-Id: I3e5f48b88905f4533cac60975802d4da3746e7f8

Android.bp
api/system-current.txt
telephony/java/android/telephony/data/DataService.java [new file with mode: 0644]
telephony/java/android/telephony/data/DataServiceCallback.java [new file with mode: 0644]
telephony/java/android/telephony/data/IDataService.aidl [new file with mode: 0644]
telephony/java/android/telephony/data/IDataServiceCallback.aidl [new file with mode: 0644]

index facc741..f61115a 100644 (file)
@@ -455,6 +455,8 @@ java_library {
         "telecomm/java/com/android/internal/telecom/IInCallService.aidl",
         "telecomm/java/com/android/internal/telecom/ITelecomService.aidl",
         "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/ims/internal/aidl/IImsCallSessionListener.aidl",
         "telephony/java/android/telephony/ims/internal/aidl/IImsCapabilityCallback.aidl",
         "telephony/java/android/telephony/ims/internal/aidl/IImsConfig.aidl",
index aa84f32..282dfaa 100644 (file)
@@ -4123,6 +4123,38 @@ package android.telephony.data {
     field public static final int TYPE_COMMON = 0; // 0x0
   }
 
+  public abstract class DataService extends android.app.Service {
+    method public abstract android.telephony.data.DataService.DataServiceProvider createDataServiceProvider(int);
+    field public static final java.lang.String DATA_SERVICE_EXTRA_SLOT_ID = "android.telephony.data.extra.SLOT_ID";
+    field public static final java.lang.String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService";
+  }
+
+  public class DataService.DataServiceProvider {
+    ctor public DataService.DataServiceProvider(int);
+    method public void deactivateDataCall(int, boolean, boolean, android.telephony.data.DataServiceCallback);
+    method public void getDataCallList(android.telephony.data.DataServiceCallback);
+    method public final int getSlotId();
+    method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>);
+    method protected void onDestroy();
+    method public void setDataProfile(java.util.List<android.telephony.data.DataProfile>, boolean, android.telephony.data.DataServiceCallback);
+    method public void setInitialAttachApn(android.telephony.data.DataProfile, boolean, android.telephony.data.DataServiceCallback);
+    method public void setupDataCall(int, android.telephony.data.DataProfile, boolean, boolean, boolean, android.net.LinkProperties, android.telephony.data.DataServiceCallback);
+  }
+
+  public class DataServiceCallback {
+    method public void onDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>);
+    method public void onDeactivateDataCallComplete(int);
+    method public void onGetDataCallListComplete(int, java.util.List<android.telephony.data.DataCallResponse>);
+    method public void onSetDataProfileComplete(int);
+    method public void onSetInitialAttachApnComplete(int);
+    method public void onSetupDataCallComplete(int, android.telephony.data.DataCallResponse);
+    field public static final int RESULT_ERROR_BUSY = 3; // 0x3
+    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
+  }
+
 }
 
 package android.telephony.ims {
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
new file mode 100644 (file)
index 0000000..ea08175
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * 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.data;
+
+import android.annotation.CallSuper;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.net.LinkProperties;
+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;
+import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class of data service. Services that extend DataService must register the service in
+ * their AndroidManifest to be detected by the framework. They must be protected by the permission
+ * "android.permission.BIND_DATA_SERVICE". The data service definition in the manifest must follow
+ * the following format:
+ * ...
+ * <service android:name=".xxxDataService"
+ *     android:permission="android.permission.BIND_DATA_SERVICE" >
+ *     <intent-filter>
+ *         <action android:name="android.telephony.data.DataService" />
+ *     </intent-filter>
+ * </service>
+ * @hide
+ */
+@SystemApi
+public abstract class DataService extends Service {
+    private static final String TAG = DataService.class.getSimpleName();
+
+    public static final String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService";
+    public static final String DATA_SERVICE_EXTRA_SLOT_ID = "android.telephony.data.extra.SLOT_ID";
+
+    private static final int DATA_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE          = 1;
+    private static final int DATA_SERVICE_REQUEST_SETUP_DATA_CALL                      = 2;
+    private static final int DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL                 = 3;
+    private static final int DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN               = 4;
+    private static final int DATA_SERVICE_REQUEST_SET_DATA_PROFILE                     = 5;
+    private static final int DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST                   = 6;
+    private static final int DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED      = 7;
+    private static final int DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED    = 8;
+    private static final int DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED            = 9;
+
+    private final HandlerThread mHandlerThread;
+
+    private final DataServiceHandler mHandler;
+
+    private final SparseArray<DataServiceProvider> mServiceMap = new SparseArray<>();
+
+    private final SparseArray<IDataServiceWrapper> mBinderMap = new SparseArray<>();
+
+    /**
+     * The abstract class of the actual data service implementation. The data service provider
+     * must extend this class to support data connection. Note that each instance of data service
+     * provider is associated with one physical SIM slot.
+     */
+    public class DataServiceProvider {
+
+        private final int mSlotId;
+
+        private final List<IDataServiceCallback> mDataCallListChangedCallbacks = new ArrayList<>();
+
+        /**
+         * Constructor
+         * @param slotId SIM slot id the data service provider associated with.
+         */
+        public DataServiceProvider(int slotId) {
+            mSlotId = slotId;
+        }
+
+        /**
+         * @return SIM slot id the data service provider associated with.
+         */
+        public final int getSlotId() {
+            return mSlotId;
+        }
+
+        /**
+         * Setup a data connection. The data service provider must implement this method to support
+         * establishing a packet data connection. When completed or error, the service must invoke
+         * the provided callback to notify the platform.
+         *
+         * @param accessNetworkType Access network type that the data call will be established on.
+         * Must be one of {@link AccessNetworkConstants.AccessNetworkType}.
+         * @param dataProfile Data profile used for data call setup. See {@link DataProfile}
+         * @param isRoaming True if the device is data roaming.
+         * @param allowRoaming True if data roaming is allowed by the user.
+         * @param isHandover True if the request is for IWLAN handover.
+         * @param linkProperties If {@code isHandover} is true, this is the link properties of the
+         * existing data connection, otherwise null.
+         * @param callback The result callback for this request.
+         */
+        public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
+                                  boolean allowRoaming, boolean isHandover,
+                                  LinkProperties linkProperties, DataServiceCallback callback) {
+            // The default implementation is to return unsupported.
+            callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null);
+        }
+
+        /**
+         * Deactivate a data connection. The data service provider must implement this method to
+         * support data connection tear down. When completed or error, the service must invoke the
+         * provided callback to notify the platform.
+         *
+         * @param cid Call id returned in the callback of {@link DataServiceProvider#setupDataCall(
+         * int, DataProfile, boolean, boolean, boolean, LinkProperties, DataServiceCallback)}.
+         * @param reasonRadioShutDown True if the deactivate request reason is device shut down.
+         * @param isHandover True if the request is for IWLAN handover.
+         * @param callback The result callback for this request.
+         */
+        public void deactivateDataCall(int cid, boolean reasonRadioShutDown, boolean isHandover,
+                                       DataServiceCallback callback) {
+            // The default implementation is to return unsupported.
+            callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+        }
+
+        /**
+         * Set an APN to initial attach network.
+         *
+         * @param dataProfile Data profile used for data call setup. See {@link DataProfile}.
+         * @param isRoaming True if the device is data roaming.
+         * @param callback The result callback for this request.
+         */
+        public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
+                                        DataServiceCallback callback) {
+            // The default implementation is to return unsupported.
+            callback.onSetInitialAttachApnComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+        }
+
+        /**
+         * Send current carrier's data profiles to the data service for data call setup. This is
+         * only for CDMA carrier that can change the profile through OTA. The data service should
+         * always uses the latest data profile sent by the framework.
+         *
+         * @param dps A list of data profiles.
+         * @param isRoaming True if the device is data roaming.
+         * @param callback The result callback for this request.
+         */
+        public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
+                                   DataServiceCallback callback) {
+            // The default implementation is to return unsupported.
+            callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+        }
+
+        /**
+         * Get the active data call list.
+         *
+         * @param callback The result callback for this request.
+         */
+        public void getDataCallList(DataServiceCallback callback) {
+            // The default implementation is to return unsupported.
+            callback.onGetDataCallListComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null);
+        }
+
+        private void registerForDataCallListChanged(IDataServiceCallback callback) {
+            synchronized (mDataCallListChangedCallbacks) {
+                mDataCallListChangedCallbacks.add(callback);
+            }
+        }
+
+        private void unregisterForDataCallListChanged(IDataServiceCallback callback) {
+            synchronized (mDataCallListChangedCallbacks) {
+                mDataCallListChangedCallbacks.remove(callback);
+            }
+        }
+
+        /**
+         * Notify the system that current data call list changed. Data service must invoke this
+         * method whenever there is any data call status changed.
+         *
+         * @param dataCallList List of the current active data call.
+         */
+        public final void notifyDataCallListChanged(List<DataCallResponse> dataCallList) {
+            synchronized (mDataCallListChangedCallbacks) {
+                for (IDataServiceCallback callback : mDataCallListChangedCallbacks) {
+                    mHandler.obtainMessage(DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED, mSlotId,
+                            0, new DataCallListChangedIndication(dataCallList, callback))
+                            .sendToTarget();
+                }
+            }
+        }
+
+        /**
+         * Called when the instance of data service is destroyed (e.g. got unbind or binder died).
+         */
+        @CallSuper
+        protected void onDestroy() {
+            mDataCallListChangedCallbacks.clear();
+        }
+    }
+
+    private static final class SetupDataCallRequest {
+        public final int accessNetworkType;
+        public final DataProfile dataProfile;
+        public final boolean isRoaming;
+        public final boolean allowRoaming;
+        public final boolean isHandover;
+        public final LinkProperties linkProperties;
+        public final IDataServiceCallback callback;
+        SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
+                             boolean allowRoaming, boolean isHandover,
+                             LinkProperties linkProperties, IDataServiceCallback callback) {
+            this.accessNetworkType = accessNetworkType;
+            this.dataProfile = dataProfile;
+            this.isRoaming = isRoaming;
+            this.allowRoaming = allowRoaming;
+            this.linkProperties = linkProperties;
+            this.isHandover = isHandover;
+            this.callback = callback;
+        }
+    }
+
+    private static final class DeactivateDataCallRequest {
+        public final int cid;
+        public final boolean reasonRadioShutDown;
+        public final boolean isHandover;
+        public final IDataServiceCallback callback;
+        DeactivateDataCallRequest(int cid, boolean reasonRadioShutDown, boolean isHandover,
+                                  IDataServiceCallback callback) {
+            this.cid = cid;
+            this.reasonRadioShutDown = reasonRadioShutDown;
+            this.isHandover = isHandover;
+            this.callback = callback;
+        }
+    }
+
+    private static final class SetInitialAttachApnRequest {
+        public final DataProfile dataProfile;
+        public final boolean isRoaming;
+        public final IDataServiceCallback callback;
+        SetInitialAttachApnRequest(DataProfile dataProfile, boolean isRoaming,
+                                   IDataServiceCallback callback) {
+            this.dataProfile = dataProfile;
+            this.isRoaming = isRoaming;
+            this.callback = callback;
+        }
+    }
+
+    private static final class SetDataProfileRequest {
+        public final List<DataProfile> dps;
+        public final boolean isRoaming;
+        public final IDataServiceCallback callback;
+        SetDataProfileRequest(List<DataProfile> dps, boolean isRoaming,
+                              IDataServiceCallback callback) {
+            this.dps = dps;
+            this.isRoaming = isRoaming;
+            this.callback = callback;
+        }
+    }
+
+    private static final class DataCallListChangedIndication {
+        public final List<DataCallResponse> dataCallList;
+        public final IDataServiceCallback callback;
+        DataCallListChangedIndication(List<DataCallResponse> dataCallList,
+                                      IDataServiceCallback callback) {
+            this.dataCallList = dataCallList;
+            this.callback = callback;
+        }
+    }
+
+    private class DataServiceHandler extends Handler {
+
+        DataServiceHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            IDataServiceCallback callback;
+            final int slotId = message.arg1;
+            DataServiceProvider service;
+
+            synchronized (mServiceMap) {
+                service = mServiceMap.get(slotId);
+            }
+
+            switch (message.what) {
+                case DATA_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE:
+                    service = createDataServiceProvider(message.arg1);
+                    if (service != null) {
+                        mServiceMap.put(slotId, service);
+                    }
+                    break;
+                case DATA_SERVICE_REQUEST_SETUP_DATA_CALL:
+                    if (service == null) break;
+                    SetupDataCallRequest setupDataCallRequest = (SetupDataCallRequest) message.obj;
+                    service.setupDataCall(setupDataCallRequest.accessNetworkType,
+                            setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming,
+                            setupDataCallRequest.allowRoaming, setupDataCallRequest.isHandover,
+                            setupDataCallRequest.linkProperties,
+                            new DataServiceCallback(setupDataCallRequest.callback));
+
+                    break;
+                case DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL:
+                    if (service == null) break;
+                    DeactivateDataCallRequest deactivateDataCallRequest =
+                            (DeactivateDataCallRequest) message.obj;
+                    service.deactivateDataCall(deactivateDataCallRequest.cid,
+                            deactivateDataCallRequest.reasonRadioShutDown,
+                            deactivateDataCallRequest.isHandover,
+                            new DataServiceCallback(deactivateDataCallRequest.callback));
+                    break;
+                case DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN:
+                    if (service == null) break;
+                    SetInitialAttachApnRequest setInitialAttachApnRequest =
+                            (SetInitialAttachApnRequest) message.obj;
+                    service.setInitialAttachApn(setInitialAttachApnRequest.dataProfile,
+                            setInitialAttachApnRequest.isRoaming,
+                            new DataServiceCallback(setInitialAttachApnRequest.callback));
+                    break;
+                case DATA_SERVICE_REQUEST_SET_DATA_PROFILE:
+                    if (service == null) break;
+                    SetDataProfileRequest setDataProfileRequest =
+                            (SetDataProfileRequest) message.obj;
+                    service.setDataProfile(setDataProfileRequest.dps,
+                            setDataProfileRequest.isRoaming,
+                            new DataServiceCallback(setDataProfileRequest.callback));
+                    break;
+                case DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST:
+                    if (service == null) break;
+
+                    service.getDataCallList(new DataServiceCallback(
+                            (IDataServiceCallback) message.obj));
+                    break;
+                case DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED:
+                    if (service == null) break;
+                    service.registerForDataCallListChanged((IDataServiceCallback) message.obj);
+                    break;
+                case DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED:
+                    if (service == null) break;
+                    callback = (IDataServiceCallback) message.obj;
+                    service.unregisterForDataCallListChanged(callback);
+                    break;
+                case DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED:
+                    if (service == null) break;
+                    DataCallListChangedIndication indication =
+                            (DataCallListChangedIndication) message.obj;
+                    try {
+                        indication.callback.onDataCallListChanged(indication.dataCallList);
+                    } catch (RemoteException e) {
+                        loge("Failed to call onDataCallListChanged. " + e);
+                    }
+                    break;
+            }
+        }
+    }
+
+    private DataService() {
+        mHandlerThread = new HandlerThread(TAG);
+        mHandlerThread.start();
+
+        mHandler = new DataServiceHandler(mHandlerThread.getLooper());
+        log("Data service created");
+    }
+
+    /**
+     * Create the instance of {@link DataServiceProvider}. Data service provider must override
+     * this method to facilitate the creation of {@link DataServiceProvider} instances. The system
+     * will call this method after binding the data service for each active SIM slot id.
+     *
+     * @param slotId SIM slot id the data service associated with.
+     * @return Data service object
+     */
+    public abstract DataServiceProvider createDataServiceProvider(int slotId);
+
+    /** @hide */
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (intent == null || !DATA_SERVICE_INTERFACE.equals(intent.getAction())) {
+            loge("Unexpected intent " + intent);
+            return null;
+        }
+
+        int slotId = intent.getIntExtra(
+                DATA_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);
+
+        IDataServiceWrapper binder = mBinderMap.get(slotId);
+        if (binder == null) {
+            Message msg = mHandler.obtainMessage(DATA_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE);
+            msg.arg1 = slotId;
+            msg.sendToTarget();
+
+            binder = new IDataServiceWrapper(slotId);
+            mBinderMap.put(slotId, binder);
+        }
+
+        return binder;
+    }
+
+    /** @hide */
+    @Override
+    public boolean onUnbind(Intent intent) {
+        int slotId = intent.getIntExtra(DATA_SERVICE_EXTRA_SLOT_ID,
+                SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+        if (mBinderMap.get(slotId) != null) {
+            DataServiceProvider serviceImpl;
+            synchronized (mServiceMap) {
+                serviceImpl = mServiceMap.get(slotId);
+            }
+            if (serviceImpl != null) {
+                serviceImpl.onDestroy();
+            }
+            mBinderMap.remove(slotId);
+        }
+
+        // If all clients unbinds, quit the handler thread
+        if (mBinderMap.size() == 0) {
+            mHandlerThread.quit();
+        }
+
+        return false;
+    }
+
+    /** @hide */
+    @Override
+    public void onDestroy() {
+        synchronized (mServiceMap) {
+            for (int i = 0; i < mServiceMap.size(); i++) {
+                DataServiceProvider serviceImpl = mServiceMap.get(i);
+                if (serviceImpl != null) {
+                    serviceImpl.onDestroy();
+                }
+            }
+            mServiceMap.clear();
+        }
+
+        mHandlerThread.quit();
+    }
+
+    /**
+     * A wrapper around IDataService that forwards calls to implementations of {@link DataService}.
+     */
+    private class IDataServiceWrapper extends IDataService.Stub {
+
+        private final int mSlotId;
+
+        IDataServiceWrapper(int slotId) {
+            mSlotId = slotId;
+        }
+
+        @Override
+        public void setupDataCall(int accessNetworkType, DataProfile dataProfile,
+                                  boolean isRoaming, boolean allowRoaming, boolean isHandover,
+                                  LinkProperties linkProperties, IDataServiceCallback callback) {
+            mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, mSlotId, 0,
+                    new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming,
+                            allowRoaming, isHandover, linkProperties, callback))
+                    .sendToTarget();
+        }
+
+        @Override
+        public void deactivateDataCall(int cid, boolean reasonRadioShutDown, boolean isHandover,
+                                       IDataServiceCallback callback) {
+            mHandler.obtainMessage(DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL, mSlotId, 0,
+                    new DeactivateDataCallRequest(cid, reasonRadioShutDown, isHandover, callback))
+                    .sendToTarget();
+        }
+
+        @Override
+        public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
+                                        IDataServiceCallback callback) {
+            mHandler.obtainMessage(DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN, mSlotId, 0,
+                    new SetInitialAttachApnRequest(dataProfile, isRoaming, callback))
+                    .sendToTarget();
+        }
+
+        @Override
+        public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
+                                   IDataServiceCallback callback) {
+            mHandler.obtainMessage(DATA_SERVICE_REQUEST_SET_DATA_PROFILE, mSlotId, 0,
+                    new SetDataProfileRequest(dps, isRoaming, callback)).sendToTarget();
+        }
+
+        @Override
+        public void getDataCallList(IDataServiceCallback callback) {
+            mHandler.obtainMessage(DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST, mSlotId, 0,
+                    callback).sendToTarget();
+        }
+
+        @Override
+        public void registerForDataCallListChanged(IDataServiceCallback callback) {
+            if (callback == null) {
+                loge("Callback is null");
+                return;
+            }
+            mHandler.obtainMessage(DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED, mSlotId,
+                    0, callback).sendToTarget();
+        }
+
+        @Override
+        public void unregisterForDataCallListChanged(IDataServiceCallback callback) {
+            if (callback == null) {
+                loge("Callback is null");
+                return;
+            }
+            mHandler.obtainMessage(DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED, mSlotId,
+                    0, callback).sendToTarget();
+        }
+    }
+
+    private void log(String s) {
+        Rlog.d(TAG, s);
+    }
+
+    private void loge(String s) {
+        Rlog.e(TAG, s);
+    }
+}
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
new file mode 100644 (file)
index 0000000..b6a81f9
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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.data;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+import android.telephony.Rlog;
+import android.telephony.data.DataService.DataServiceProvider;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+/**
+ * Data service callback, which is for bound data service to invoke for solicited and unsolicited
+ * response. The caller is responsible to create a callback object for each single asynchronous
+ * request.
+ *
+ * @hide
+ */
+@SystemApi
+public class DataServiceCallback {
+
+    private static final String mTag = DataServiceCallback.class.getSimpleName();
+
+    /**
+     * Result of data requests
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({RESULT_SUCCESS, RESULT_ERROR_UNSUPPORTED, RESULT_ERROR_INVALID_ARG, RESULT_ERROR_BUSY,
+            RESULT_ERROR_ILLEGAL_STATE})
+    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;
+
+    private final WeakReference<IDataServiceCallback> mCallback;
+
+    /** @hide */
+    public DataServiceCallback(IDataServiceCallback callback) {
+        mCallback = new WeakReference<>(callback);
+    }
+
+    /**
+     * Called to indicate result for the request {@link DataServiceProvider#setupDataCall(int,
+     * DataProfile, boolean, boolean, boolean, DataServiceCallback)}.
+     *
+     * @param result The result code. Must be one of the {@link Result}.
+     * @param response Setup data call response.
+     */
+    public void onSetupDataCallComplete(@Result int result, DataCallResponse response) {
+        IDataServiceCallback callback = mCallback.get();
+        if (callback != null) {
+            try {
+                callback.onSetupDataCallComplete(result, response);
+            } catch (RemoteException e) {
+                Rlog.e(mTag, "Failed to onSetupDataCallComplete on the remote");
+            }
+        }
+    }
+
+    /**
+     * Called to indicate result for the request {@link DataServiceProvider#deactivateDataCall(int,
+     * boolean, boolean, DataServiceCallback)}.
+     *
+     * @param result The result code. Must be one of the {@link Result}.
+     */
+    public void onDeactivateDataCallComplete(@Result int result) {
+        IDataServiceCallback callback = mCallback.get();
+        if (callback != null) {
+            try {
+                callback.onDeactivateDataCallComplete(result);
+            } catch (RemoteException e) {
+                Rlog.e(mTag, "Failed to onDeactivateDataCallComplete on the remote");
+            }
+        }
+    }
+
+    /**
+     * Called to indicate result for the request {@link DataServiceProvider#setInitialAttachApn(
+     * DataProfile, boolean, DataServiceCallback)}.
+     *
+     * @param result The result code. Must be one of the {@link Result}.
+     */
+    public void onSetInitialAttachApnComplete(@Result int result) {
+        IDataServiceCallback callback = mCallback.get();
+        if (callback != null) {
+            try {
+                callback.onSetInitialAttachApnComplete(result);
+            } catch (RemoteException e) {
+                Rlog.e(mTag, "Failed to onSetInitialAttachApnComplete on the remote");
+            }
+        }
+    }
+
+    /**
+     * Called to indicate result for the request {@link DataServiceProvider#setDataProfile(List,
+     * boolean, DataServiceCallback)}.
+     *
+     * @param result The result code. Must be one of the {@link Result}.
+     */
+    @SystemApi
+    public void onSetDataProfileComplete(@Result int result) {
+        IDataServiceCallback callback = mCallback.get();
+        if (callback != null) {
+            try {
+                callback.onSetDataProfileComplete(result);
+            } catch (RemoteException e) {
+                Rlog.e(mTag, "Failed to onSetDataProfileComplete on the remote");
+            }
+        }
+    }
+
+    /**
+     * Called to indicate result for the request {@link DataServiceProvider#getDataCallList(
+     * DataServiceCallback)}.
+     *
+     * @param result The result code. Must be one of the {@link Result}.
+     * @param dataCallList List of the current active data connection.
+     */
+    public void onGetDataCallListComplete(@Result int result, List<DataCallResponse> dataCallList) {
+        IDataServiceCallback callback = mCallback.get();
+        if (callback != null) {
+            try {
+                callback.onGetDataCallListComplete(result, dataCallList);
+            } catch (RemoteException e) {
+                Rlog.e(mTag, "Failed to onGetDataCallListComplete on the remote");
+            }
+        }
+    }
+
+    /**
+     * Called to indicate that data connection list changed.
+     *
+     * @param dataCallList List of the current active data connection.
+     */
+    public void onDataCallListChanged(List<DataCallResponse> dataCallList) {
+        IDataServiceCallback callback = mCallback.get();
+        if (callback != null) {
+            try {
+                callback.onDataCallListChanged(dataCallList);
+            } catch (RemoteException e) {
+                Rlog.e(mTag, "Failed to onDataCallListChanged on the remote");
+            }
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl
new file mode 100644 (file)
index 0000000..4eaaa25
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.data;
+
+import android.net.LinkProperties;
+import android.telephony.data.DataProfile;
+import android.telephony.data.IDataServiceCallback;
+
+/**
+ * {@hide}
+ */
+oneway interface IDataService
+{
+    void setupDataCall(int accessNetwork, in DataProfile dataProfile, boolean isRoaming,
+                       boolean allowRoaming, boolean isHandover, in LinkProperties linkProperties,
+                       IDataServiceCallback callback);
+    void deactivateDataCall(int cid, boolean reasonRadioShutDown, boolean isHandover,
+                            IDataServiceCallback callback);
+    void setInitialAttachApn(in DataProfile dataProfile, boolean isRoaming,
+                             IDataServiceCallback callback);
+    void setDataProfile(in List<DataProfile> dps, boolean isRoaming, IDataServiceCallback callback);
+    void getDataCallList(IDataServiceCallback callback);
+    void registerForDataCallListChanged(IDataServiceCallback callback);
+    void unregisterForDataCallListChanged(IDataServiceCallback callback);
+}
diff --git a/telephony/java/android/telephony/data/IDataServiceCallback.aidl b/telephony/java/android/telephony/data/IDataServiceCallback.aidl
new file mode 100644 (file)
index 0000000..856185b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.data;
+
+import android.telephony.data.DataCallResponse;
+
+/**
+ * The call back interface
+ * @hide
+ */
+oneway interface IDataServiceCallback
+{
+    void onSetupDataCallComplete(int result, in DataCallResponse dataCallResponse);
+    void onDeactivateDataCallComplete(int result);
+    void onSetInitialAttachApnComplete(int result);
+    void onSetDataProfileComplete(int result);
+    void onGetDataCallListComplete(int result, in List<DataCallResponse> dataCallList);
+    void onDataCallListChanged(in List<DataCallResponse> dataCallList);
+}