333 lines
15 KiB
Java
333 lines
15 KiB
Java
/*
|
|
* Copyright (C) 2016 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;
|
|
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.database.ContentObserver;
|
|
import android.os.AsyncResult;
|
|
import android.os.Handler;
|
|
import android.os.Message;
|
|
import android.os.Registrant;
|
|
import android.os.RegistrantList;
|
|
import android.provider.Settings;
|
|
import android.provider.Telephony;
|
|
import android.telephony.SubscriptionManager;
|
|
import android.telephony.TelephonyManager;
|
|
import android.util.LocalLog;
|
|
import android.util.Log;
|
|
|
|
import com.android.internal.annotations.VisibleForTesting;
|
|
import com.android.internal.util.IndentingPrintWriter;
|
|
import com.android.telephony.Rlog;
|
|
|
|
import java.io.FileDescriptor;
|
|
import java.io.PrintWriter;
|
|
|
|
/**
|
|
* Carrier Action Agent(CAA) paired with
|
|
* {@link com.android.internal.telephony.CarrierSignalAgent CarrierSignalAgent},
|
|
* serves as an agent to dispatch carrier actions from carrier apps to different telephony modules,
|
|
* {@link android.telephony.TelephonyManager#carrierActionSetRadioEnabled(int, boolean)
|
|
* carrierActionSetRadioEnabled} for example.
|
|
*
|
|
* CAA supports dynamic registration where different telephony modules could listen for a specific
|
|
* carrier action event and implement their own handler. CCA will dispatch the event to all
|
|
* interested parties and maintain the received action states internally for future inspection.
|
|
* Each CarrierActionAgent is associated with a phone object.
|
|
*/
|
|
public class CarrierActionAgent extends Handler {
|
|
private static final String LOG_TAG = "CarrierActionAgent";
|
|
private static final boolean DBG = true;
|
|
private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE);
|
|
|
|
/** A list of carrier actions */
|
|
public static final int CARRIER_ACTION_SET_METERED_APNS_ENABLED = 0;
|
|
public static final int CARRIER_ACTION_SET_RADIO_ENABLED = 1;
|
|
public static final int CARRIER_ACTION_RESET = 2;
|
|
public static final int CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS = 3;
|
|
public static final int EVENT_APM_SETTINGS_CHANGED = 4;
|
|
public static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED = 5;
|
|
public static final int EVENT_DATA_ROAMING_OFF = 6;
|
|
public static final int EVENT_SIM_STATE_CHANGED = 7;
|
|
public static final int EVENT_APN_SETTINGS_CHANGED = 8;
|
|
|
|
/** Member variables */
|
|
private final Phone mPhone;
|
|
/** registrant list per carrier action */
|
|
private RegistrantList mMeteredApnEnableRegistrants = new RegistrantList();
|
|
private RegistrantList mRadioEnableRegistrants = new RegistrantList();
|
|
private RegistrantList mDefaultNetworkReportRegistrants = new RegistrantList();
|
|
/** local log for carrier actions */
|
|
private LocalLog mMeteredApnEnabledLog = new LocalLog(8);
|
|
private LocalLog mRadioEnabledLog = new LocalLog(8);
|
|
private LocalLog mReportDefaultNetworkStatusLog = new LocalLog(8);
|
|
/** carrier actions */
|
|
private Boolean mCarrierActionOnMeteredApnEnabled = true;
|
|
private Boolean mCarrierActionOnRadioEnabled = true;
|
|
private Boolean mCarrierActionReportDefaultNetworkStatus = false;
|
|
/** content observer for APM change */
|
|
private final SettingsObserver mSettingsObserver;
|
|
|
|
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
final String action = intent.getAction();
|
|
final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
|
|
if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){
|
|
if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
|
|
// ignore rebroadcast since carrier apps are direct boot aware.
|
|
return;
|
|
}
|
|
final int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
|
|
SubscriptionManager.INVALID_PHONE_INDEX);
|
|
if (mPhone.getPhoneId() == phoneId) {
|
|
sendMessage(obtainMessage(EVENT_SIM_STATE_CHANGED, iccState));
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/** Constructor */
|
|
public CarrierActionAgent(Phone phone) {
|
|
mPhone = phone;
|
|
mPhone.getContext().registerReceiver(mReceiver,
|
|
new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
|
|
mSettingsObserver = new SettingsObserver(mPhone.getContext(), this);
|
|
if (DBG) log("Creating CarrierActionAgent");
|
|
}
|
|
|
|
@Override
|
|
public void handleMessage(Message msg) {
|
|
// skip notification if the input carrier action is same as the current one.
|
|
Boolean enabled = getCarrierActionEnabled(msg.what);
|
|
if (enabled != null && enabled == (boolean) msg.obj) return;
|
|
switch (msg.what) {
|
|
case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
|
|
mCarrierActionOnMeteredApnEnabled = (boolean) msg.obj;
|
|
log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled);
|
|
mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: "
|
|
+ mCarrierActionOnMeteredApnEnabled);
|
|
int otaspState = (mCarrierActionOnMeteredApnEnabled)
|
|
? mPhone.getServiceStateTracker().getOtasp()
|
|
: TelephonyManager.OTASP_SIM_UNPROVISIONED;
|
|
mPhone.notifyOtaspChanged(otaspState);
|
|
mMeteredApnEnableRegistrants.notifyRegistrants(
|
|
new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null));
|
|
break;
|
|
case CARRIER_ACTION_SET_RADIO_ENABLED:
|
|
mCarrierActionOnRadioEnabled = (boolean) msg.obj;
|
|
log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
|
|
mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
|
|
mRadioEnableRegistrants.notifyRegistrants(
|
|
new AsyncResult(null, mCarrierActionOnRadioEnabled, null));
|
|
break;
|
|
case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS:
|
|
mCarrierActionReportDefaultNetworkStatus = (boolean) msg.obj;
|
|
log("CARRIER_ACTION_REPORT_AT_DEFAULT_NETWORK_STATUS: "
|
|
+ mCarrierActionReportDefaultNetworkStatus);
|
|
mReportDefaultNetworkStatusLog.log("REGISTER_DEFAULT_NETWORK_STATUS: "
|
|
+ mCarrierActionReportDefaultNetworkStatus);
|
|
mDefaultNetworkReportRegistrants.notifyRegistrants(
|
|
new AsyncResult(null, mCarrierActionReportDefaultNetworkStatus, null));
|
|
break;
|
|
case CARRIER_ACTION_RESET:
|
|
log("CARRIER_ACTION_RESET");
|
|
carrierActionReset();
|
|
break;
|
|
case EVENT_APM_SETTINGS_CHANGED:
|
|
log("EVENT_APM_SETTINGS_CHANGED");
|
|
if ((Settings.Global.getInt(mPhone.getContext().getContentResolver(),
|
|
Settings.Global.AIRPLANE_MODE_ON, 0) != 0)) {
|
|
carrierActionReset();
|
|
}
|
|
break;
|
|
case EVENT_MOBILE_DATA_SETTINGS_CHANGED:
|
|
log("EVENT_MOBILE_DATA_SETTINGS_CHANGED");
|
|
if (!mPhone.isUserDataEnabled()) carrierActionReset();
|
|
break;
|
|
case EVENT_DATA_ROAMING_OFF:
|
|
log("EVENT_DATA_ROAMING_OFF");
|
|
// reset carrier actions when exit roaming state.
|
|
carrierActionReset();
|
|
break;
|
|
case EVENT_SIM_STATE_CHANGED:
|
|
String iccState = (String) msg.obj;
|
|
if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState)) {
|
|
log("EVENT_SIM_STATE_CHANGED status: " + iccState);
|
|
carrierActionReset();
|
|
String mobileData = Settings.Global.MOBILE_DATA;
|
|
if (TelephonyManager.getDefault().getSimCount() != 1) {
|
|
mobileData = mobileData + mPhone.getSubId();
|
|
}
|
|
mSettingsObserver.observe(Settings.Global.getUriFor(mobileData),
|
|
EVENT_MOBILE_DATA_SETTINGS_CHANGED);
|
|
mSettingsObserver.observe(
|
|
Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
|
|
EVENT_APM_SETTINGS_CHANGED);
|
|
mSettingsObserver.observe(
|
|
Telephony.Carriers.CONTENT_URI, EVENT_APN_SETTINGS_CHANGED);
|
|
if (mPhone.getServiceStateTracker() != null) {
|
|
mPhone.getServiceStateTracker().registerForDataRoamingOff(
|
|
this, EVENT_DATA_ROAMING_OFF, null, false);
|
|
}
|
|
} else if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) {
|
|
log("EVENT_SIM_STATE_CHANGED status: " + iccState);
|
|
carrierActionReset();
|
|
mSettingsObserver.unobserve();
|
|
if (mPhone.getServiceStateTracker() != null) {
|
|
mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this);
|
|
}
|
|
}
|
|
break;
|
|
case EVENT_APN_SETTINGS_CHANGED:
|
|
log("EVENT_APN_SETTINGS_CHANGED");
|
|
// Reset carrier actions when APN change.
|
|
carrierActionReset();
|
|
break;
|
|
default:
|
|
loge("Unknown carrier action: " + msg.what);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Action set from carrier app to enable/disable radio
|
|
*/
|
|
public void carrierActionSetRadioEnabled(boolean enabled) {
|
|
sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled));
|
|
}
|
|
|
|
/**
|
|
* Action set from carrier app to enable/disable metered APNs
|
|
*/
|
|
public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
|
|
sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled));
|
|
}
|
|
|
|
/**
|
|
* Action set from carrier app to start/stop reporting default network status.
|
|
*/
|
|
public void carrierActionReportDefaultNetworkStatus(boolean report) {
|
|
sendMessage(obtainMessage(CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS, report));
|
|
}
|
|
|
|
public void carrierActionReset() {
|
|
carrierActionReportDefaultNetworkStatus(false);
|
|
carrierActionSetMeteredApnsEnabled(true);
|
|
carrierActionSetRadioEnabled(true);
|
|
// notify configured carrier apps for reset
|
|
mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(
|
|
new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_RESET));
|
|
}
|
|
|
|
private RegistrantList getRegistrantsFromAction(int action) {
|
|
switch (action) {
|
|
case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
|
|
return mMeteredApnEnableRegistrants;
|
|
case CARRIER_ACTION_SET_RADIO_ENABLED:
|
|
return mRadioEnableRegistrants;
|
|
case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS:
|
|
return mDefaultNetworkReportRegistrants;
|
|
default:
|
|
loge("Unsupported action: " + action);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private Boolean getCarrierActionEnabled(int action) {
|
|
switch (action) {
|
|
case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
|
|
return mCarrierActionOnMeteredApnEnabled;
|
|
case CARRIER_ACTION_SET_RADIO_ENABLED:
|
|
return mCarrierActionOnRadioEnabled;
|
|
case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS:
|
|
return mCarrierActionReportDefaultNetworkStatus;
|
|
default:
|
|
loge("Unsupported action: " + action);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register with CAA for a specific event.
|
|
* @param action which carrier action registrant is interested in
|
|
* @param notifyNow if carrier action has once set, notify registrant right after
|
|
* registering, so that registrants will get the latest carrier action.
|
|
*/
|
|
public void registerForCarrierAction(int action, Handler h, int what, Object obj,
|
|
boolean notifyNow) {
|
|
Boolean carrierAction = getCarrierActionEnabled(action);
|
|
if (carrierAction == null) {
|
|
throw new IllegalArgumentException("invalid carrier action: " + action);
|
|
}
|
|
RegistrantList list = getRegistrantsFromAction(action);
|
|
Registrant r = new Registrant(h, what, obj);
|
|
list.add(r);
|
|
if (notifyNow) {
|
|
r.notifyRegistrant(new AsyncResult(null, carrierAction, null));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Unregister with CAA for a specific event. Callers will no longer be notified upon such event.
|
|
* @param action which carrier action caller is no longer interested in
|
|
*/
|
|
public void unregisterForCarrierAction(Handler h, int action) {
|
|
RegistrantList list = getRegistrantsFromAction(action);
|
|
if (list == null) {
|
|
throw new IllegalArgumentException("invalid carrier action: " + action);
|
|
}
|
|
list.remove(h);
|
|
}
|
|
|
|
@VisibleForTesting
|
|
public ContentObserver getContentObserver() {
|
|
return mSettingsObserver;
|
|
}
|
|
|
|
private void log(String s) {
|
|
Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
|
|
}
|
|
|
|
private void loge(String s) {
|
|
Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
|
|
}
|
|
|
|
private void logv(String s) {
|
|
Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
|
|
}
|
|
|
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
|
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
|
|
pw.println(" mCarrierActionOnMeteredApnsEnabled Log:");
|
|
ipw.increaseIndent();
|
|
mMeteredApnEnabledLog.dump(fd, ipw, args);
|
|
ipw.decreaseIndent();
|
|
|
|
pw.println(" mCarrierActionOnRadioEnabled Log:");
|
|
ipw.increaseIndent();
|
|
mRadioEnabledLog.dump(fd, ipw, args);
|
|
ipw.decreaseIndent();
|
|
|
|
pw.println(" mCarrierActionReportDefaultNetworkStatus Log:");
|
|
ipw.increaseIndent();
|
|
mReportDefaultNetworkStatusLog.dump(fd, ipw, args);
|
|
ipw.decreaseIndent();
|
|
}
|
|
}
|