diff options
7 files changed, 129 insertions, 2 deletions
diff --git a/api/current.txt b/api/current.txt index 6de9a03..37e1c2b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -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); diff --git a/api/system-current.txt b/api/system-current.txt index 2d387d1..bb0aa10 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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); diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index d153233..908ee22 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -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( diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 611dd7bd..d192288 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -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; } } @@ -500,6 +512,22 @@ public class PhoneStateListener { } /** + * 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) { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index c5573ba..39ff283 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -2041,6 +2041,35 @@ public class TelephonyManager { } /** + * 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. * <p> diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl index cea62ba..cbedb95 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -44,5 +44,6 @@ oneway interface IPhoneStateListener { void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo); void onVoLteServiceStateChanged(in VoLteServiceState lteState); void onOemHookRawEvent(in byte[] rawData); + void onCarrierNetworkChange(in boolean active); } diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 7d8a8d6..76b69ce 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -69,4 +69,5 @@ interface ITelephonyRegistry { void notifyVoLteServiceStateChanged(in VoLteServiceState lteState); void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData); void notifySubscriptionInfoChanged(); + void notifyCarrierNetworkChange(in boolean active); } |