blob: a4b5929ff05a521b1a97206460a9051a896b0ada [file] [log] [blame]
/*
* 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 com.android.internal.telephony.dataconnection;
import android.net.LinkProperties;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.telephony.SubscriptionManager;
import android.telephony.data.DataCallResponse;
import android.telephony.data.DataProfile;
import android.telephony.data.DataService;
import android.telephony.data.DataServiceCallback;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.telephony.Rlog;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This class represents cellular data service which handles telephony data requests and response
* from the cellular modem.
*/
public class CellularDataService extends DataService {
private static final String TAG = CellularDataService.class.getSimpleName();
private static final boolean DBG = false;
private static final int SETUP_DATA_CALL_COMPLETE = 1;
private static final int DEACTIVATE_DATA_ALL_COMPLETE = 2;
private static final int SET_INITIAL_ATTACH_APN_COMPLETE = 3;
private static final int SET_DATA_PROFILE_COMPLETE = 4;
private static final int REQUEST_DATA_CALL_LIST_COMPLETE = 5;
private static final int DATA_CALL_LIST_CHANGED = 6;
private class CellularDataServiceProvider extends DataService.DataServiceProvider {
private final Map<Message, DataServiceCallback> mCallbackMap = new HashMap<>();
private final Handler mHandler;
private final Phone mPhone;
private CellularDataServiceProvider(int slotId) {
super(slotId);
mPhone = PhoneFactory.getPhone(getSlotIndex());
mHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message message) {
DataServiceCallback callback = mCallbackMap.remove(message);
AsyncResult ar = (AsyncResult) message.obj;
switch (message.what) {
case SETUP_DATA_CALL_COMPLETE:
DataCallResponse response = (DataCallResponse) ar.result;
callback.onSetupDataCallComplete(ar.exception != null
? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
: DataServiceCallback.RESULT_SUCCESS,
response);
break;
case DEACTIVATE_DATA_ALL_COMPLETE:
callback.onDeactivateDataCallComplete(ar.exception != null
? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
: DataServiceCallback.RESULT_SUCCESS);
break;
case SET_INITIAL_ATTACH_APN_COMPLETE:
callback.onSetInitialAttachApnComplete(ar.exception != null
? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
: DataServiceCallback.RESULT_SUCCESS);
break;
case SET_DATA_PROFILE_COMPLETE:
callback.onSetDataProfileComplete(ar.exception != null
? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
: DataServiceCallback.RESULT_SUCCESS);
break;
case REQUEST_DATA_CALL_LIST_COMPLETE:
callback.onRequestDataCallListComplete(
ar.exception != null
? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
: DataServiceCallback.RESULT_SUCCESS,
ar.exception != null
? null : (List<DataCallResponse>) ar.result
);
break;
case DATA_CALL_LIST_CHANGED:
notifyDataCallListChanged((List<DataCallResponse>) ar.result);
break;
default:
loge("Unexpected event: " + message.what);
return;
}
}
};
if (DBG) log("Register for data call list changed.");
mPhone.mCi.registerForDataCallListChanged(mHandler, DATA_CALL_LIST_CHANGED, null);
}
@Override
public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties,
DataServiceCallback callback) {
if (DBG) log("setupDataCall " + getSlotIndex());
Message message = null;
// Only obtain the message when the caller wants a callback. If the caller doesn't care
// the request completed or results, then no need to pass the message down.
if (callback != null) {
message = Message.obtain(mHandler, SETUP_DATA_CALL_COMPLETE);
mCallbackMap.put(message, callback);
}
mPhone.mCi.setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming,
reason, linkProperties, message);
}
@Override
public void deactivateDataCall(int cid, int reason, DataServiceCallback callback) {
if (DBG) log("deactivateDataCall " + getSlotIndex());
Message message = null;
// Only obtain the message when the caller wants a callback. If the caller doesn't care
// the request completed or results, then no need to pass the message down.
if (callback != null) {
message = Message.obtain(mHandler, DEACTIVATE_DATA_ALL_COMPLETE);
mCallbackMap.put(message, callback);
}
mPhone.mCi.deactivateDataCall(cid, reason, message);
}
@Override
public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
DataServiceCallback callback) {
if (DBG) log("setInitialAttachApn " + getSlotIndex());
Message message = null;
// Only obtain the message when the caller wants a callback. If the caller doesn't care
// the request completed or results, then no need to pass the message down.
if (callback != null) {
message = Message.obtain(mHandler, SET_INITIAL_ATTACH_APN_COMPLETE);
mCallbackMap.put(message, callback);
}
mPhone.mCi.setInitialAttachApn(dataProfile, isRoaming, message);
}
@Override
public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
DataServiceCallback callback) {
if (DBG) log("setDataProfile " + getSlotIndex());
Message message = null;
// Only obtain the message when the caller wants a callback. If the caller doesn't care
// the request completed or results, then no need to pass the message down.
if (callback != null) {
message = Message.obtain(mHandler, SET_DATA_PROFILE_COMPLETE);
mCallbackMap.put(message, callback);
}
mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[dps.size()]), isRoaming, message);
}
@Override
public void requestDataCallList(DataServiceCallback callback) {
if (DBG) log("requestDataCallList " + getSlotIndex());
Message message = null;
// Only obtain the message when the caller wants a callback. If the caller doesn't care
// the request completed or results, then no need to pass the message down.
if (callback != null) {
message = Message.obtain(mHandler, REQUEST_DATA_CALL_LIST_COMPLETE);
mCallbackMap.put(message, callback);
}
mPhone.mCi.getDataCallList(message);
}
@Override
public void close() {
mPhone.mCi.unregisterForDataCallListChanged(mHandler);
}
}
@Override
public DataServiceProvider onCreateDataServiceProvider(int slotIndex) {
log("Cellular data service created for slot " + slotIndex);
if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
loge("Tried to cellular data service with invalid slotId " + slotIndex);
return null;
}
return new CellularDataServiceProvider(slotIndex);
}
private void log(String s) {
Rlog.d(TAG, s);
}
private void loge(String s) {
Rlog.e(TAG, s);
}
}