Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 437bd386 authored by Thomas Nguyen's avatar Thomas Nguyen
Browse files

Add new APIs for owner groups to vote on radio power state

Bug: 228777724
Design doc: go/voting-radio-power-state
Test: Run the following tests
 - atest android.telephony.cts.TelephonyManagerTest
 - atest com.android.internal.telephony.ServiceStateTrackerTest
 - atest com.android.internal.telephony.data.DataNetworkControllerTest
 - atest com.android.internal.telephony.dataconnection.DcTrackerTest
 - atest com.android.internal.telephony.GsmCdmaPhoneTest
Change-Id: I4d49de3e056be62897a7472acc1c68c2a9932c27

Change-Id: I15750f49573d4213970b6b5228d5180c775f8536
parent c59f56b5
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -13398,6 +13398,7 @@ package android.telephony {
    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String);
    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int checkCarrierPrivilegesForPackage(String);
    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int checkCarrierPrivilegesForPackageAnyPhone(String);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void clearRadioPowerOffForReason(int);
    method public void dial(String);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean disableDataConnectivity();
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableDataConnectivity();
@@ -13443,6 +13444,7 @@ package android.telephony {
    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getMergedImsisFromGroup();
    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.PhoneCapability getPhoneCapability();
    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask();
    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Set<java.lang.Integer> getRadioPowerOffReasons();
    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState();
    method public int getSimApplicationState();
    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimApplicationState(int);
@@ -13497,6 +13499,7 @@ package android.telephony {
    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestRadioPowerOffForReason(int);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int);
@@ -13521,9 +13524,9 @@ package android.telephony {
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setNrDualConnectivityState(int);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRadioEnabled(boolean);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean);
    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRadioEnabled(boolean);
    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean);
    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerStateForSlot(int, int);
