diff options
Diffstat (limited to 'telephony/java/android')
27 files changed, 624 insertions, 306 deletions
diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java index 8450a9018634..92e419707970 100644 --- a/telephony/java/android/service/euicc/EuiccProfileInfo.java +++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java @@ -29,6 +29,7 @@ import android.text.TextUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -231,7 +232,9 @@ public final class EuiccProfileInfo implements Parcelable { mState = baseProfile.mState; mCarrierIdentifier = baseProfile.mCarrierIdentifier; mPolicyRules = baseProfile.mPolicyRules; - mAccessRules = Arrays.asList(baseProfile.mAccessRules); + mAccessRules = baseProfile.mAccessRules == null + ? Collections.emptyList() + : Arrays.asList(baseProfile.mAccessRules); } /** Builds the profile instance. */ diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java index 93155865c166..fcbb008c79b3 100644 --- a/telephony/java/android/service/euicc/EuiccService.java +++ b/telephony/java/android/service/euicc/EuiccService.java @@ -328,8 +328,7 @@ public abstract class EuiccService extends Service { * or when an number is bigger than 15 */ public int encodeSmdxSubjectAndReasonCode(@Nullable String subjectCode, - @Nullable String reasonCode) - throws NumberFormatException, IllegalArgumentException, UnsupportedOperationException { + @Nullable String reasonCode) { final int maxSupportedSection = 3; final int maxSupportedDigit = 15; final int bitsPerSection = 4; diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 52f1e37e69f4..b6152e200e65 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -354,6 +354,34 @@ public class CarrierConfigManager { "only_auto_select_in_home_network"; /** + * Flag indicating whether to show single operator row in the choose network setting. + * + * The device configuration value {@code config_enableNewAutoSelectNetworkUI} ultimately + * controls whether this carrier configuration option is used. Where + * {@code config_enableNewAutoSelectNetworkUI} is false, the value of the + * {@link #KEY_SHOW_SINGLE_OPERATOR_ROW_IN_CHOOSE_NETWORK_SETTING_BOOL} carrier configuration + * option is ignored. + * + * If {@code true}, default value, merge the duplicate networks which with the same plmn, keep + * the one that with the higher signal strength level. + * If {@code false}, show all operators without merging. + * @hide + */ + public static final String KEY_SHOW_SINGLE_OPERATOR_ROW_IN_CHOOSE_NETWORK_SETTING_BOOL = + "show_single_operator_row_in_choose_network_setting_bool"; + + /** + * Flag indicating whether to display SPN as network name for home network in choose + * network setting. + * + * If {@code true}, display SPN as network name in choose network setting. + * If {@code false}, display PLMN in choose network setting. + * @hide + */ + public static final String KEY_SHOW_SPN_FOR_HOME_IN_CHOOSE_NETWORK_SETTING_BOOL = + "show_spn_for_home_in_choose_network_setting_bool"; + + /** * Control whether users receive a simplified network settings UI and improved network * selection. */ @@ -3779,6 +3807,15 @@ public class CarrierConfigManager { "carrier_certificate_string_array"; /** + * Flag specifying whether the incoming call number should be formatted to national number + * for Japan. @return {@code true} convert to the national format, {@code false} otherwise. + * e.g. "+819012345678" -> "09012345678" + * @hide + */ + public static final String KEY_FORMAT_INCOMING_NUMBER_TO_NATIONAL_FOR_JP_BOOL = + "format_incoming_number_to_national_for_jp_bool"; + + /** * DisconnectCause array to play busy tone. Value should be array of * {@link android.telephony.DisconnectCause}. */ @@ -3910,6 +3947,8 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL, false); sDefaults.putBoolean(KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false); sDefaults.putBoolean(KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL, false); + sDefaults.putBoolean(KEY_SHOW_SINGLE_OPERATOR_ROW_IN_CHOOSE_NETWORK_SETTING_BOOL, true); + sDefaults.putBoolean(KEY_SHOW_SPN_FOR_HOME_IN_CHOOSE_NETWORK_SETTING_BOOL, false); sDefaults.putBoolean(KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL, false); sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false); @@ -4359,6 +4398,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true); sDefaults.putAll(Ims.getDefaults()); sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, null); + sDefaults.putBoolean(KEY_FORMAT_INCOMING_NUMBER_TO_NATIONAL_FOR_JP_BOOL, false); sDefaults.putIntArray(KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY, new int[] {4 /* BUSY */}); sDefaults.putBoolean(KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL, false); @@ -4622,6 +4662,7 @@ public class CarrierConfigManager { } catch (RemoteException ex) { Rlog.e(TAG, "getDefaultCarrierServicePackageName ICarrierConfigLoader is null" + ex.toString()); + ex.rethrowAsRuntimeException(); } return ""; } diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java index 2d0bd52f84ee..aa1230165e13 100644 --- a/telephony/java/android/telephony/CellLocation.java +++ b/telephony/java/android/telephony/CellLocation.java @@ -16,7 +16,9 @@ package android.telephony; +import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; import android.os.Bundle; import android.os.RemoteException; import android.telephony.cdma.CdmaCellLocation; @@ -31,11 +33,32 @@ import com.android.internal.telephony.PhoneConstants; public abstract class CellLocation { /** - * Request an update of the current location. If the location has changed, - * a broadcast will be sent to everyone registered with {@link - * PhoneStateListener#LISTEN_CELL_LOCATION}. + * This method will not do anything. + * + * Whenever location changes, a callback will automatically be be sent to + * all registrants of {@link PhoneStateListener#LISTEN_CELL_LOCATION}. + * + * <p>This method is a no-op for callers targeting SDK level 31 or greater. + * <p>This method is a no-op for callers that target SDK level 29 or 30 and lack + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. + * <p>This method is a no-op for callers that target SDK level 28 or below and lack + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. + * + * Callers wishing to request a single location update should use + * {@link TelephonyManager#requestCellInfoUpdate}. + * + * @deprecated this method has undesirable side-effects, and it calls into the OS without + * access to a {@link android.content.Context Context}, meaning that certain safety checks and + * attribution are error-prone. Given that this method has numerous downsides, and given that + * there are long-available superior alternatives, callers are strongly discouraged from using + * this method. */ + @Deprecated public static void requestLocationUpdate() { + // Since this object doesn't have a context, this is the best we can do. + final Context appContext = ActivityThread.currentApplication(); + if (appContext == null) return; // should never happen + try { ITelephony phone = ITelephony.Stub.asInterface( TelephonyFrameworkInitializer @@ -43,7 +66,7 @@ public abstract class CellLocation { .getTelephonyServiceRegisterer() .get()); if (phone != null) { - phone.updateServiceLocation(); + phone.updateServiceLocationWithPackageName(appContext.getOpPackageName()); } } catch (RemoteException ex) { // ignore it diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java index c667165e7a0e..e91d6fc9d801 100644 --- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java +++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java @@ -72,28 +72,20 @@ public final class DataSpecificRegistrationInfo implements Parcelable { /** * Provides network support info for LTE VoPS and LTE Emergency bearer support */ + @Nullable private final LteVopsSupportInfo mLteVopsSupportInfo; /** - * Indicates if it's using carrier aggregation - * - * @hide - */ - public boolean mIsUsingCarrierAggregation; - - /** * @hide */ DataSpecificRegistrationInfo( int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable, - boolean isEnDcAvailable, LteVopsSupportInfo lteVops, - boolean isUsingCarrierAggregation) { + boolean isEnDcAvailable, @Nullable LteVopsSupportInfo lteVops) { this.maxDataCalls = maxDataCalls; this.isDcNrRestricted = isDcNrRestricted; this.isNrAvailable = isNrAvailable; this.isEnDcAvailable = isEnDcAvailable; this.mLteVopsSupportInfo = lteVops; - this.mIsUsingCarrierAggregation = isUsingCarrierAggregation; } /** @@ -102,32 +94,29 @@ public final class DataSpecificRegistrationInfo implements Parcelable { * @param dsri another data specific registration info * @hide */ - DataSpecificRegistrationInfo(DataSpecificRegistrationInfo dsri) { + DataSpecificRegistrationInfo(@NonNull DataSpecificRegistrationInfo dsri) { maxDataCalls = dsri.maxDataCalls; isDcNrRestricted = dsri.isDcNrRestricted; isNrAvailable = dsri.isNrAvailable; isEnDcAvailable = dsri.isEnDcAvailable; mLteVopsSupportInfo = dsri.mLteVopsSupportInfo; - mIsUsingCarrierAggregation = dsri.mIsUsingCarrierAggregation; } - private DataSpecificRegistrationInfo(Parcel source) { + private DataSpecificRegistrationInfo(/* @NonNull */ Parcel source) { maxDataCalls = source.readInt(); isDcNrRestricted = source.readBoolean(); isNrAvailable = source.readBoolean(); isEnDcAvailable = source.readBoolean(); mLteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source); - mIsUsingCarrierAggregation = source.readBoolean(); } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(/* @NonNull */ Parcel dest, int flags) { dest.writeInt(maxDataCalls); dest.writeBoolean(isDcNrRestricted); dest.writeBoolean(isNrAvailable); dest.writeBoolean(isEnDcAvailable); mLteVopsSupportInfo.writeToParcel(dest, flags); - dest.writeBoolean(mIsUsingCarrierAggregation); } @Override @@ -144,8 +133,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { .append(" isDcNrRestricted = " + isDcNrRestricted) .append(" isNrAvailable = " + isNrAvailable) .append(" isEnDcAvailable = " + isEnDcAvailable) - .append(" " + mLteVopsSupportInfo.toString()) - .append(" mIsUsingCarrierAggregation = " + mIsUsingCarrierAggregation) + .append(" " + mLteVopsSupportInfo) .append(" }") .toString(); } @@ -153,7 +141,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { @Override public int hashCode() { return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable, - mLteVopsSupportInfo, mIsUsingCarrierAggregation); + mLteVopsSupportInfo); } @Override @@ -167,8 +155,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { && this.isDcNrRestricted == other.isDcNrRestricted && this.isNrAvailable == other.isNrAvailable && this.isEnDcAvailable == other.isEnDcAvailable - && this.mLteVopsSupportInfo.equals(other.mLteVopsSupportInfo) - && this.mIsUsingCarrierAggregation == other.mIsUsingCarrierAggregation; + && Objects.equals(mLteVopsSupportInfo, other.mLteVopsSupportInfo); } public static final @NonNull Parcelable.Creator<DataSpecificRegistrationInfo> CREATOR = @@ -192,23 +179,4 @@ public final class DataSpecificRegistrationInfo implements Parcelable { return mLteVopsSupportInfo; } - /** - * Set the flag indicating if using carrier aggregation. - * - * @param isUsingCarrierAggregation {@code true} if using carrier aggregation. - * @hide - */ - public void setIsUsingCarrierAggregation(boolean isUsingCarrierAggregation) { - mIsUsingCarrierAggregation = isUsingCarrierAggregation; - } - - /** - * Get whether network has configured carrier aggregation or not. - * - * @return {@code true} if using carrier aggregation. - * @hide - */ - public boolean isUsingCarrierAggregation() { - return mIsUsingCarrierAggregation; - } } diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java index be85b30f272b..2704418935d9 100644 --- a/telephony/java/android/telephony/DisconnectCause.java +++ b/telephony/java/android/telephony/DisconnectCause.java @@ -17,16 +17,14 @@ package android.telephony; import android.annotation.NonNull; -import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; /** * Describes the cause of a disconnected call. Those disconnect causes can be converted into a more * generic {@link android.telecom.DisconnectCause} object. * - * @hide + * Used in {@link PhoneStateListener#onCallDisconnectCauseChanged}. */ -@SystemApi public final class DisconnectCause { /** The disconnect cause is not valid (Not received a disconnect cause) */ @@ -337,20 +335,17 @@ public final class DisconnectCause { /** * Indicates that the call is dropped due to RTCP inactivity, primarily due to media path * disruption. - * @hide */ public static final int MEDIA_TIMEOUT = 77; /** * Indicates that an emergency call cannot be placed over WFC because the service is not * available in the current location. - * @hide */ public static final int EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 78; /** * Indicates that WiFi calling service is not available in the current location. - * @hide */ public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79; diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java index 45deea206cfc..3f671ca2d809 100644 --- a/telephony/java/android/telephony/MbmsDownloadSession.java +++ b/telephony/java/android/telephony/MbmsDownloadSession.java @@ -231,6 +231,8 @@ public class MbmsDownloadSession implements AutoCloseable { private static final String DESTINATION_SANITY_CHECK_FILE_NAME = "destinationSanityCheckFile"; + private static final int MAX_SERVICE_ANNOUNCEMENT_SIZE = 10 * 1024; // 10KB + private static AtomicBoolean sIsInitialized = new AtomicBoolean(false); private final Context mContext; @@ -318,6 +320,16 @@ public class MbmsDownloadSession implements AutoCloseable { return session; } + /** + * Returns the maximum size of the service announcement descriptor that can be provided via + * {@link #addServiceAnnouncement} + * @return The maximum length of the byte array passed as an argument to + * {@link #addServiceAnnouncement}. + */ + public static int getMaximumServiceAnnouncementSize() { + return MAX_SERVICE_ANNOUNCEMENT_SIZE; + } + private int bindAndInitialize() { mServiceConnection = new ServiceConnection() { @Override @@ -424,6 +436,61 @@ public class MbmsDownloadSession implements AutoCloseable { } /** + * Inform the middleware of a service announcement descriptor received from a group + * communication server. + * + * When participating in a group call via the {@link MbmsGroupCallSession} API, applications may + * receive a service announcement descriptor from the group call server that informs them of + * files that may be relevant to users communicating on the group call. + * + * After supplying the service announcement descriptor received from the server to the + * middleware via this API, applications will receive information on the available files via + * {@link MbmsDownloadSessionCallback#onFileServicesUpdated}, and the available files will be + * downloadable via {@link MbmsDownloadSession#download} like other files published via + * {@link MbmsDownloadSessionCallback#onFileServicesUpdated}. + * + * Asynchronous error codes via the {@link MbmsDownloadSessionCallback#onError(int, String)} + * callback may include any of the errors that are not specific to the streaming use-case. + * + * May throw an {@link IllegalStateException} when the middleware has not yet been bound, + * or an {@link IllegalArgumentException} if the byte array is too large, or an + * {@link UnsupportedOperationException} if the middleware has not implemented this method. + * + * @param contents The contents of the service announcement descriptor received from the + * group call server. If the size of this array is greater than the value of + * {@link #getMaximumServiceAnnouncementSize()}, an + * {@link IllegalArgumentException} will be thrown. + */ + public void addServiceAnnouncement(@NonNull byte[] contents) { + IMbmsDownloadService downloadService = mService.get(); + if (downloadService == null) { + throw new IllegalStateException("Middleware not yet bound"); + } + + if (contents.length > MAX_SERVICE_ANNOUNCEMENT_SIZE) { + throw new IllegalArgumentException("File too large"); + } + + try { + int returnCode = downloadService.addServiceAnnouncement( + mSubscriptionId, contents); + if (returnCode == MbmsErrors.UNKNOWN) { + // Unbind and throw an obvious error + close(); + throw new IllegalStateException("Middleware must not return an unknown error code"); + } + if (returnCode != MbmsErrors.SUCCESS) { + sendErrorToApp(returnCode, null); + } + } catch (RemoteException e) { + Log.w(LOG_TAG, "Remote process died"); + mService.set(null); + sIsInitialized.set(false); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + } + } + + /** * Sets the temp file root for downloads. * All temp files created for the middleware to write to will be contained in the specified * directory. Applications that wish to specify a location only need to call this method once diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java index 2b72ab7635c3..debb119c94bc 100644 --- a/telephony/java/android/telephony/ModemActivityInfo.java +++ b/telephony/java/android/telephony/ModemActivityInfo.java @@ -234,7 +234,7 @@ public final class ModemActivityInfo implements Parcelable { } /** - * Indicate if the ModemActivityInfo is invalid due to modem's invalid reporting. + * Indicates if the modem has reported valid {@link ModemActivityInfo}. * * @return {@code true} if this {@link ModemActivityInfo} record is valid, * {@code false} otherwise. diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index 6a67ad2b72cc..aee1e84ca356 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -218,6 +218,9 @@ public final class NetworkRegistrationInfo implements Parcelable { @NonNull private String mRplmn; + // Updated based on the accessNetworkTechnology + private boolean mIsUsingCarrierAggregation; + /** * @param domain Network domain. Must be a {@link Domain}. For transport type * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, this must set to {@link #DOMAIN_PS}. @@ -251,7 +254,7 @@ public final class NetworkRegistrationInfo implements Parcelable { mRegistrationState = registrationState; mRoamingType = (registrationState == REGISTRATION_STATE_ROAMING) ? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING; - mAccessNetworkTechnology = accessNetworkTechnology; + setAccessNetworkTechnology(accessNetworkTechnology); mRejectCause = rejectCause; mAvailableServices = (availableServices != null) ? new ArrayList<>(availableServices) : new ArrayList<>(); @@ -290,13 +293,11 @@ public final class NetworkRegistrationInfo implements Parcelable { @Nullable CellIdentity cellIdentity, @Nullable String rplmn, int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable, - LteVopsSupportInfo lteVopsSupportInfo, - boolean isUsingCarrierAggregation) { + LteVopsSupportInfo lteVopsSupportInfo) { this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause, emergencyOnly, availableServices, cellIdentity, rplmn); mDataSpecificInfo = new DataSpecificRegistrationInfo( - maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo, - isUsingCarrierAggregation); + maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo); updateNrState(); } @@ -317,6 +318,7 @@ public final class NetworkRegistrationInfo implements Parcelable { DataSpecificRegistrationInfo.class.getClassLoader()); mNrState = source.readInt(); mRplmn = source.readString(); + mIsUsingCarrierAggregation = source.readBoolean(); } /** @@ -331,6 +333,7 @@ public final class NetworkRegistrationInfo implements Parcelable { mRegistrationState = nri.mRegistrationState; mRoamingType = nri.mRoamingType; mAccessNetworkTechnology = nri.mAccessNetworkTechnology; + mIsUsingCarrierAggregation = nri.mIsUsingCarrierAggregation; mRejectCause = nri.mRejectCause; mEmergencyOnly = nri.mEmergencyOnly; mAvailableServices = new ArrayList<>(nri.mAvailableServices); @@ -389,7 +392,7 @@ public final class NetworkRegistrationInfo implements Parcelable { } /** - * @return {@code true} if registered on roaming network, {@code false} otherwise. + * @return {@code true} if registered on roaming or home network, {@code false} otherwise. */ public boolean isRegistered() { return mRegistrationState == REGISTRATION_STATE_HOME @@ -397,7 +400,7 @@ public final class NetworkRegistrationInfo implements Parcelable { } /** - * @return {@code true} if registered on roaming network, {@code false} otherwise. + * @return {@code true} if searching for service, {@code false} otherwise. */ public boolean isSearching() { return mRegistrationState == REGISTRATION_STATE_NOT_REGISTERED_SEARCHING; @@ -484,9 +487,7 @@ public final class NetworkRegistrationInfo implements Parcelable { if (tech == TelephonyManager.NETWORK_TYPE_LTE_CA) { // For old device backward compatibility support tech = TelephonyManager.NETWORK_TYPE_LTE; - if (mDataSpecificInfo != null) { - mDataSpecificInfo.setIsUsingCarrierAggregation(true); - } + mIsUsingCarrierAggregation = true; } mAccessNetworkTechnology = tech; } @@ -511,6 +512,27 @@ public final class NetworkRegistrationInfo implements Parcelable { } /** + * Set whether network has configured carrier aggregation or not. + * + * @param isUsingCarrierAggregation set whether or not carrier aggregation is used. + * + * @hide + */ + public void setIsUsingCarrierAggregation(boolean isUsingCarrierAggregation) { + mIsUsingCarrierAggregation = isUsingCarrierAggregation; + } + + /** + * Get whether network has configured carrier aggregation or not. + * + * @return {@code true} if using carrier aggregation. + * @hide + */ + public boolean isUsingCarrierAggregation() { + return mIsUsingCarrierAggregation; + } + + /** * @hide */ @Nullable @@ -617,6 +639,7 @@ public final class NetworkRegistrationInfo implements Parcelable { .append(" dataSpecificInfo=").append(mDataSpecificInfo) .append(" nrState=").append(nrStateToString(mNrState)) .append(" rRplmn=").append(mRplmn) + .append(" isUsingCarrierAggregation=").append(mIsUsingCarrierAggregation) .append("}").toString(); } @@ -624,7 +647,8 @@ public final class NetworkRegistrationInfo implements Parcelable { public int hashCode() { return Objects.hash(mDomain, mTransportType, mRegistrationState, mRoamingType, mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices, - mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState, mRplmn); + mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState, mRplmn, + mIsUsingCarrierAggregation); } @Override @@ -644,6 +668,7 @@ public final class NetworkRegistrationInfo implements Parcelable { && mRejectCause == other.mRejectCause && mEmergencyOnly == other.mEmergencyOnly && mAvailableServices.equals(other.mAvailableServices) + && mIsUsingCarrierAggregation == other.mIsUsingCarrierAggregation && Objects.equals(mCellIdentity, other.mCellIdentity) && Objects.equals(mVoiceSpecificInfo, other.mVoiceSpecificInfo) && Objects.equals(mDataSpecificInfo, other.mDataSpecificInfo) @@ -670,6 +695,7 @@ public final class NetworkRegistrationInfo implements Parcelable { dest.writeParcelable(mDataSpecificInfo, 0); dest.writeInt(mNrState); dest.writeString(mRplmn); + dest.writeBoolean(mIsUsingCarrierAggregation); } /** diff --git a/telephony/java/android/telephony/PinResult.java b/telephony/java/android/telephony/PinResult.java index 98d6448e77ea..c2a4f33e95b9 100644 --- a/telephony/java/android/telephony/PinResult.java +++ b/telephony/java/android/telephony/PinResult.java @@ -37,6 +37,7 @@ public final class PinResult implements Parcelable { PIN_RESULT_TYPE_SUCCESS, PIN_RESULT_TYPE_INCORRECT, PIN_RESULT_TYPE_FAILURE, + PIN_RESULT_TYPE_ABORTED, }) public @interface PinResultType {} @@ -55,6 +56,11 @@ public final class PinResult implements Parcelable { */ public static final int PIN_RESULT_TYPE_FAILURE = PhoneConstants.PIN_GENERAL_FAILURE; + /** + * Indicates that the pin attempt was aborted. + */ + public static final int PIN_RESULT_TYPE_ABORTED = PhoneConstants.PIN_OPERATION_ABORTED; + private static final PinResult sFailedResult = new PinResult(PinResult.PIN_RESULT_TYPE_FAILURE, -1); diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 9e2ba6875577..3e7464739f9f 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -1412,29 +1412,14 @@ public class ServiceState implements Parcelable { /** @hide */ public boolean isUsingCarrierAggregation() { - boolean isUsingCa = false; - NetworkRegistrationInfo nri = getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - if (nri != null) { - DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); - if (dsri != null) { - isUsingCa = dsri.isUsingCarrierAggregation(); - } - } - return isUsingCa || getCellBandwidths().length > 1; - } + if (getCellBandwidths().length > 1) return true; - /** @hide */ - public void setIsUsingCarrierAggregation(boolean ca) { - NetworkRegistrationInfo nri = getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - if (nri != null) { - DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); - if (dsri != null) { - dsri.setIsUsingCarrierAggregation(ca); - addNetworkRegistrationInfo(nri); + synchronized (mNetworkRegistrationInfos) { + for (NetworkRegistrationInfo nri : mNetworkRegistrationInfos) { + if (nri.isUsingCarrierAggregation()) return true; } } + return false; } /** diff --git a/telephony/java/android/telephony/SmsCbEtwsInfo.java b/telephony/java/android/telephony/SmsCbEtwsInfo.java index 2a7f7ad81e3b..a98916d715e4 100644 --- a/telephony/java/android/telephony/SmsCbEtwsInfo.java +++ b/telephony/java/android/telephony/SmsCbEtwsInfo.java @@ -27,6 +27,7 @@ import com.android.internal.telephony.uicc.IccUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.time.DateTimeException; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Arrays; @@ -173,7 +174,7 @@ public final class SmsCbEtwsInfo implements Parcelable { /** * Returns the Warning-Security-Information timestamp (GSM primary notifications only). * As of Release 10, 3GPP TS 23.041 states that the UE shall ignore this value if received. - * @return a UTC timestamp in System.currentTimeMillis() format, or 0 if not present + * @return a UTC timestamp in System.currentTimeMillis() format, or 0 if not present or invalid. */ public long getPrimaryNotificationTimestamp() { if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 7) { @@ -201,18 +202,23 @@ public final class SmsCbEtwsInfo implements Parcelable { // timezoneOffset is in quarter hours. int timeZoneOffsetSeconds = timezoneOffset * 15 * 60; - LocalDateTime localDateTime = LocalDateTime.of( - // We only need to support years above 2000. - year + 2000, - month /* 1-12 */, - day, - hour, - minute, - second); - - long epochSeconds = localDateTime.toEpochSecond(ZoneOffset.UTC) - timeZoneOffsetSeconds; - // Convert to milliseconds, ignore overflow. - return epochSeconds * 1000; + try { + LocalDateTime localDateTime = LocalDateTime.of( + // We only need to support years above 2000. + year + 2000, + month /* 1-12 */, + day, + hour, + minute, + second); + + long epochSeconds = localDateTime.toEpochSecond(ZoneOffset.UTC) - timeZoneOffsetSeconds; + // Convert to milliseconds, ignore overflow. + return epochSeconds * 1000; + } catch (DateTimeException ex) { + // No-op + } + return 0; } /** diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index b376660f839e..183fdcce1ca4 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -670,10 +670,12 @@ public final class SmsManager { } if (priority < 0x00 || priority > 0x03) { + Log.e(TAG, "Invalid Priority " + priority); priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED; } if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) { + Log.e(TAG, "Invalid Validity Period " + validityPeriod); validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED; } @@ -1231,10 +1233,12 @@ public final class SmsManager { } if (priority < 0x00 || priority > 0x03) { + Log.e(TAG, "Invalid Priority " + priority); priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED; } if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) { + Log.e(TAG, "Invalid Validity Period " + validityPeriod); validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED; } diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index e537f666d4c0..717a9b155cbf 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -255,28 +255,6 @@ public class SmsMessage { } /** - * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the - * +CMT unsolicited response (PDU mode, of course) - * +CMT: [<alpha>],<length><CR><LF><pdu> - * - * Only public for debugging and for RIL - * - * {@hide} - */ - public static SmsMessage newFromCMT(byte[] pdu) { - // received SMS in 3GPP format - SmsMessageBase wrappedMessage = - com.android.internal.telephony.gsm.SmsMessage.newFromCMT(pdu); - - if (wrappedMessage != null) { - return new SmsMessage(wrappedMessage); - } else { - Rlog.e(LOG_TAG, "newFromCMT(): wrappedMessage is null"); - return null; - } - } - - /** * Creates an SmsMessage from an SMS EF record. * * @param index Index of SMS EF record. @@ -321,12 +299,9 @@ public class SmsMessage { * @param data Message data. * @param isCdma Indicates weather the type of the SMS is CDMA. * @return An SmsMessage representing the message. - * - * @hide */ - @SystemApi @Nullable - public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) { + public static SmsMessage createSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) { SmsMessageBase wrappedMessage; if (isCdma) { @@ -342,6 +317,23 @@ public class SmsMessage { } /** + * Create an SmsMessage from a native SMS-Submit PDU, specified by Bluetooth Message Access + * Profile Specification v1.4.2 5.8. + * This is used by Bluetooth MAP profile to decode message when sending non UTF-8 SMS messages. + * + * @param data Message data. + * @param isCdma Indicates weather the type of the SMS is CDMA. + * @return An SmsMessage representing the message. + * + * @hide + */ + @SystemApi + @Nullable + public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) { + return null; + } + + /** * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the * length in bytes (not hex chars) less the SMSC header * @@ -496,7 +488,10 @@ public class SmsMessage { String newMsgBody = null; Resources r = Resources.getSystem(); if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) { - newMsgBody = Sms7BitEncodingTranslator.translate(text, isCdma); + // 7-bit ASCII table based translation is required only for CDMA single-part SMS since + // ENCODING_7BIT_ASCII is used for CDMA single-part SMS and ENCODING_GSM_7BIT_ALPHABET + // is used for CDMA multi-part SMS. + newMsgBody = Sms7BitEncodingTranslator.translate(text, isCdma && ted.msgCount == 1); } if (TextUtils.isEmpty(newMsgBody)) { newMsgBody = text; diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index e9ee06c246ba..4ad52ae5e077 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1111,11 +1111,15 @@ public class SubscriptionManager { * individual records themselves. When a change occurs the onSubscriptionsChanged method of * the listener will be invoked immediately if there has been a notification. The * onSubscriptionChanged method will also be triggered once initially when calling this - * function. + * function. The callback will be invoked on the looper specified in the listener's constructor. * * @param listener an instance of {@link OnSubscriptionsChangedListener} with * onSubscriptionsChanged overridden. + * + * @deprecated Will get exception if the parameter listener is not initialized with a Looper. + * Use {@link #addOnSubscriptionsChangedListener(Executor, OnSubscriptionsChangedListener)}. */ + @Deprecated public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { if (listener == null) return; addOnSubscriptionsChangedListener(listener.mExecutor, listener); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 8ae1ee99b060..4b5399e74abf 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -113,8 +113,6 @@ import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.SmsApplication; import com.android.telephony.Rlog; -import java.io.FileInputStream; -import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -127,8 +125,6 @@ import java.util.Objects; import java.util.UUID; import java.util.concurrent.Executor; import java.util.function.Consumer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Provides access to information about the telephony services on @@ -2341,58 +2337,6 @@ public class TelephonyManager { } /** - * Enables location update notifications. {@link PhoneStateListener#onCellLocationChanged - * PhoneStateListener.onCellLocationChanged} will be called on location updates. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES) - public void enableLocationUpdates() { - enableLocationUpdates(getSubId()); - } - - /** - * Enables location update notifications for a subscription. - * {@link PhoneStateListener#onCellLocationChanged - * PhoneStateListener.onCellLocationChanged} will be called on location updates. - * - * @param subId for which the location updates are enabled - * @hide - */ - @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES) - public void enableLocationUpdates(int subId) { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) - telephony.enableLocationUpdatesForSubscriber(subId); - } catch (RemoteException ex) { - } catch (NullPointerException ex) { - } - } - - /** - * Disables location update notifications. {@link PhoneStateListener#onCellLocationChanged - * PhoneStateListener.onCellLocationChanged} will be called on location updates. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES) - public void disableLocationUpdates() { - disableLocationUpdates(getSubId()); - } - - /** @hide */ - public void disableLocationUpdates(int subId) { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) - telephony.disableLocationUpdatesForSubscriber(subId); - } catch (RemoteException ex) { - } catch (NullPointerException ex) { - } - } - - /** * Returns the neighboring cell information of the device. * * @return List of NeighboringCellInfo or null if info unavailable. @@ -2592,7 +2536,8 @@ public class TelephonyManager { return PhoneConstants.PHONE_TYPE_CDMA; case RILConstants.NETWORK_MODE_LTE_ONLY: - if (getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) { + if (TelephonyProperties.lte_on_cdma_device().orElse( + PhoneConstants.LTE_ON_CDMA_FALSE) == PhoneConstants.LTE_ON_CDMA_TRUE) { return PhoneConstants.PHONE_TYPE_CDMA; } else { return PhoneConstants.PHONE_TYPE_GSM; @@ -2603,35 +2548,6 @@ public class TelephonyManager { } /** - * The contents of the /proc/cmdline file - */ - @UnsupportedAppUsage - private static String getProcCmdLine() - { - String cmdline = ""; - FileInputStream is = null; - try { - is = new FileInputStream("/proc/cmdline"); - byte [] buffer = new byte[2048]; - int count = is.read(buffer); - if (count > 0) { - cmdline = new String(buffer, 0, count); - } - } catch (IOException e) { - Rlog.d(TAG, "No /proc/cmdline exception=" + e); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - } - } - } - Rlog.d(TAG, "/proc/cmdline=" + cmdline); - return cmdline; - } - - /** * @return The max value for the timeout passed in {@link #requestNumberVerification}. * @hide */ @@ -2640,56 +2556,6 @@ public class TelephonyManager { return MAX_NUMBER_VERIFICATION_TIMEOUT_MILLIS; } - /** Kernel command line */ - private static final String sKernelCmdLine = getProcCmdLine(); - - /** Pattern for selecting the product type from the kernel command line */ - private static final Pattern sProductTypePattern = - Pattern.compile("\\sproduct_type\\s*=\\s*(\\w+)"); - - /** The ProductType used for LTE on CDMA devices */ - private static final String sLteOnCdmaProductType = - TelephonyProperties.lte_on_cdma_product_type().orElse(""); - - /** - * Return if the current radio is LTE on CDMA. This - * is a tri-state return value as for a period of time - * the mode may be unknown. - * - * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE} - * or {@link PhoneConstants#LTE_ON_CDMA_TRUE} - * - * @hide - */ - @UnsupportedAppUsage - public static int getLteOnCdmaModeStatic() { - int retVal; - int curVal; - String productType = ""; - - curVal = TelephonyProperties.lte_on_cdma_device().orElse( - PhoneConstants.LTE_ON_CDMA_UNKNOWN); - retVal = curVal; - if (retVal == PhoneConstants.LTE_ON_CDMA_UNKNOWN) { - Matcher matcher = sProductTypePattern.matcher(sKernelCmdLine); - if (matcher.find()) { - productType = matcher.group(1); - if (sLteOnCdmaProductType.equals(productType)) { - retVal = PhoneConstants.LTE_ON_CDMA_TRUE; - } else { - retVal = PhoneConstants.LTE_ON_CDMA_FALSE; - } - } else { - retVal = PhoneConstants.LTE_ON_CDMA_FALSE; - } - } - - Rlog.d(TAG, "getLteOnCdmaMode=" + retVal + " curVal=" + curVal + - " product_type='" + productType + - "' lteOnCdmaProductType='" + sLteOnCdmaProductType + "'"); - return retVal; - } - // // // Current Network @@ -9307,17 +9173,14 @@ public class TelephonyManager { return RADIO_POWER_UNAVAILABLE; } - /** @hide */ + /** + * This method should not be used due to privacy and stability concerns. + * + * @hide + */ @SystemApi - @SuppressLint("Doclava125") public void updateServiceLocation() { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) - telephony.updateServiceLocation(); - } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#updateServiceLocation", e); - } + Log.e(TAG, "Do not call TelephonyManager#updateServiceLocation()"); } /** @hide */ diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java index cdff651c9c3d..e890acb36b48 100644 --- a/telephony/java/android/telephony/TelephonyScanManager.java +++ b/telephony/java/android/telephony/TelephonyScanManager.java @@ -30,6 +30,7 @@ import android.os.Parcelable; import android.os.RemoteException; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.telephony.ITelephony; import com.android.telephony.Rlog; @@ -55,6 +56,8 @@ public final class TelephonyScanManager { public static final int CALLBACK_SCAN_COMPLETE = 3; /** @hide */ public static final int CALLBACK_RESTRICTED_SCAN_RESULTS = 4; + /** @hide */ + public static final int CALLBACK_TELEPHONY_DIED = 5; /** @hide */ public static final int INVALID_SCAN_ID = -1; @@ -103,17 +106,44 @@ public final class TelephonyScanManager { } private final Looper mLooper; + private final Handler mHandler; private final Messenger mMessenger; private final SparseArray<NetworkScanInfo> mScanInfo = new SparseArray<NetworkScanInfo>(); + private final Binder.DeathRecipient mDeathRecipient; public TelephonyScanManager() { HandlerThread thread = new HandlerThread(TAG); thread.start(); mLooper = thread.getLooper(); - mMessenger = new Messenger(new Handler(mLooper) { + mHandler = new Handler(mLooper) { @Override public void handleMessage(Message message) { checkNotNull(message, "message cannot be null"); + if (message.what == CALLBACK_TELEPHONY_DIED) { + // If there are no objects in mScanInfo then binder death will simply return. + synchronized (mScanInfo) { + for (int i = 0; i < mScanInfo.size(); i++) { + NetworkScanInfo nsi = mScanInfo.valueAt(i); + // At this point we go into panic mode and ignore errors that would + // normally stop the show in order to try and clean up as gracefully + // as possible. + if (nsi == null) continue; // shouldn't be possible + Executor e = nsi.mExecutor; + NetworkScanCallback cb = nsi.mCallback; + if (e == null || cb == null) continue; + try { + e.execute( + () -> cb.onError(NetworkScan.ERROR_MODEM_UNAVAILABLE)); + } catch (java.util.concurrent.RejectedExecutionException ignore) { + // ignore so that we can continue + } + } + + mScanInfo.clear(); + } + return; + } + NetworkScanInfo nsi; synchronized (mScanInfo) { nsi = mScanInfo.get(message.arg2); @@ -158,6 +188,9 @@ public final class TelephonyScanManager { Rlog.d(TAG, "onError: " + errorCode); callback.onError(errorCode); }); + synchronized (mScanInfo) { + mScanInfo.remove(message.arg2); + } } catch (Exception e) { Rlog.e(TAG, "Exception in networkscan callback onError", e); } @@ -168,7 +201,9 @@ public final class TelephonyScanManager { Rlog.d(TAG, "onComplete"); callback.onComplete(); }); - mScanInfo.remove(message.arg2); + synchronized (mScanInfo) { + mScanInfo.remove(message.arg2); + } } catch (Exception e) { Rlog.e(TAG, "Exception in networkscan callback onComplete", e); } @@ -178,7 +213,14 @@ public final class TelephonyScanManager { break; } } - }); + }; + mMessenger = new Messenger(mHandler); + mDeathRecipient = new Binder.DeathRecipient() { + @Override + public void binderDied() { + mHandler.obtainMessage(CALLBACK_TELEPHONY_DIED).sendToTarget(); + } + }; } /** @@ -189,7 +231,7 @@ public final class TelephonyScanManager { * * <p> * Requires Permission: - * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} and + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} * Or the calling app has carrier privileges. @see #hasCarrierPrivileges * @@ -204,19 +246,26 @@ public final class TelephonyScanManager { NetworkScanRequest request, Executor executor, NetworkScanCallback callback, String callingPackage, @Nullable String callingFeatureId) { try { - ITelephony telephony = getITelephony(); - if (telephony != null) { - synchronized (mScanInfo) { - int scanId = telephony.requestNetworkScan( - subId, request, mMessenger, new Binder(), callingPackage, - callingFeatureId); - if (scanId == INVALID_SCAN_ID) { - Rlog.e(TAG, "Failed to initiate network scan"); - return null; - } - saveScanInfo(scanId, request, executor, callback); - return new NetworkScan(scanId, subId); - } + final ITelephony telephony = getITelephony(); + if (telephony == null) return null; + + int scanId = telephony.requestNetworkScan( + subId, request, mMessenger, new Binder(), callingPackage, + callingFeatureId); + if (scanId == INVALID_SCAN_ID) { + Rlog.e(TAG, "Failed to initiate network scan"); + return null; + } + synchronized (mScanInfo) { + // We link to death whenever a scan is started to ensure that we are linked + // at the point that phone process death might matter. + // We never unlink because: + // - Duplicate links to death with the same callback do not result in + // extraneous callbacks (the tracking de-dupes). + // - Receiving binderDeath() when no scans are active is a no-op. + telephony.asBinder().linkToDeath(mDeathRecipient, 0); + saveScanInfo(scanId, request, executor, callback); + return new NetworkScan(scanId, subId); } } catch (RemoteException ex) { Rlog.e(TAG, "requestNetworkScan RemoteException", ex); @@ -226,6 +275,7 @@ public final class TelephonyScanManager { return null; } + @GuardedBy("mScanInfo") private void saveScanInfo( int id, NetworkScanRequest request, Executor executor, NetworkScanCallback callback) { mScanInfo.put(id, new NetworkScanInfo(request, executor, callback)); diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java index 81af99fb40b7..d21a05103241 100644 --- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java +++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java @@ -683,5 +683,32 @@ public class ImsCallSessionListener { e.rethrowFromSystemServer(); } } + + /** + * Notifies the result of transfer request. + * @hide + */ + public void callSessionTransferred() { + try { + mListener.callSessionTransferred(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Notifies the result of transfer request. + * + * @param reasonInfo {@link ImsReasonInfo} containing a reason for the + * session transfer failure + * @hide + */ + public void callSessionTransferFailed(ImsReasonInfo reasonInfo) { + try { + mListener.callSessionTransferFailed(reasonInfo); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } } diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java index ec112790a144..a427d056f915 100644 --- a/telephony/java/android/telephony/ims/RcsUceAdapter.java +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -31,7 +31,7 @@ import android.os.RemoteException; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.ims.aidl.IImsRcsController; import android.telephony.ims.aidl.IRcsUceControllerCallback; -import android.telephony.ims.feature.RcsFeature; +import android.telephony.ims.aidl.IRcsUcePublishStateCallback; import android.util.Log; import java.lang.annotation.Retention; @@ -185,6 +185,58 @@ public class RcsUceAdapter { }) public @interface PublishState {} + /** + * An application can use {@link #registerPublishStateCallback} to register a + * {@link PublishStateCallback), which will notify the user when the publish state to the + * network changes. + * @hide + */ + public static class PublishStateCallback { + + private static class PublishStateBinder extends IRcsUcePublishStateCallback.Stub { + + private final PublishStateCallback mLocalCallback; + private Executor mExecutor; + + PublishStateBinder(PublishStateCallback c) { + mLocalCallback = c; + } + + @Override + public void onPublishStateChanged(int publishState) { + if (mLocalCallback == null) return; + + long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mLocalCallback.onChanged(publishState)); + } finally { + restoreCallingIdentity(callingIdentity); + } + } + + private void setExecutor(Executor executor) { + mExecutor = executor; + } + } + + private final PublishStateBinder mBinder = new PublishStateBinder(this); + + /**@hide*/ + public final IRcsUcePublishStateCallback getBinder() { + return mBinder; + } + + private void setExecutor(Executor executor) { + mBinder.setExecutor(executor); + } + + /** + * Notifies the callback when the publish state has changed. + * @param publishState The latest update to the publish state. + */ + public void onChanged(@PublishState int publishState) { + } + } /** * Provides a one-time callback for the response to a UCE request. After this callback is called @@ -321,6 +373,8 @@ public class RcsUceAdapter { try { return imsRcsController.getUcePublishState(mSubId); + } catch (android.os.ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); } catch (RemoteException e) { Log.e(TAG, "Error calling IImsRcsController#getUcePublishState", e); throw new ImsException("Remote IMS Service is not available", @@ -329,6 +383,91 @@ public class RcsUceAdapter { } /** + * Registers a {@link PublishStateCallback} with the system, which will provide publish state + * updates for the subscription specified in {@link ImsManager@getRcsManager(subid)}. + * <p> + * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to subscription + * changed events and call {@link #unregisterPublishStateCallback} to clean up. + * <p> + * The registered {@link PublishStateCallback} will also receive a callback when it is + * registered with the current publish state. + * + * @param executor The executor the listener callback events should be run on. + * @param c The {@link PublishStateCallback} to be added. + * @throws ImsException if the subscription associated with this callback is valid, but + * the {@link ImsService} associated with the subscription is not available. This can happen if + * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed + * reason. + * @hide + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void registerPublishStateCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull PublishStateCallback c) throws ImsException { + if (c == null) { + throw new IllegalArgumentException("Must include a non-null PublishStateCallback."); + } + if (executor == null) { + throw new IllegalArgumentException("Must include a non-null Executor."); + } + + IImsRcsController imsRcsController = getIImsRcsController(); + if (imsRcsController == null) { + Log.e(TAG, "registerPublishStateCallback : IImsRcsController is null"); + throw new ImsException("Cannot find remote IMS service", + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + + c.setExecutor(executor); + try { + imsRcsController.registerUcePublishStateCallback(mSubId, c.getBinder()); + } catch (android.os.ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); + } catch (RemoteException e) { + Log.e(TAG, "Error calling IImsRcsController#registerUcePublishStateCallback", e); + throw new ImsException("Remote IMS Service is not available", + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + } + + /** + * Removes an existing {@link PublishStateCallback}. + * <p> + * When the subscription associated with this callback is removed + * (SIM removed, ESIM swap,etc...), this callback will automatically be removed. If this method + * is called for an inactive subscription, it will result in a no-op. + * + * @param c The callback to be unregistered. + * @throws ImsException if the subscription associated with this callback is valid, but + * the {@link ImsService} associated with the subscription is not available. This can happen if + * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed + * reason. + * @hide + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void unregisterPublishStateCallback(@NonNull PublishStateCallback c) + throws ImsException { + if (c == null) { + throw new IllegalArgumentException("Must include a non-null PublishStateCallback."); + } + IImsRcsController imsRcsController = getIImsRcsController(); + if (imsRcsController == null) { + Log.e(TAG, "unregisterPublishStateCallback: IImsRcsController is null"); + throw new ImsException("Cannot find remote IMS service", + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + + try { + imsRcsController.unregisterUcePublishStateCallback(mSubId, c.getBinder()); + } catch (android.os.ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); + } catch (RemoteException e) { + Log.e(TAG, "Error calling IImsRcsController#unregisterUcePublishStateCallback", e); + throw new ImsException("Remote IMS Service is not available", + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + } + + /** * The user’s setting for whether or not User Capability Exchange (UCE) is enabled for the * associated subscription. * <p> diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl index 483c66eedc0c..9e461420e126 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl @@ -19,6 +19,7 @@ package android.telephony.ims.aidl; import android.net.Uri; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IRcsUceControllerCallback; +import android.telephony.ims.aidl.IRcsUcePublishStateCallback; import android.telephony.ims.aidl.IImsRegistrationCallback; import com.android.internal.telephony.IIntegerConsumer; @@ -47,4 +48,6 @@ interface IImsRcsController { int getUcePublishState(int subId); boolean isUceSettingEnabled(int subId, String callingPackage, String callingFeatureId); void setUceSettingEnabled(int subId, boolean isEnabled); + void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c); + void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c); } diff --git a/telephony/java/android/telephony/ims/aidl/IRcsUcePublishStateCallback.aidl b/telephony/java/android/telephony/ims/aidl/IRcsUcePublishStateCallback.aidl new file mode 100644 index 000000000000..b6e84154f80f --- /dev/null +++ b/telephony/java/android/telephony/ims/aidl/IRcsUcePublishStateCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 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 android.telephony.ims.aidl; + +/** + * Interface for RCS UCE publish state change callbacks. + * + * {@hide} + */ +oneway interface IRcsUcePublishStateCallback { + void onPublishStateChanged(int publishState); +} diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index b3b7b200816a..01d468cb53f6 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -343,7 +343,6 @@ public class MmTelFeature extends ImsFeature { * @hide */ @Override - @SystemApi @TestApi public void onIncomingCall(IImsCallSession c, Bundle extras) { } @@ -355,7 +354,6 @@ public class MmTelFeature extends ImsFeature { * @hide */ @Override - @SystemApi @TestApi public void onRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) { } @@ -366,7 +364,6 @@ public class MmTelFeature extends ImsFeature { * @hide */ @Override - @SystemApi @TestApi public void onVoiceMessageCountUpdate(int count) { } diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java index 7069e0ab9b1e..2cdf70e6cf4c 100644 --- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java @@ -29,6 +29,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.util.RemoteCallbackListExt; +import com.android.internal.util.ArrayUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -105,6 +106,11 @@ public class ImsRegistrationImplBase { // Locked on mLock, create unspecified disconnect cause. private ImsReasonInfo mLastDisconnectCause = new ImsReasonInfo(); + // We hold onto the uris each time they change so that we can send it to a callback when its + // first added. + private Uri[] mUris = new Uri[0]; + private boolean mUrisSet = false; + /** * @hide */ @@ -208,19 +214,27 @@ public class ImsRegistrationImplBase { } /** - * The this device's subscriber associated {@link Uri}s have changed, which are used to filter - * out this device's {@link Uri}s during conference calling. - * @param uris + * Invoked when the {@link Uri}s associated to this device's subscriber have changed. + * These {@link Uri}s' are filtered out during conference calls. + * + * The {@link Uri}s are not guaranteed to be different between subsequent calls. + * @param uris changed uris */ public final void onSubscriberAssociatedUriChanged(Uri[] uris) { - mCallbacks.broadcastAction((c) -> { - try { - c.onSubscriberAssociatedUriChanged(uris); - } catch (RemoteException e) { - Log.w(LOG_TAG, e + " " + "onSubscriberAssociatedUriChanged() - Skipping " + - "callback."); - } - }); + synchronized (mLock) { + mUris = ArrayUtils.cloneOrNull(uris); + mUrisSet = true; + } + mCallbacks.broadcastAction((c) -> onSubscriberAssociatedUriChanged(c, uris)); + } + + private void onSubscriberAssociatedUriChanged(IImsRegistrationCallback callback, Uri[] uris) { + try { + callback.onSubscriberAssociatedUriChanged(uris); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " " + "onSubscriberAssociatedUriChanged() - Skipping " + + "callback."); + } } private void updateToState(@ImsRegistrationTech int connType, int newState) { @@ -233,6 +247,10 @@ public class ImsRegistrationImplBase { private void updateToDisconnectedState(ImsReasonInfo info) { synchronized (mLock) { + //We don't want to send this info over if we are disconnected + mUrisSet = false; + mUris = null; + updateToState(REGISTRATION_TECH_NONE, RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED); if (info != null) { @@ -260,12 +278,17 @@ public class ImsRegistrationImplBase { * @param c the newly registered callback that will be updated with the current registration * state. */ - private void updateNewCallbackWithState(IImsRegistrationCallback c) throws RemoteException { + private void updateNewCallbackWithState(IImsRegistrationCallback c) + throws RemoteException { int state; ImsReasonInfo disconnectInfo; + boolean urisSet; + Uri[] uris; synchronized (mLock) { state = mRegistrationState; disconnectInfo = mLastDisconnectCause; + urisSet = mUrisSet; + uris = mUris; } switch (state) { case RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED: { @@ -285,5 +308,8 @@ public class ImsRegistrationImplBase { break; } } + if (urisSet) { + onSubscriberAssociatedUriChanged(c, uris); + } } } diff --git a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java index ce9a73a21657..a9a33c0e1507 100644 --- a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java @@ -403,8 +403,7 @@ public class ImsSmsImplBase { message.mWrappedSmsMessage.mMessageRef, STATUS_REPORT_STATUS_ERROR); } else { - Log.w(LOG_TAG, - "onSmsStatusReportReceivedWithoutMessageRef: Invalid pdu entered."); + Log.w(LOG_TAG, "onSmsStatusReportReceived: Invalid pdu entered."); acknowledgeSmsReport(token, 0, STATUS_REPORT_STATUS_ERROR); } } diff --git a/telephony/java/android/telephony/mbms/MbmsErrors.java b/telephony/java/android/telephony/mbms/MbmsErrors.java index 52e4d333b29d..40f3ae82d778 100644 --- a/telephony/java/android/telephony/mbms/MbmsErrors.java +++ b/telephony/java/android/telephony/mbms/MbmsErrors.java @@ -16,8 +16,12 @@ package android.telephony.mbms; +import android.annotation.IntDef; import android.telephony.MbmsStreamingSession; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + public class MbmsErrors { /** * Indicates that the middleware has sent an error code that is not defined in the version of @@ -138,6 +142,13 @@ public class MbmsErrors { /** Indicates the the middleware has no record of the supplied {@link FileInfo} */ public static final int ERROR_UNKNOWN_FILE_INFO = 403; + + /** + * Indicates that the service announcement descriptor passed via + * {@link android.telephony.MbmsDownloadSession#addServiceAnnouncement(byte[])} + * is malformed. + */ + public static final int ERROR_MALFORMED_SERVICE_ANNOUNCEMENT = 404; } /** @@ -156,5 +167,35 @@ public class MbmsErrors { public static final int ERROR_DUPLICATE_START_GROUP_CALL = 502; } + /** @hide */ + @IntDef(value = { + SUCCESS, + ERROR_NO_UNIQUE_MIDDLEWARE, + ERROR_MIDDLEWARE_NOT_BOUND, + ERROR_MIDDLEWARE_LOST, + InitializationErrors.ERROR_DUPLICATE_INITIALIZE, + InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED, + InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY, + GeneralErrors.ERROR_OUT_OF_MEMORY, + GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE, + GeneralErrors.ERROR_IN_E911, + GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE, + GeneralErrors.ERROR_UNABLE_TO_READ_SIM, + GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED, + StreamingErrors.ERROR_CONCURRENT_SERVICE_LIMIT_REACHED, + StreamingErrors.ERROR_UNABLE_TO_START_SERVICE, + StreamingErrors.ERROR_DUPLICATE_START_STREAM, + DownloadErrors.ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT, + DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST, + DownloadErrors.ERROR_UNKNOWN_FILE_INFO, + DownloadErrors.ERROR_MALFORMED_SERVICE_ANNOUNCEMENT, + GroupCallErrors.ERROR_UNABLE_TO_START_SERVICE, + GroupCallErrors.ERROR_DUPLICATE_START_GROUP_CALL, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MbmsError { + } + private MbmsErrors() {} } diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl index 445087fb78d5..04efd53eb743 100755 --- a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl +++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl @@ -35,6 +35,8 @@ interface IMbmsDownloadService int setTempFileRootDirectory(int subId, String rootDirectoryPath); + int addServiceAnnouncement(int subId, in byte[] contents); + int download(in DownloadRequest downloadRequest); int addStatusListener(in DownloadRequest downloadRequest, diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java index 9f22d0a49806..3053ea03bebe 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java @@ -216,6 +216,29 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { } /** + * Called when the client application wishes to receive file information according to a + * service announcement descriptor received from a group call server. + * + * The service announcement descriptor is in the format of a multipart MIME file with XML parts, + * though no validation is performed on the contents of the {@code contents} argument -- + * implementing middleware applications should perform their own validation and return + * {@link MbmsErrors.DownloadErrors#ERROR_MALFORMED_SERVICE_ANNOUNCEMENT} if the descriptor is + * malformed. + * + * @param subscriptionId The subscription id the service announcement applies to. + * @param contents The contents of the service announcement descriptor. + * @return {@link MbmsErrors#SUCCESS}, or + * {@link MbmsErrors.DownloadErrors#ERROR_MALFORMED_SERVICE_ANNOUNCEMENT} + */ + // TODO: are there any public specifications of what the file format is that I can link to? + @Override + public @MbmsErrors.MbmsError int addServiceAnnouncement( + int subscriptionId, @NonNull byte[] contents) { + throw new UnsupportedOperationException("addServiceAnnouncement not supported by" + + " this middleware."); + } + + /** * Issues a request to download a set of files. * * The middleware should expect that {@link #setTempFileRootDirectory(int, String)} has been |