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

Commit 1f45264d authored by Andrew Flynn's avatar Andrew Flynn
Browse files

TelephonyManager Carrier Network Change Notification

Adds a way for a carrier app to notify the system that an intended network
change is starting or ending. This can be used by a system PhoneStateListener
to provide custom UI or perform other actions during this period.

- Adds new public TelephonyManager API: notifyCarrierNetworkChange(boolean)
- Adds new @hide PhoneStateListener method: onCarrierNetworkChange(boolean)
- Functionality merely serves as a pass-through of data from an app to a
  PhoneStateListener (SystemUI for the intended use case)
- Protected by MODIFY_PHONE_STATE permission or hasCarrierPrivileges().

Bug: 11392659

Change-Id: I3199e21ec1ac124198f44b86c1534dd3ff1f6858
parent 7d43893b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -30295,6 +30295,7 @@ package android.telephony {
    method public boolean isVoiceCapable();
    method public boolean isWorldPhone();
    method public void listen(android.telephony.PhoneStateListener, int);
    method public void notifyCarrierNetworkChange(boolean);
    method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
    method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
    method public boolean setOperatorBrandOverride(java.lang.String);
+1 −0
Original line number Diff line number Diff line
@@ -32902,6 +32902,7 @@ package android.telephony {
    method public boolean isWorldPhone();
    method public void listen(android.telephony.PhoneStateListener, int);
    method public boolean needsOtaServiceProvisioning();
    method public void notifyCarrierNetworkChange(boolean);
    method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
    method public void setDataEnabled(boolean);
    method public void setDataEnabled(int, boolean);
+64 −2
Original line number Diff line number Diff line
@@ -181,6 +181,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {

    private PreciseCallState mPreciseCallState = new PreciseCallState();

    private boolean mCarrierNetworkChangeState = false;

    private PreciseDataConnectionState mPreciseDataConnectionState =
                new PreciseDataConnectionState();

@@ -607,6 +609,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                            remove(r.binder);
                        }
                    }
                    if ((events & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) {
                        try {
                            r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState);
                        } catch (RemoteException ex) {
                            remove(r.binder);
                        }
                    }
                }
            }
        } else {
@@ -790,6 +799,31 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
        broadcastSignalStrengthChanged(signalStrength, subId);
    }

    @Override
    public void notifyCarrierNetworkChange(boolean active) {
        if (!checkNotifyPermissionOrCarrierPrivilege("notifyCarrierNetworkChange()")) {
            return;
        }
        if (VDBG) {
            log("notifyCarrierNetworkChange: active=" + active);
        }

        synchronized (mRecords) {
            mCarrierNetworkChangeState = active;
            for (Record r : mRecords) {
                if (r.matchPhoneStateListenerEvent(
                        PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE)) {
                    try {
                        r.callback.onCarrierNetworkChange(active);
                    } catch (RemoteException ex) {
                        mRemoveList.add(r.binder);
                    }
                }
            }
            handleRemoveListLocked();
        }
    }

    public void notifyCellInfo(List<CellInfo> cellInfo) {
         notifyCellInfoForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cellInfo);
    }