@@ -13605,6 +13608,10 @@ package android.telephony {
    field public static final int PREPARE_UNATTENDED_REBOOT_SUCCESS = 0; // 0x0
    field public static final int RADIO_POWER_OFF = 0; // 0x0
    field public static final int RADIO_POWER_ON = 1; // 0x1
    field public static final int RADIO_POWER_REASON_CARRIER = 2; // 0x2
    field public static final int RADIO_POWER_REASON_NEARBY_DEVICE = 3; // 0x3
    field public static final int RADIO_POWER_REASON_THERMAL = 1; // 0x1
    field public static final int RADIO_POWER_REASON_USER = 0; // 0x0
    field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
    field public static final int SET_CARRIER_RESTRICTION_ERROR = 2; // 0x2
    field public static final int SET_CARRIER_RESTRICTION_NOT_SUPPORTED = 1; // 0x1
+190 −19
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -234,6 +235,54 @@ public class TelephonyManager {
    public static final int NETWORK_SELECTION_MODE_AUTO = 1;
    public static final int NETWORK_SELECTION_MODE_MANUAL = 2;
    /**
     * Reasons for Radio being powered off.
     *
     * @hide
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"RADIO_POWER_REASON_"},
            value = {
                    RADIO_POWER_REASON_USER,
                    RADIO_POWER_REASON_THERMAL,
                    RADIO_POWER_REASON_CARRIER,
                    RADIO_POWER_REASON_NEARBY_DEVICE})
    public @interface RadioPowerReason {}
    /**
     * This reason is used when users want to turn off radio, e.g., users turn on airplane mode.
     *
     * @hide
     */
    @SystemApi
    public static final int RADIO_POWER_REASON_USER = 0;
    /**
     * This reason is used when radio needs to be turned off due to thermal.
     *
     * @hide
     */
    @SystemApi
    public static final int RADIO_POWER_REASON_THERMAL = 1;
    /**
     * This reason is used when carriers want to turn off radio. A privileged app can request to
     * turn off radio via the system service
     * {@link com.android.carrierdefaultapp.CaptivePortalLoginActivity}, which subsequently calls
     * the system APIs {@link requestRadioPowerOffForReason} and
     * {@link clearRadioPowerOffForReason}.
     *
     * @hide
     */
    @SystemApi
    public static final int RADIO_POWER_REASON_CARRIER = 2;
    /**
     * Used to reduce power on a battery-constrained device when Telephony services are available
     * via a paired device which is nearby.
     *
     * @hide
     */
    @SystemApi
    public static final int RADIO_POWER_REASON_NEARBY_DEVICE = 3;
    /** The otaspMode passed to PhoneStateListener#onOtaspChanged */
    /** @hide */
    static public final int OTASP_UNINITIALIZED = 0;
@@ -10506,34 +10555,155 @@ public class TelephonyManager {
        }
    }
    /** @hide */
    /**
     * @deprecated - use the APIs {@link requestRadioPowerOffForReason} and
     * {@link clearRadioPowerOffForReason}.
     *
     * @hide
     */
    @Deprecated
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
    public boolean setRadio(boolean turnOn) {
        boolean result = true;
        try {
            if (turnOn) {
                clearRadioPowerOffForReason(RADIO_POWER_REASON_USER);
            } else {
                requestRadioPowerOffForReason(RADIO_POWER_REASON_USER);
            }
        } catch (Exception e) {
            String calledFunction =
                    turnOn ? "clearRadioPowerOffForReason" : "requestRadioPowerOffForReason";
            Log.e(TAG, "Error calling " + calledFunction, e);
            result = false;
        }
        return result;
    }
    /**
     * @deprecated - use the APIs {@link requestRadioPowerOffForReason} and
     * {@link clearRadioPowerOffForReason}.
     *
     * @hide
     */
    @Deprecated
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
    public boolean setRadioPower(boolean turnOn) {
        boolean result = true;
        try {
            if (turnOn) {
                clearRadioPowerOffForReason(RADIO_POWER_REASON_USER);
            } else {
                requestRadioPowerOffForReason(RADIO_POWER_REASON_USER);
            }
        } catch (Exception e) {
            String calledFunction =
                    turnOn ? "clearRadioPowerOffForReason" : "requestRadioPowerOffForReason";
            Log.e(TAG, "Error calling " + calledFunction, e);
            result = false;
        }
        return result;
    }
    /**
     * Vote on powering off the radio for a reason. The radio will be turned on only when there is
     * no reason to power it off. When any of the voters want to power it off, it will be turned
     * off. In case of emergency, the radio will be turned on even if there are some reasons for
     * powering it off, and these radio off votes will be cleared.
     * Multiple apps can vote for the same reason and the last vote will take effect. Each app is
     * responsible for its vote. A powering-off vote of a reason will be maintained until it is
     * cleared by calling {@link clearRadioPowerOffForReason} for that reason, or an emergency call
     * is made, or the device is rebooted. When an app comes backup from a crash, it needs to make
     * sure if its vote is as expected. An app can use the API {@link getRadioPowerOffReasons} to
     * check its vote.
     *
     * @param reason The reason for powering off radio.
     * @throws SecurityException if the caller does not have MODIFY_PHONE_STATE permission.
     * @throws IllegalStateException if the Telephony service is not currently available.
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
    public void requestRadioPowerOffForReason(@RadioPowerReason int reason) {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                return telephony.setRadio(turnOn);
            if (telephony != null) {
                if (!telephony.requestRadioPowerOffForReason(getSubId(), reason)) {
                    throw new IllegalStateException("Telephony service is not available.");
                }
            } else {
                throw new IllegalStateException("Telephony service is null.");
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#setRadio", e);
            Log.e(TAG, "Error calling ITelephony#requestRadioPowerOffForReason", e);
            e.rethrowAsRuntimeException();
        }
        return false;
    }
    /** @hide */
    /**
     * Remove the vote on powering off the radio for a reason, as requested by
     * {@link requestRadioPowerOffForReason}.
     *
     * @param reason The reason for powering off radio.
     * @throws SecurityException if the caller does not have MODIFY_PHONE_STATE permission.
     * @throws IllegalStateException if the Telephony service is not currently available.
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
    public boolean setRadioPower(boolean turnOn) {
    public void clearRadioPowerOffForReason(@RadioPowerReason int reason) {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                return telephony.setRadioPower(turnOn);
            if (telephony != null) {
                if (!telephony.clearRadioPowerOffForReason(getSubId(), reason)) {
                    throw new IllegalStateException("Telephony service is not available.");
                }
            } else {
                throw new IllegalStateException("Telephony service is null.");
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#setRadioPower", e);
            Log.e(TAG, "Error calling ITelephony#clearRadioPowerOffForReason", e);
            e.rethrowAsRuntimeException();
        }
        return false;
    }
    /**
     * Get reasons for powering off radio, as requested by {@link requestRadioPowerOffForReason}.
     * If the reason set is empty, the radio is on in all cases.
     *
     * @return Set of reasons for powering off radio.
     * @throws SecurityException if the caller does not have READ_PRIVILEGED_PHONE_STATE permission.
     * @throws IllegalStateException if the Telephony service is not currently available.
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
    @NonNull
    public Set<Integer> getRadioPowerOffReasons() {
        Set<Integer> result = new HashSet<>();
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null) {
                result.addAll(telephony.getRadioPowerOffReasons(getSubId(),
                        mContext.getOpPackageName(), mContext.getAttributionTag()));
            } else {
                throw new IllegalStateException("Telephony service is null.");
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#getRadioPowerOffReasons", e);
            e.rethrowAsRuntimeException();
        }
        return result;
    }
    /**
@@ -13037,20 +13207,21 @@ public class TelephonyManager {
     *
     * @param enabled control enable or disable radio.
     * @see #resetAllCarrierActions()
     *
     * @deprecated - use the APIs {@link requestRadioPowerOffForReason} and
     * {@link clearRadioPowerOffForReason}.
     *
     * @hide
     */
    @Deprecated
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
    public void setRadioEnabled(boolean enabled) {
        try {
            ITelephony service = getITelephony();
            if (service != null) {
                service.carrierActionSetRadioEnabled(
                        getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#carrierActionSetRadioEnabled", e);
        if (enabled) {
            clearRadioPowerOffForReason(RADIO_POWER_REASON_CARRIER);
        } else {
            requestRadioPowerOffForReason(RADIO_POWER_REASON_CARRIER);
        }
    }
+38 −0
Original line number Diff line number Diff line
@@ -243,6 +243,44 @@ interface ITelephony {
     */
    boolean setRadioPower(boolean turnOn);

    /**
     * Vote on powering off the radio for a reason. The radio will be turned on only when there is
     * no reason to power it off. When any of the voters want to power it off, it will be turned
     * off. In case of emergency, the radio will be turned on even if there are some reasons for
     * powering it off, and these radio off votes will be cleared.
     * Multiple apps can vote for the same reason and the last vote will take effect. Each app is
     * responsible for its vote. A powering-off vote of a reason will be maintained until it is
     * cleared by calling {@link clearRadioPowerOffForReason} for that reason, or an emergency call
     * is made, or the device is rebooted. When an app comes backup from a crash, it needs to make
     * sure if its vote is as expected. An app can use the API {@link getRadioPowerOffReasons} to
     * check its vote.
     *
     * @param subId The subscription ID.
     * @param reason The reason for powering off radio.
     * @return true on success and false on failure.
     */
    boolean requestRadioPowerOffForReason(int subId, int reason);

    /**
     * Remove the vote on powering off the radio for a reasonas, requested by
     * {@link requestRadioPowerOffForReason}.
     *
     * @param subId The subscription ID.
     * @param reason The reason for powering off radio.
     * @return true on success and false on failure.
     */
    boolean clearRadioPowerOffForReason(int subId, int reason);

    /**
     * Get reasons for powering off radio, as requested by {@link requestRadioPowerOffForReason}.
     *
     * @param subId The subscription ID.
     * @param callingPackage The package making the call.
     * @param callingFeatureId The feature in the package.
     * @return List of reasons for powering off radio.
     */
    List getRadioPowerOffReasons(int subId, String callingPackage, String callingFeatureId);

    /**
     * This method has been removed due to security and stability issues.
     */