diff options
Diffstat (limited to 'telephony/java')
32 files changed, 738 insertions, 450 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 diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index b70937cee8a1..ae1b5c1b50bd 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -222,42 +222,29 @@ interface ITelephony { boolean setRadioPower(boolean turnOn); /** - * Request to update location information in service state + * This method has been removed due to security and stability issues. */ @UnsupportedAppUsage void updateServiceLocation(); /** - * Request to update location information for a subscrition in service state - * @param subId user preferred subId. + * Version of updateServiceLocation that records the caller and validates permissions. */ - void updateServiceLocationForSubscriber(int subId); + void updateServiceLocationWithPackageName(String callingPkg); /** - * Enable location update notifications. + * This method has been removed due to security and stability issues. */ @UnsupportedAppUsage void enableLocationUpdates(); /** - * Enable location update notifications. - * @param subId user preferred subId. - */ - void enableLocationUpdatesForSubscriber(int subId); - - /** - * Disable location update notifications. + * This method has been removed due to security and stability issues. */ @UnsupportedAppUsage void disableLocationUpdates(); /** - * Disable location update notifications. - * @param subId user preferred subId. - */ - void disableLocationUpdatesForSubscriber(int subId); - - /** * Allow mobile data connections. */ @UnsupportedAppUsage diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index 4d677545bc39..151187c5071f 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -108,6 +108,7 @@ public class PhoneConstants { public static final int PIN_RESULT_SUCCESS = 0; public static final int PIN_PASSWORD_INCORRECT = 1; public static final int PIN_GENERAL_FAILURE = 2; + public static final int PIN_OPERATION_ABORTED = 3; /** * Return codes for <code>enableApnType()</code> diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index 6ed0be24a0f1..542e08d743ab 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -17,7 +17,7 @@ package com.android.internal.telephony.cdma; import android.compat.annotation.UnsupportedAppUsage; -import android.content.res.Resources; +import android.os.Build; import android.sysprop.TelephonyProperties; import android.telephony.PhoneNumberUtils; import android.telephony.SmsCbLocation; @@ -27,7 +27,6 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; -import com.android.internal.telephony.Sms7BitEncodingTranslator; import com.android.internal.telephony.SmsAddress; import com.android.internal.telephony.SmsConstants; import com.android.internal.telephony.SmsHeader; @@ -156,7 +155,8 @@ public class SmsMessage extends SmsMessageBase { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link " + + "android.telephony.SmsMessage} API instead") public static SmsMessage createFromEfRecord(int index, byte[] data) { try { SmsMessage msg = new SmsMessage(); @@ -414,15 +414,7 @@ public class SmsMessage extends SmsMessageBase { @UnsupportedAppUsage public static TextEncodingDetails calculateLength(CharSequence messageBody, boolean use7bitOnly, boolean isEntireMsg) { - CharSequence newMsgBody = null; - Resources r = Resources.getSystem(); - if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) { - newMsgBody = Sms7BitEncodingTranslator.translate(messageBody, true /* isCdmaFormat */); - } - if (TextUtils.isEmpty(newMsgBody)) { - newMsgBody = messageBody; - } - return BearerData.calcTextEncodingDetails(newMsgBody, use7bitOnly, isEntireMsg); + return BearerData.calcTextEncodingDetails(messageBody, use7bitOnly, isEntireMsg); } /** diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java index c074e6e9a438..d186fcf63cfe 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -21,9 +21,11 @@ import android.content.res.Resources; import android.telephony.SmsCbCmasInfo; import android.telephony.cdma.CdmaSmsCbProgramData; import android.telephony.cdma.CdmaSmsCbProgramResults; +import android.text.TextUtils; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; +import com.android.internal.telephony.Sms7BitEncodingTranslator; import com.android.internal.telephony.SmsConstants; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; @@ -33,6 +35,7 @@ import com.android.internal.util.BitwiseOutputStream; import com.android.telephony.Rlog; import java.io.ByteArrayOutputStream; +import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -313,10 +316,16 @@ public final class BearerData { } public long toMillis() { - LocalDateTime localDateTime = - LocalDateTime.of(year, monthOrdinal, monthDay, hour, minute, second); - Instant instant = localDateTime.toInstant(mZoneId.getRules().getOffset(localDateTime)); - return instant.toEpochMilli(); + try { + LocalDateTime localDateTime = + LocalDateTime.of(year, monthOrdinal, monthDay, hour, minute, second); + Instant instant = + localDateTime.toInstant(mZoneId.getRules().getOffset(localDateTime)); + return instant.toEpochMilli(); + } catch (DateTimeException ex) { + Rlog.e(LOG_TAG, "Invalid timestamp", ex); + } + return 0; } @@ -540,8 +549,17 @@ public final class BearerData { */ public static TextEncodingDetails calcTextEncodingDetails(CharSequence msg, boolean force7BitEncoding, boolean isEntireMsg) { + CharSequence newMsg = null; + Resources r = Resources.getSystem(); + if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) { + newMsg = Sms7BitEncodingTranslator.translate(msg, true /* isCdmaFormat */); + } + if (TextUtils.isEmpty(newMsg)) { + newMsg = msg; + } + TextEncodingDetails ted; - int septets = countAsciiSeptets(msg, force7BitEncoding); + int septets = countAsciiSeptets(newMsg, force7BitEncoding); if (septets != -1 && septets <= SmsConstants.MAX_USER_DATA_SEPTETS) { ted = new TextEncodingDetails(); ted.msgCount = 1; @@ -1082,7 +1100,7 @@ public final class BearerData { bData.hasUserDataHeader = (inStream.read(1) == 1); inStream.skip(3); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1451,7 +1469,7 @@ public final class BearerData { bData.reportReq = (inStream.read(1) == 1); inStream.skip(4); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "REPLY_OPTION decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1470,7 +1488,7 @@ public final class BearerData { decodeSuccess = true; bData.numberOfMessages = IccUtils.cdmaBcdByteToInt((byte)inStream.read(8)); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1489,7 +1507,7 @@ public final class BearerData { decodeSuccess = true; bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1576,7 +1594,7 @@ public final class BearerData { bData.errorClass = inStream.read(2); bData.messageStatus = inStream.read(6); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "MESSAGE_STATUS decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1596,7 +1614,7 @@ public final class BearerData { decodeSuccess = true; bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1615,7 +1633,7 @@ public final class BearerData { decodeSuccess = true; bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1635,7 +1653,7 @@ public final class BearerData { bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray( inStream.readByteArray(6 * 8)); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1654,7 +1672,7 @@ public final class BearerData { decodeSuccess = true; bData.deferredDeliveryTimeRelative = inStream.read(8); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1674,7 +1692,7 @@ public final class BearerData { decodeSuccess = true; bData.validityPeriodRelative = inStream.read(8); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1695,7 +1713,7 @@ public final class BearerData { bData.privacy = inStream.read(2); inStream.skip(6); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "PRIVACY_INDICATOR decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1715,7 +1733,7 @@ public final class BearerData { decodeSuccess = true; bData.language = inStream.read(8); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "LANGUAGE_INDICATOR decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1736,7 +1754,7 @@ public final class BearerData { bData.displayMode = inStream.read(2); inStream.skip(6); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "DISPLAY_MODE decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1757,7 +1775,7 @@ public final class BearerData { bData.priority = inStream.read(2); inStream.skip(6); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "PRIORITY_INDICATOR decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1778,7 +1796,7 @@ public final class BearerData { bData.alert = inStream.read(2); inStream.skip(6); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1798,7 +1816,7 @@ public final class BearerData { decodeSuccess = true; bData.userResponseCode = inStream.read(8); } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "USER_RESPONSE_CODE decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ")"); @@ -1860,7 +1878,7 @@ public final class BearerData { decodeSuccess = true; } - if ((! decodeSuccess) || (paramBits > 0)) { + if ((!decodeSuccess) || (paramBits > 0)) { Rlog.d(LOG_TAG, "SERVICE_CATEGORY_PROGRAM_DATA decode " + (decodeSuccess ? "succeeded" : "failed") + " (extra bits = " + paramBits + ')'); diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java index 08580012ad17..7e31c4633050 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -27,6 +27,7 @@ import static com.android.internal.telephony.SmsConstants.MessageClass; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; +import android.os.Build; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; @@ -42,6 +43,7 @@ import com.android.telephony.Rlog; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.text.ParseException; +import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -90,14 +92,15 @@ public class SmsMessage extends SmsMessageBase { private int mVoiceMailCount = 0; + /** TP-Validity-Period-Format (TP-VPF). See TS 23.040, 9.2.3.3 */ private static final int VALIDITY_PERIOD_FORMAT_NONE = 0x00; private static final int VALIDITY_PERIOD_FORMAT_ENHANCED = 0x01; private static final int VALIDITY_PERIOD_FORMAT_RELATIVE = 0x02; private static final int VALIDITY_PERIOD_FORMAT_ABSOLUTE = 0x03; - //Validity Period min - 5 mins + // Validity Period min - 5 mins private static final int VALIDITY_PERIOD_MIN = 5; - //Validity Period max - 63 weeks + // Validity Period max - 63 weeks private static final int VALIDITY_PERIOD_MAX = 635040; private static final int INVALID_VALIDITY_PERIOD = -1; @@ -138,38 +141,6 @@ public class SmsMessage extends SmsMessageBase { } /** - * 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 - * - * {@hide} - */ - public static SmsMessage newFromCMT(byte[] pdu) { - try { - SmsMessage msg = new SmsMessage(); - msg.parsePdu(pdu); - return msg; - } catch (RuntimeException ex) { - Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex); - return null; - } - } - - /** @hide */ - public static SmsMessage newFromCDS(byte[] pdu) { - try { - SmsMessage msg = new SmsMessage(); - msg.parsePdu(pdu); - return msg; - } catch (RuntimeException ex) { - Rlog.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex); - return null; - } - } - - /** * Creates an SmsMessage from an SMS EF record. * * @param index Index of SMS EF record. @@ -178,7 +149,8 @@ public class SmsMessage extends SmsMessageBase { * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link " + + "android.telephony.SmsMessage} API instead") public static SmsMessage createFromEfRecord(int index, byte[] data) { try { SmsMessage msg = new SmsMessage(); @@ -222,20 +194,20 @@ public class SmsMessage extends SmsMessageBase { } /** - * Get Encoded Relative Validty Period Value from Validity period in mins. + * Gets Encoded Relative Validity Period Value from Validity period in mins. * * @param validityPeriod Validity period in mins. * * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. - * ||relValidityPeriod (TP-VP) || || validityPeriod || - * - * 0 to 143 ---> (TP-VP + 1) x 5 minutes - * - * 144 to 167 ---> 12 hours + ((TP-VP -143) x 30 minutes) - * - * 168 to 196 ---> (TP-VP - 166) x 1 day - * - * 197 to 255 ---> (TP-VP - 192) x 1 week + * ------------------------------------------------------------ + * TP-VP | Validity period + * (Relative format) | value + * ------------------------------------------------------------ + * 0 to 143 | (TP-VP + 1) x 5 minutes + * 144 to 167 | 12 hours + ((TP-VP -143) x 30 minutes) + * 168 to 196 | (TP-VP - 166) x 1 day + * 197 to 255 | (TP-VP - 192) x 1 week + * ------------------------------------------------------------ * * @return relValidityPeriod Encoded Relative Validity Period Value. * @hide @@ -243,19 +215,16 @@ public class SmsMessage extends SmsMessageBase { public static int getRelativeValidityPeriod(int validityPeriod) { int relValidityPeriod = INVALID_VALIDITY_PERIOD; - if (validityPeriod < VALIDITY_PERIOD_MIN || validityPeriod > VALIDITY_PERIOD_MAX) { - Rlog.e(LOG_TAG,"Invalid Validity Period" + validityPeriod); - return relValidityPeriod; - } - - if (validityPeriod <= 720) { - relValidityPeriod = (validityPeriod / 5) - 1; - } else if (validityPeriod <= 1440) { - relValidityPeriod = ((validityPeriod - 720) / 30) + 143; - } else if (validityPeriod <= 43200) { - relValidityPeriod = (validityPeriod / 1440) + 166; - } else if (validityPeriod <= 635040) { - relValidityPeriod = (validityPeriod / 10080) + 192; + if (validityPeriod >= VALIDITY_PERIOD_MIN) { + if (validityPeriod <= 720) { + relValidityPeriod = (validityPeriod / 5) - 1; + } else if (validityPeriod <= 1440) { + relValidityPeriod = ((validityPeriod - 720) / 30) + 143; + } else if (validityPeriod <= 43200) { + relValidityPeriod = (validityPeriod / 1440) + 166; + } else if (validityPeriod <= VALIDITY_PERIOD_MAX) { + relValidityPeriod = (validityPeriod / 10080) + 192; + } } return relValidityPeriod; } @@ -365,17 +334,19 @@ public class SmsMessage extends SmsMessageBase { SubmitPdu ret = new SubmitPdu(); - int validityPeriodFormat = VALIDITY_PERIOD_FORMAT_NONE; - int relativeValidityPeriod = INVALID_VALIDITY_PERIOD; + int relativeValidityPeriod = getRelativeValidityPeriod(validityPeriod); + + byte mtiByte = 0x01; // SMS-SUBMIT - // TP-Validity-Period-Format (TP-VPF) in 3GPP TS 23.040 V6.8.1 section 9.2.3.3 - //bit 4:3 = 10 - TP-VP field present - relative format - if((relativeValidityPeriod = getRelativeValidityPeriod(validityPeriod)) >= 0) { - validityPeriodFormat = VALIDITY_PERIOD_FORMAT_RELATIVE; + if (header != null) { + // Set TP-UDHI + mtiByte |= 0x40; } - byte mtiByte = (byte)(0x01 | (validityPeriodFormat << 0x03) | - (header != null ? 0x40 : 0x00)); + if (relativeValidityPeriod != INVALID_VALIDITY_PERIOD) { + // Set TP-Validity-Period-Format (TP-VPF) + mtiByte |= VALIDITY_PERIOD_FORMAT_RELATIVE << 3; + } ByteArrayOutputStream bo = getSubmitPduHead( scAddress, destinationAddress, mtiByte, @@ -447,8 +418,8 @@ public class SmsMessage extends SmsMessageBase { bo.write(0x08); } - if (validityPeriodFormat == VALIDITY_PERIOD_FORMAT_RELATIVE) { - // ( TP-Validity-Period - relative format) + // TP-Validity-Period (TP-VP) + if (relativeValidityPeriod != INVALID_VALIDITY_PERIOD) { bo.write(relativeValidityPeriod); } @@ -885,10 +856,9 @@ public class SmsMessage extends SmsMessageBase { } /** - * Parses an SC timestamp and returns a currentTimeMillis()-style - * timestamp + * Parses an SC timestamp and returns a currentTimeMillis()-style timestamp, or 0 if + * invalid. */ - long getSCTimestampMillis() { // TP-Service-Centre-Time-Stamp int year = IccUtils.gsmBcdByteToInt(mPdu[mCur++]); @@ -914,16 +884,22 @@ public class SmsMessage extends SmsMessageBase { // It's 2006. Should I really support years < 2000? int fullYear = year >= 90 ? year + 1900 : year + 2000; - LocalDateTime localDateTime = LocalDateTime.of( - fullYear, - month /* 1-12 */, - day, - hour, - minute, - second); - long epochSeconds = localDateTime.toEpochSecond(ZoneOffset.UTC) - timeZoneOffsetSeconds; - // Convert to milliseconds. - return epochSeconds * 1000; + try { + LocalDateTime localDateTime = LocalDateTime.of( + fullYear, + month /* 1-12 */, + day, + hour, + minute, + second); + long epochSeconds = + localDateTime.toEpochSecond(ZoneOffset.UTC) - timeZoneOffsetSeconds; + // Convert to milliseconds. + return epochSeconds * 1000; + } catch (DateTimeException ex) { + Rlog.e(LOG_TAG, "Invalid timestamp", ex); + } + return 0; } /** @@ -1274,6 +1250,7 @@ public class SmsMessage extends SmsMessageBase { mRecipientAddress = p.getAddress(); // TP-Service-Centre-Time-Stamp mScTimeMillis = p.getSCTimestampMillis(); + // TP-Discharge-Time p.getSCTimestampMillis(); // TP-Status mStatus = p.getByte(); @@ -1332,6 +1309,7 @@ public class SmsMessage extends SmsMessageBase { + " data coding scheme: " + mDataCodingScheme); } + // TP-Service-Centre-Time-Stamp mScTimeMillis = p.getSCTimestampMillis(); if (VDBG) Rlog.d(LOG_TAG, "SMS SC timestamp: " + mScTimeMillis); @@ -1374,23 +1352,17 @@ public class SmsMessage extends SmsMessageBase { // TP-Validity-Period-Format int validityPeriodLength = 0; - int validityPeriodFormat = ((firstByte>>3) & 0x3); - if (0x0 == validityPeriodFormat) /* 00, TP-VP field not present*/ - { + int validityPeriodFormat = ((firstByte >> 3) & 0x3); + if (validityPeriodFormat == VALIDITY_PERIOD_FORMAT_NONE) { validityPeriodLength = 0; - } - else if (0x2 == validityPeriodFormat) /* 10, TP-VP: relative format*/ - { + } else if (validityPeriodFormat == VALIDITY_PERIOD_FORMAT_RELATIVE) { validityPeriodLength = 1; - } - else /* other case, 11 or 01, TP-VP: absolute or enhanced format*/ - { + } else { // VALIDITY_PERIOD_FORMAT_ENHANCED or VALIDITY_PERIOD_FORMAT_ABSOLUTE validityPeriodLength = 7; } // TP-Validity-Period is not used on phone, so just ignore it for now. - while (validityPeriodLength-- > 0) - { + while (validityPeriodLength-- > 0) { p.getByte(); } |