@@ -1422,9 +1456,19 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                android.Manifest.permission.READ_PRECISE_PHONE_STATE);
    }

    private boolean checkNotifyPermissionOrCarrierPrivilege(String method) {
        if  (checkNotifyPermission() || checkCarrierPrivilege()) {
            return true;
        }

        String msg = "Modify Phone State or Carrier Privilege Permission Denial: " + method
                + " from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
        if (DBG) log(msg);
        return false;
    }

    private boolean checkNotifyPermission(String method) {
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                == PackageManager.PERMISSION_GRANTED) {
        if (checkNotifyPermission()) {
            return true;
        }
        String msg = "Modify Phone State Permission Denial: " + method + " from pid="
@@ -1433,6 +1477,24 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
        return false;
    }

    private boolean checkNotifyPermission() {
        return mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                == PackageManager.PERMISSION_GRANTED;
    }

    private boolean checkCarrierPrivilege() {
        TelephonyManager tm = TelephonyManager.getDefault();
        String[] pkgs = mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid());
        for (String pkg : pkgs) {
            if (tm.checkCarrierPrivilegesForPackage(pkg) ==
                    TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
                return true;
            }
        }

        return false;
    }

    private void checkListenerPermission(int events) {
        if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
            mContext.enforceCallingOrSelfPermission(
+32 −0
Original line number Diff line number Diff line
@@ -219,6 +219,15 @@ public class PhoneStateListener {
     */
    public static final int LISTEN_OEM_HOOK_RAW_EVENT                       = 0x00008000;

    /**
     * Listen for carrier network changes indicated by a carrier app.
     *
     * @see #onCarrierNetworkRequest
     * @see TelephonyManager#notifyCarrierNetworkChange(boolean)
     * @hide
     */
    public static final int LISTEN_CARRIER_NETWORK_CHANGE                   = 0x00010000;

     /*
     * Subscription used to listen to the phone state changes
     * @hide
@@ -321,6 +330,9 @@ public class PhoneStateListener {
                    case LISTEN_OEM_HOOK_RAW_EVENT:
                        PhoneStateListener.this.onOemHookRawEvent((byte[])msg.obj);
                        break;
                    case LISTEN_CARRIER_NETWORK_CHANGE:
                        PhoneStateListener.this.onCarrierNetworkChange((boolean)msg.obj);
                        break;

                }
            }
@@ -499,6 +511,22 @@ public class PhoneStateListener {
        // default implementation empty
    }

    /**
     * Callback invoked when telephony has received notice from a carrier
     * app that a network action that could result in connectivity loss
     * has been requested by an app using
     * {@link android.telephony.TelephonyManager#notifyCarrierNetworkChange(boolean)}
     *
     * @param active Whether the carrier network change is or shortly
     *               will be active. This value is true to indicate
     *               showing alternative UI and false to stop.
     *
     * @hide
     */
    public void onCarrierNetworkChange(boolean active) {
        // default implementation empty
    }

    /**
     * The callback methods need to be called on the handler thread where
     * this object was created.  If the binder did that for us it'd be nice.
@@ -575,6 +603,10 @@ public class PhoneStateListener {
        public void onOemHookRawEvent(byte[] rawData) {
            Message.obtain(mHandler, LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData).sendToTarget();
        }

        public void onCarrierNetworkChange(boolean active) {
            Message.obtain(mHandler, LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active).sendToTarget();
        }
    };

    private void log(String s) {
+29 −0
Original line number Diff line number Diff line
@@ -2040,6 +2040,35 @@ public class TelephonyManager {
        return false;
    }

    /**
     * Informs the system of an intentional upcoming carrier network change by
     * a carrier app. This call is optional and is only used to allow the
     * system to provide alternative UI while telephony is performing an action
     * that may result in intentional, temporary network lack of connectivity.
     * <p>
     * Based on the active parameter passed in, this method will either show or
     * hide the alternative UI. There is no timeout associated with showing
     * this UX, so a carrier app must be sure to call with active set to false
     * sometime after calling with it set to true.
     * <p>
     * Requires Permission:
     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
     * Or the calling app has carrier privileges.
     *   @see #hasCarrierPrivileges
     *
     * @param active Whether the carrier network change is or shortly will be
     *               active. Set this value to true to begin showing
     *               alternative UI and false to stop.
     */
    public void notifyCarrierNetworkChange(boolean active) {
        try {
            if (sRegistry != null)
                sRegistry.notifyCarrierNetworkChange(active);
        } catch (RemoteException ex) {
        } catch (NullPointerException ex) {
        }
    }

    /**
     * Returns the alphabetic identifier associated with the line 1 number.
     * Return null if it is unavailable.
Loading