summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format13
-rw-r--r--Android.bp2
-rw-r--r--Android.mk4
-rw-r--r--PREUPLOAD.cfg12
-rw-r--r--StubLibraries.bp28
-rw-r--r--apex/Android.bp3
-rw-r--r--api/current.txt3
-rw-r--r--api/module-lib-current.txt90
-rw-r--r--cmds/statsd/src/anomaly/AlarmTracker.cpp4
-rw-r--r--cmds/statsd/tests/anomaly/AlarmTracker_test.cpp30
-rw-r--r--cmds/telecom/src/com/android/commands/telecom/Telecom.java14
-rw-r--r--config/preloaded-classes2
-rw-r--r--core/java/android/annotation/SystemApi.java2
-rw-r--r--core/java/android/app/Activity.java18
-rw-r--r--core/java/android/app/AlarmManager.java2
-rw-r--r--core/java/android/app/Fragment.java12
-rw-r--r--core/java/android/app/admin/DelegatedAdminReceiver.java4
-rw-r--r--core/java/android/app/admin/DeviceAdminReceiver.java4
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java4
-rw-r--r--core/java/android/bluetooth/BluetoothHeadsetClient.java3
-rw-r--r--core/java/android/bluetooth/BluetoothMapClient.java72
-rw-r--r--core/java/android/bluetooth/BluetoothPbapClient.java3
-rw-r--r--core/java/android/bluetooth/BluetoothSap.java3
-rw-r--r--core/java/android/content/pm/PackageParser.java4
-rw-r--r--core/java/android/hardware/GeomagneticField.java138
-rw-r--r--core/java/android/net/DnsPacket.java235
-rw-r--r--core/java/android/net/DnsResolver.java15
-rw-r--r--core/java/android/net/ITetheredInterfaceCallback.aidl2
-rw-r--r--core/java/android/net/MacAddress.java14
-rw-r--r--core/java/android/net/NetworkTemplate.java12
-rw-r--r--core/java/android/net/NetworkUtils.java8
-rw-r--r--core/java/android/net/ProxyInfo.java12
-rw-r--r--core/java/android/os/Debug.java25
-rw-r--r--core/java/android/os/HwBinder.java9
-rw-r--r--core/java/android/os/Process.java7
-rw-r--r--core/java/android/provider/Telephony.java12
-rw-r--r--core/java/android/telephony/TelephonyRegistryManager.java2
-rwxr-xr-xcore/java/android/text/format/DateFormat.java69
-rw-r--r--core/java/android/text/format/DateIntervalFormat.java126
-rw-r--r--core/java/android/text/format/DateTimeFormat.java60
-rw-r--r--core/java/android/text/format/DateUtils.java5
-rw-r--r--core/java/android/text/format/DateUtilsBridge.java194
-rw-r--r--core/java/android/text/format/RelativeDateTimeFormatter.java359
-rw-r--r--core/java/android/text/format/Time.java38
-rw-r--r--core/java/android/text/format/TimeFormatter.java61
-rw-r--r--core/java/android/text/method/NumberKeyListener.java4
-rw-r--r--core/java/android/timezone/CountryTimeZones.java17
-rw-r--r--core/java/android/timezone/TelephonyLookup.java9
-rw-r--r--core/java/android/timezone/TelephonyNetwork.java4
-rw-r--r--core/java/android/timezone/TelephonyNetworkFinder.java6
-rw-r--r--core/java/android/timezone/TimeZoneFinder.java10
-rw-r--r--core/java/android/timezone/TzDataSetVersion.java14
-rw-r--r--core/java/android/timezone/ZoneInfoDb.java6
-rw-r--r--core/java/android/util/TimeUtils.java8
-rw-r--r--core/java/android/widget/DatePickerSpinnerDelegate.java4
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java72
-rw-r--r--core/java/android/widget/TimePicker.java12
-rw-r--r--core/java/android/widget/TimePickerSpinnerDelegate.java12
-rw-r--r--core/java/com/android/internal/logging/AndroidHandler.java29
-rw-r--r--core/java/com/android/internal/net/VpnProfile.java3
-rw-r--r--core/java/com/android/internal/os/KernelWakelockReader.java29
-rw-r--r--core/java/com/android/internal/os/Zygote.java13
-rw-r--r--core/java/com/android/internal/util/StateMachine.java5
-rw-r--r--core/java/com/android/internal/widget/PointerLocationView.java2
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp2
-rw-r--r--core/jni/android_app_ActivityThread.cpp3
-rw-r--r--core/jni/android_backup_BackupDataInput.cpp2
-rw-r--r--core/jni/android_backup_BackupDataOutput.cpp2
-rw-r--r--core/jni/android_backup_BackupHelperDispatcher.cpp2
-rw-r--r--core/jni/android_backup_FileBackupHelperBase.cpp2
-rw-r--r--core/jni/android_hardware_SerialPort.cpp2
-rw-r--r--core/jni/android_hardware_UsbDeviceConnection.cpp2
-rw-r--r--core/jni/android_net_LocalSocketImpl.cpp2
-rw-r--r--core/jni/android_net_NetUtils.cpp10
-rw-r--r--core/jni/android_opengl_EGL14.cpp2
-rw-r--r--core/jni/android_opengl_EGL15.cpp2
-rw-r--r--core/jni/android_opengl_EGLExt.cpp2
-rw-r--r--core/jni/android_opengl_GLES10.cpp2
-rw-r--r--core/jni/android_opengl_GLES10Ext.cpp2
-rw-r--r--core/jni/android_opengl_GLES11.cpp2
-rw-r--r--core/jni/android_opengl_GLES11Ext.cpp2
-rw-r--r--core/jni/android_opengl_GLES20.cpp2
-rw-r--r--core/jni/android_opengl_GLES30.cpp2
-rw-r--r--core/jni/android_opengl_GLES31.cpp2
-rw-r--r--core/jni/android_opengl_GLES31Ext.cpp2
-rw-r--r--core/jni/android_opengl_GLES32.cpp2
-rw-r--r--core/jni/android_os_Debug.cpp2
-rw-r--r--core/jni/android_os_HwBinder.cpp7
-rw-r--r--core/jni/android_os_HwParcel.cpp16
-rw-r--r--core/jni/android_os_MemoryFile.cpp2
-rw-r--r--core/jni/android_os_Parcel.cpp2
-rw-r--r--core/jni/android_os_SELinux.cpp2
-rw-r--r--core/jni/android_os_SharedMemory.cpp2
-rw-r--r--core/jni/android_server_NetworkManagementSocketTagger.cpp2
-rw-r--r--core/jni/android_util_AssetManager.cpp2
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp33
-rw-r--r--core/jni/com_google_android_gles_jni_GLImpl.cpp2
-rw-r--r--core/jni/core_jni_helpers.h2
-rw-r--r--core/proto/android/app/settings_enums.proto5
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/res/res/values/config.xml5
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/bluetoothtests/AndroidManifest.xml6
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java24
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java11
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java156
-rw-r--r--core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java23
-rw-r--r--core/tests/coretests/src/android/text/format/DateFormatTest.java80
-rw-r--r--core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java671
-rw-r--r--core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java762
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java24
-rw-r--r--data/etc/Android.bp8
-rw-r--r--data/etc/com.android.cellbroadcastreceiver.xml26
-rw-r--r--data/keyboards/Generic.kl2
-rw-r--r--drm/jni/android_drm_DrmManagerClient.cpp2
-rw-r--r--identity/java/android/security/identity/IdentityCredential.java29
-rw-r--r--identity/java/android/security/identity/ResultData.java16
-rw-r--r--keystore/java/android/security/Credentials.java26
-rw-r--r--keystore/java/android/security/IKeyChainService.aidl3
-rw-r--r--keystore/java/android/security/KeyChain.java10
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java5
-rw-r--r--libs/input/PointerController.cpp124
-rw-r--r--libs/input/PointerController.h72
-rw-r--r--libs/input/tests/PointerController_test.cpp16
-rw-r--r--media/jni/android_media_JetPlayer.cpp2
-rw-r--r--media/jni/android_media_MediaExtractor.cpp2
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp2
-rw-r--r--media/jni/android_media_MediaMuxer.cpp2
-rw-r--r--media/jni/android_media_MediaPlayer.cpp2
-rw-r--r--media/jni/android_media_MediaRecorder.cpp2
-rw-r--r--media/jni/android_media_MediaScanner.cpp2
-rw-r--r--media/jni/android_mtp_MtpServer.cpp2
-rw-r--r--media/jni/audioeffect/Visualizer.cpp1
-rw-r--r--media/jni/soundpool/android_media_SoundPool.cpp2
-rw-r--r--non-updatable-api/current.txt3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java7
-rw-r--r--packages/Tethering/Android.bp3
-rw-r--r--packages/Tethering/common/TetheringLib/api/module-lib-current.txt88
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java3
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java1
-rw-r--r--packages/Tethering/jarjar-rules.txt5
-rw-r--r--packages/Tethering/jni/android_net_util_TetheringUtils.cpp1
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java10
-rw-r--r--packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java25
-rw-r--r--packages/Tethering/tests/privileged/Android.bp30
-rw-r--r--packages/Tethering/tests/privileged/AndroidManifest.xml32
-rw-r--r--packages/Tethering/tests/unit/jarjar-rules.txt2
-rw-r--r--packages/services/PacProcessor/AndroidManifest.xml4
-rw-r--r--packages/services/PacProcessor/src/com/android/net/IProxyService.aidl3
-rw-r--r--packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java10
-rw-r--r--rs/jni/Android.mk2
-rw-r--r--services/Android.bp4
-rw-r--r--services/backup/OWNERS13
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java20
-rw-r--r--services/core/java/com/android/server/RuntimeService.java15
-rw-r--r--services/core/java/com/android/server/compat/TEST_MAPPING4
-rw-r--r--services/core/java/com/android/server/connectivity/PacManager.java13
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java112
-rw-r--r--services/core/java/com/android/server/connectivity/ProxyTracker.java24
-rw-r--r--services/core/java/com/android/server/net/IpConfigStore.java3
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java15
-rw-r--r--services/core/java/com/android/server/pm/OWNERS4
-rw-r--r--services/core/java/com/android/server/storage/DeviceStorageMonitorService.java25
-rw-r--r--services/core/java/com/android/server/timezone/RulesManagerService.java8
-rw-r--r--services/core/jni/com_android_server_AlarmManagerService.cpp140
-rw-r--r--services/core/jni/com_android_server_SerialService.cpp2
-rw-r--r--services/core/jni/com_android_server_UsbDeviceManager.cpp2
-rw-r--r--services/core/jni/com_android_server_UsbHostManager.cpp2
-rw-r--r--services/core/jni/com_android_server_UsbMidiDevice.cpp2
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp24
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java2
-rw-r--r--services/java/com/android/server/SystemServer.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java2
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl5
-rw-r--r--telephony/common/com/android/internal/telephony/CarrierAppUtils.java63
-rw-r--r--telephony/common/com/android/internal/telephony/SmsApplication.java27
-rw-r--r--telephony/java/android/service/euicc/EuiccProfileInfo.java5
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java18
-rw-r--r--telephony/java/android/telephony/CellLocation.java31
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthNr.java14
-rw-r--r--telephony/java/android/telephony/DataSpecificRegistrationInfo.java48
-rw-r--r--telephony/java/android/telephony/NetworkRegistrationInfo.java44
-rw-r--r--telephony/java/android/telephony/PreciseDataConnectionState.java1
-rw-r--r--telephony/java/android/telephony/ServiceState.java25
-rw-r--r--telephony/java/android/telephony/SmsCbEtwsInfo.java32
-rw-r--r--telephony/java/android/telephony/SmsManager.java4
-rw-r--r--telephony/java/android/telephony/SmsMessage.java22
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java288
-rw-r--r--telephony/java/android/telephony/TelephonyScanManager.java84
-rw-r--r--telephony/java/android/telephony/ims/feature/MmTelFeature.java3
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java50
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl52
-rw-r--r--telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java22
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java49
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java152
-rw-r--r--test-base/Android.bp1
-rw-r--r--test-base/src/android/test/InstrumentationTestCase.java4
-rw-r--r--test-mock/Android.bp1
-rw-r--r--test-mock/src/android/test/mock/MockContentProvider.java3
-rw-r--r--test-runner/Android.bp1
-rw-r--r--test-runner/api/current.txt1
-rw-r--r--test-runner/src/android/test/InstrumentationTestRunner.java1
-rw-r--r--tests/DynamicCodeLoggerIntegrationTests/Android.mk3
-rw-r--r--tests/net/java/android/net/DnsPacketTest.java159
-rw-r--r--tests/net/java/android/net/NetworkTemplateTest.kt7
-rw-r--r--tests/net/java/android/net/NetworkUtilsTest.java60
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java49
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java55
209 files changed, 4403 insertions, 1915 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 000000000000..03af56d64062
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+
+AccessModifierOffset: -4
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakBeforeMultilineStrings: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ConstructorInitializerIndentWidth: 6
+ContinuationIndentWidth: 8
+IndentWidth: 4
+PenaltyBreakBeforeFirstCallParameter: 100000
+SpacesBeforeTrailingComments: 1
diff --git a/Android.bp b/Android.bp
index aeaaca3d7705..a93a155089ce 100644
--- a/Android.bp
+++ b/Android.bp
@@ -371,7 +371,7 @@ filegroup {
java_library {
name: "framework-updatable-stubs-module_libs_api",
static_libs: [
- "framework-sdkextensions-stubs-module_libs_api",
+ "framework-sdkextensions.stubs.module_lib",
"framework-tethering.stubs.module_lib",
"updatable_media_stubs",
],
diff --git a/Android.mk b/Android.mk
index d8532489a786..46529eb64657 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,10 +32,6 @@ ifneq ($(ANDROID_BUILD_EMBEDDED),true)
# ============================================================
include $(CLEAR_VARS)
-# This is used by ide.mk as the list of source files that are
-# always included.
-INTERNAL_SDK_SOURCE_DIRS := $(addprefix $(LOCAL_PATH)/,$(dirs_to_document))
-
# sdk.atree needs to copy the whole dir: $(OUT_DOCS)/offline-sdk to the final zip.
# So keep offline-sdk-timestamp target here, and unzip offline-sdk-docs.zip to
# $(OUT_DOCS)/offline-sdk.
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 68311176a783..9abb308534df 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,15 @@
+[Builtin Hooks]
+clang_format = true
+
+[Builtin Hooks Options]
+# Only turn on clang-format check for the following subfolders.
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+ cmds/hid/
+ cmds/input/
+ core/jni/
+ libs/input/
+ services/core/jni/
+
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index bb13eaacfa90..26478d3bad26 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -150,6 +150,9 @@ priv_apps = " " +
module_libs = " " +
" --show-annotation android.annotation.SystemApi\\(" +
"client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
+ "\\)" +
+ " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
"\\) "
droidstubs {
@@ -222,16 +225,10 @@ droidstubs {
}
/////////////////////////////////////////////////////////////////////
-// Following droidstubs modules are for extra APIs for modules.
-// The framework currently have two more API surfaces for modules:
-// @SystemApi(client=MODULE_APPS) and @SystemApi(client=MODULE_LIBRARIES)
+// Following droidstubs modules are for extra APIs for modules,
+// namely @SystemApi(client=MODULE_LIBRARIES) APIs.
/////////////////////////////////////////////////////////////////////
-// TODO(b/146727827) remove the *-api module when we can teach metalava
-// about the relationship among the API surfaces. Currently, these modules are only to generate
-// the API signature files and ensure that the APIs evolve in a backwards compatible manner.
-// They however are NOT used for building the API stub.
-
droidstubs {
name: "module-lib-api",
defaults: ["metalava-full-api-stubs-default"],
@@ -268,7 +265,7 @@ droidstubs {
name: "module-lib-api-stubs-docs-non-updatable",
defaults: ["metalava-non-updatable-api-stubs-default"],
arg_files: ["core/res/AndroidManifest.xml"],
- args: metalava_framework_docs_args + module_libs,
+ args: metalava_framework_docs_args + priv_apps + module_libs,
check_api: {
current: {
api_file: "non-updatable-api/module-lib-current.txt",
@@ -277,17 +274,6 @@ droidstubs {
},
}
-// The following droidstub module generates source files for the API stub library for
-// modules. Note that it not only includes its own APIs but also other APIs that have
-// narrower scope (all @SystemApis, not just the ones with 'client=MODULE_LIBRARIES').
-
-droidstubs {
- name: "module-lib-api-stubs-docs",
- defaults: ["metalava-non-updatable-api-stubs-default"],
- arg_files: ["core/res/AndroidManifest.xml"],
- args: metalava_framework_docs_args + priv_apps + module_libs,
-}
-
/////////////////////////////////////////////////////////////////////
// android_*_stubs_current modules are the stubs libraries compiled
// from *-api-stubs-docs
@@ -333,7 +319,7 @@ java_library_static {
java_library_static {
name: "android_module_lib_stubs_current",
- srcs: [ ":module-lib-api-stubs-docs" ],
+ srcs: [ ":module-lib-api-stubs-docs-non-updatable" ],
defaults: ["android_defaults_stubs_current"],
libs: ["sdk_system_29_android"],
}
diff --git a/apex/Android.bp b/apex/Android.bp
index 380b4c6cc0be..f34ecbd79108 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -53,6 +53,9 @@ priv_apps = " " +
module_libs = " " +
" --show-annotation android.annotation.SystemApi\\(" +
"client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
+ "\\)" +
+ " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
"\\) "
mainline_service_stubs_args =
diff --git a/api/current.txt b/api/current.txt
index fea1f2f4cac4..8dd7af81315b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41088,6 +41088,7 @@ package android.security {
field public static final String EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS";
field public static final String EXTRA_NAME = "name";
field public static final String EXTRA_PKCS12 = "PKCS12";
+ field public static final String KEY_ALIAS_SELECTION_DENIED = "android:alias-selection-denied";
}
public interface KeyChainAliasCallback {
@@ -45143,7 +45144,7 @@ package android.telephony {
public abstract class CellLocation {
ctor public CellLocation();
method public static android.telephony.CellLocation getEmpty();
- method public static void requestLocationUpdate();
+ method @Deprecated public static void requestLocationUpdate();
}
public abstract class CellSignalStrength {
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 355fa18ca249..283af068a077 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -11,24 +11,6 @@ package android.annotation {
package android.net {
- public final class TetheredClient implements android.os.Parcelable {
- ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
- method public int describeContents();
- method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
- method @NonNull public android.net.MacAddress getMacAddress();
- method public int getTetheringType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
- }
-
- public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.LinkAddress getAddress();
- method @Nullable public String getHostname();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
- }
-
public final class TetheringConstants {
field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
@@ -48,69 +30,15 @@ package android.net {
method @NonNull public String[] getTetheringErroredIfaces();
method public boolean isTetheringSupported();
method public boolean isTetheringSupported(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
method @Deprecated public int setUsbTethering(boolean);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
method @Deprecated public int tether(@NonNull String);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
method @Deprecated public int untether(@NonNull String);
- field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
- field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
- field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
- field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
- field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_ETHERNET = 5; // 0x5
- field public static final int TETHERING_INVALID = -1; // 0xffffffff
- field public static final int TETHERING_NCM = 4; // 0x4
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field public static final int TETHERING_WIFI_P2P = 3; // 0x3
- field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
- field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
- field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
- field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
- field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
- field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
- field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
- field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
- field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
- field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
- field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
- field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
- field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
- field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
- field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
- field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
- field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
- field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
- field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
- }
-
- public static interface TetheringManager.OnTetheringEntitlementResultListener {
- method public void onTetheringEntitlementResult(int);
- }
-
- public static interface TetheringManager.StartTetheringCallback {
- method public default void onTetheringFailed(int);
- method public default void onTetheringStarted();
}
public static interface TetheringManager.TetheringEventCallback {
- method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
- method public default void onError(@NonNull String, int);
- method public default void onOffloadStatusChanged(int);
method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
- method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheringSupported(boolean);
- method public default void onUpstreamChanged(@Nullable android.net.Network);
}
public static class TetheringManager.TetheringInterfaceRegexps {
@@ -119,21 +47,5 @@ package android.net {
method @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
}
- public static class TetheringManager.TetheringRequest {
- method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
- method @Nullable public android.net.LinkAddress getLocalIpv4Address();
- method public boolean getShouldShowEntitlementUi();
- method public int getTetheringType();
- method public boolean isExemptFromEntitlementCheck();
- }
-
- public static class TetheringManager.TetheringRequest.Builder {
- ctor public TetheringManager.TetheringRequest.Builder(int);
- method @NonNull public android.net.TetheringManager.TetheringRequest build();
- method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
- method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
- method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
- }
-
}
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
index 019a9f7e5f9a..a21327b4aae0 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.cpp
+++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp
@@ -61,11 +61,11 @@ void AlarmTracker::addSubscription(const Subscription& subscription) {
}
int64_t AlarmTracker::findNextAlarmSec(int64_t currentTimeSec) {
- if (currentTimeSec <= mAlarmSec) {
+ if (currentTimeSec < mAlarmSec) {
return mAlarmSec;
}
int64_t periodsForward =
- ((currentTimeSec - mAlarmSec) * MS_PER_SEC - 1) / mAlarmConfig.period_millis() + 1;
+ ((currentTimeSec - mAlarmSec) * MS_PER_SEC) / mAlarmConfig.period_millis() + 1;
return mAlarmSec + periodsForward * mAlarmConfig.period_millis() / MS_PER_SEC;
}
diff --git a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
index 5e6de1cc6b91..e664023a1647 100644
--- a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
@@ -40,23 +40,47 @@ TEST(AlarmTrackerTest, TestTriggerTimestamp) {
alarm.set_offset_millis(15 * MS_PER_SEC);
alarm.set_period_millis(60 * 60 * MS_PER_SEC); // 1hr
int64_t startMillis = 100000000 * MS_PER_SEC;
+ int64_t nextAlarmTime = startMillis / MS_PER_SEC + 15;
AlarmTracker tracker(startMillis, startMillis, alarm, kConfigKey, subscriberAlarmMonitor);
- EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15));
+ EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10;
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarmSet =
subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
EXPECT_TRUE(firedAlarmSet.empty());
tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
- EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15));
+ EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
+ EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
currentTimeSec = startMillis / MS_PER_SEC + 7000;
+ nextAlarmTime = startMillis / MS_PER_SEC + 15 + 2 * 60 * 60;
firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
EXPECT_EQ(firedAlarmSet.size(), 1u);
tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
EXPECT_TRUE(firedAlarmSet.empty());
- EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15 + 2 * 60 * 60));
+ EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
+ EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
+
+ // Alarm fires exactly on time.
+ currentTimeSec = startMillis / MS_PER_SEC + 15 + 2 * 60 * 60;
+ nextAlarmTime = startMillis / MS_PER_SEC + 15 + 3 * 60 * 60;
+ firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
+ ASSERT_EQ(firedAlarmSet.size(), 1u);
+ tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
+ EXPECT_TRUE(firedAlarmSet.empty());
+ EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
+ EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
+
+ // Alarm fires exactly 1 period late.
+ currentTimeSec = startMillis / MS_PER_SEC + 15 + 4 * 60 * 60;
+ nextAlarmTime = startMillis / MS_PER_SEC + 15 + 5 * 60 * 60;
+ firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
+ ASSERT_EQ(firedAlarmSet.size(), 1u);
+ tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
+ EXPECT_TRUE(firedAlarmSet.empty());
+ EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
+ EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
}
} // namespace statsd
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 97074050448e..35f4add46d77 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -64,6 +64,8 @@ public final class Telecom extends BaseCommand {
private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
+ private static final String COMMAND_STOP_BLOCK_SUPPRESSION = "stop-block-suppression";
+
/**
* Change the system dialer package name if a package name was specified,
* Example: adb shell telecom set-system-dialer <PACKAGE>
@@ -111,6 +113,8 @@ public final class Telecom extends BaseCommand {
+ "usage: telecom set-sim-count <COUNT>\n"
+ "usage: telecom get-sim-config\n"
+ "usage: telecom get-max-phones\n"
+ + "usage: telecom stop-block-suppression: Stop suppressing the blocked number"
+ + " provider after a call to emergency services.\n"
+ "usage: telecom set-emer-phone-account-filter <PACKAGE>\n"
+ "\n"
+ "telecom set-phone-account-enabled: Enables the given phone account, if it has"
@@ -203,6 +207,9 @@ public final class Telecom extends BaseCommand {
case COMMAND_UNREGISTER_PHONE_ACCOUNT:
runUnregisterPhoneAccount();
break;
+ case COMMAND_STOP_BLOCK_SUPPRESSION:
+ runStopBlockSuppression();
+ break;
case COMMAND_SET_DEFAULT_DIALER:
runSetDefaultDialer();
break;
@@ -320,8 +327,13 @@ public final class Telecom extends BaseCommand {
System.out.println("Success - " + handle + " unregistered.");
}
+ private void runStopBlockSuppression() throws RemoteException {
+ mTelecomService.stopBlockSuppression();
+ }
+
private void runSetDefaultDialer() throws RemoteException {
- final String packageName = nextArgRequired();
+ String packageName = nextArg();
+ if ("default".equals(packageName)) packageName = null;
mTelecomService.setTestDefaultDialer(packageName);
System.out.println("Success - " + packageName + " set as override default dialer.");
}
diff --git a/config/preloaded-classes b/config/preloaded-classes
index b05d02c9eb15..e0a3f637645d 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -5583,8 +5583,6 @@ dalvik.system.CloseGuard$DefaultReporter
dalvik.system.CloseGuard$Reporter
dalvik.system.CloseGuard$Tracker
dalvik.system.CloseGuard
-dalvik.system.DalvikLogHandler
-dalvik.system.DalvikLogging
dalvik.system.DelegateLastClassLoader
dalvik.system.DexClassLoader
dalvik.system.DexFile$1
diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java
index 4ac00983af13..a468439c8e74 100644
--- a/core/java/android/annotation/SystemApi.java
+++ b/core/java/android/annotation/SystemApi.java
@@ -23,7 +23,6 @@ import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PACKAGE;
import static java.lang.annotation.ElementType.TYPE;
-import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -41,7 +40,6 @@ import java.lang.annotation.Target;
*/
@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
-@Repeatable(SystemApi.Container.class) // TODO(b/146727827): make this non-repeatable
public @interface SystemApi {
enum Client {
/**
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4f1d7f2c761c..262051d0af1e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -215,8 +215,8 @@ import java.util.function.Consumer;
* <a name="Fragments"></a>
* <h3>Fragments</h3>
*
- * <p>The {@link android.support.v4.app.FragmentActivity} subclass
- * can make use of the {@link android.support.v4.app.Fragment} class to better
+ * <p>The {@link androidx.fragment.app.FragmentActivity} subclass
+ * can make use of the {@link androidx.fragment.app.Fragment} class to better
* modularize their code, build more sophisticated user interfaces for larger
* screens, and help scale their application between small and large screens.</p>
*
@@ -1003,7 +1003,7 @@ public class Activity extends ContextThemeWrapper
/**
* Return the LoaderManager for this activity, creating it if needed.
*
- * @deprecated Use {@link android.support.v4.app.FragmentActivity#getSupportLoaderManager()}
+ * @deprecated Use {@link androidx.fragment.app.FragmentActivity#getSupportLoaderManager()}
*/
@Deprecated
public LoaderManager getLoaderManager() {
@@ -3022,7 +3022,7 @@ public class Activity extends ContextThemeWrapper
* Return the FragmentManager for interacting with fragments associated
* with this activity.
*
- * @deprecated Use {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager()}
+ * @deprecated Use {@link androidx.fragment.app.FragmentActivity#getSupportFragmentManager()}
*/
@Deprecated
public FragmentManager getFragmentManager() {
@@ -3035,7 +3035,7 @@ public class Activity extends ContextThemeWrapper
* method and before {@link Fragment#onCreate Fragment.onCreate()}.
*
* @deprecated Use {@link
- * android.support.v4.app.FragmentActivity#onAttachFragment(android.support.v4.app.Fragment)}
+ * androidx.fragment.app.FragmentActivity#onAttachFragment(androidx.fragment.app.Fragment)}
*/
@Deprecated
public void onAttachFragment(Fragment fragment) {
@@ -5847,8 +5847,8 @@ public class Activity extends ContextThemeWrapper
* @see Fragment#startActivity
* @see Fragment#startActivityForResult
*
- * @deprecated Use {@link android.support.v4.app.FragmentActivity#startActivityFromFragment(
- * android.support.v4.app.Fragment,Intent,int)}
+ * @deprecated Use {@link androidx.fragment.app.FragmentActivity#startActivityFromFragment(
+ * androidx.fragment.app.Fragment,Intent,int)}
*/
@Deprecated
public void startActivityFromFragment(@NonNull Fragment fragment,
@@ -5876,8 +5876,8 @@ public class Activity extends ContextThemeWrapper
* @see Fragment#startActivity
* @see Fragment#startActivityForResult
*
- * @deprecated Use {@link android.support.v4.app.FragmentActivity#startActivityFromFragment(
- * android.support.v4.app.Fragment,Intent,int,Bundle)}
+ * @deprecated Use {@link androidx.fragment.app.FragmentActivity#startActivityFromFragment(
+ * androidx.fragment.app.Fragment,Intent,int,Bundle)}
*/
@Deprecated
public void startActivityFromFragment(@NonNull Fragment fragment,
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 647f63025cf7..febb293921cd 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -35,7 +35,7 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
-import libcore.timezone.ZoneInfoDb;
+import com.android.i18n.timezone.ZoneInfoDb;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index c6a0de458df0..da3bc681ed34 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -102,7 +102,7 @@ import java.lang.reflect.InvocationTargetException;
* While the Fragment API was introduced in
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, a version of the API
* at is also available for use on older platforms through
- * {@link android.support.v4.app.FragmentActivity}. See the blog post
+ * {@link androidx.fragment.app.FragmentActivity}. See the blog post
* <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
* Fragments For All</a> for more details.
*
@@ -258,8 +258,8 @@ import java.lang.reflect.InvocationTargetException;
* pressing back will pop it to return the user to whatever previous state
* the activity UI was in.
*
- * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link android.support.v4.app.Fragment} for consistent behavior across all devices
+ * @deprecated Use the <a href="{@docRoot}jetpack">Jetpack Fragment Library</a>
+ * {@link androidx.fragment.app.Fragment} for consistent behavior across all devices
* and access to <a href="{@docRoot}topic/libraries/architecture/lifecycle.html">Lifecycle</a>.
*/
@Deprecated
@@ -432,7 +432,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* through {@link FragmentManager#saveFragmentInstanceState(Fragment)
* FragmentManager.saveFragmentInstanceState}.
*
- * @deprecated Use {@link android.support.v4.app.Fragment.SavedState}
+ * @deprecated Use {@link androidx.fragment.app.Fragment.SavedState}
*/
@Deprecated
public static class SavedState implements Parcelable {
@@ -479,7 +479,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* Thrown by {@link Fragment#instantiate(Context, String, Bundle)} when
* there is an instantiation failure.
*
- * @deprecated Use {@link android.support.v4.app.Fragment.InstantiationException}
+ * @deprecated Use {@link androidx.fragment.app.Fragment.InstantiationException}
*/
@Deprecated
static public class InstantiationException extends AndroidRuntimeException {
@@ -1055,7 +1055,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
/**
* Return the LoaderManager for this fragment, creating it if needed.
*
- * @deprecated Use {@link android.support.v4.app.Fragment#getLoaderManager()}
+ * @deprecated Use {@link androidx.fragment.app.Fragment#getLoaderManager()}
*/
@Deprecated
public LoaderManager getLoaderManager() {
diff --git a/core/java/android/app/admin/DelegatedAdminReceiver.java b/core/java/android/app/admin/DelegatedAdminReceiver.java
index f66de8d238ed..25b8eab452bf 100644
--- a/core/java/android/app/admin/DelegatedAdminReceiver.java
+++ b/core/java/android/app/admin/DelegatedAdminReceiver.java
@@ -63,6 +63,10 @@ public class DelegatedAdminReceiver extends BroadcastReceiver {
* Allows this receiver to select the alias for a private key and certificate pair for
* authentication. If this method returns null, the default {@link android.app.Activity} will
* be shown that lets the user pick a private key and certificate pair.
+ * If this method returns {@link KeyChain#KEY_ALIAS_SELECTION_DENIED},
+ * the default {@link android.app.Activity} will not be shown and the user will not be allowed
+ * to pick anything. And the app, that called {@link KeyChain#choosePrivateKeyAlias}, will
+ * receive {@code null} back.
*
* <p> This callback is only applicable if the delegated app has
* {@link DevicePolicyManager#DELEGATION_CERT_SELECTION} capability. Additionally, it must
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 4771fd8a00b6..e3a49f39bdc7 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -791,6 +791,10 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
* Allows this receiver to select the alias for a private key and certificate pair for
* authentication. If this method returns null, the default {@link android.app.Activity} will be
* shown that lets the user pick a private key and certificate pair.
+ * If this method returns {@link KeyChain#KEY_ALIAS_SELECTION_DENIED},
+ * the default {@link android.app.Activity} will not be shown and the user will not be allowed
+ * to pick anything. And the app, that called {@link KeyChain#choosePrivateKeyAlias}, will
+ * receive {@code null} back.
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index f962ea0966bd..47bd207fee65 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1784,6 +1784,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
+ if (DBG) Log.d(TAG, "removeActiveDevice, profiles: " + profiles);
return mService.removeActiveDevice(profiles);
}
} catch (RemoteException e) {
@@ -1828,6 +1829,9 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
+ if (DBG) {
+ Log.d(TAG, "setActiveDevice, device: " + device + ", profiles: " + profiles);
+ }
return mService.setActiveDevice(device, profiles);
}
} catch (RemoteException e) {
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 85e0e08b19c8..28363250ebda 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -19,7 +19,6 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
@@ -587,7 +586,6 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
@@ -637,7 +635,6 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return connection policy of the device
* @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 19240dc0bbc7..df11d3adac01 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -19,7 +19,6 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -53,6 +52,18 @@ public final class BluetoothMapClient implements BluetoothProfile {
public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY =
"android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY";
+ /**
+ * Action to notify read status changed
+ */
+ public static final String ACTION_MESSAGE_READ_STATUS_CHANGED =
+ "android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED";
+
+ /**
+ * Action to notify deleted status changed
+ */
+ public static final String ACTION_MESSAGE_DELETED_STATUS_CHANGED =
+ "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED";
+
/* Extras used in ACTION_MESSAGE_RECEIVED intent.
* NOTE: HANDLE is only valid for a single session with the device. */
public static final String EXTRA_MESSAGE_HANDLE =
@@ -66,6 +77,25 @@ public final class BluetoothMapClient implements BluetoothProfile {
public static final String EXTRA_SENDER_CONTACT_NAME =
"android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME";
+ /**
+ * Used as a boolean extra in ACTION_MESSAGE_DELETED_STATUS_CHANGED
+ * Contains the MAP message deleted status
+ * Possible values are:
+ * true: deleted
+ * false: undeleted
+ */
+ public static final String EXTRA_MESSAGE_DELETED_STATUS =
+ "android.bluetooth.mapmce.profile.extra.MESSAGE_DELETED_STATUS";
+
+ /**
+ * Extra used in ACTION_MESSAGE_READ_STATUS_CHANGED or ACTION_MESSAGE_DELETED_STATUS_CHANGED
+ * Possible values are:
+ * 0: failure
+ * 1: success
+ */
+ public static final String EXTRA_RESULT_CODE =
+ "android.bluetooth.device.extra.RESULT_CODE";
+
/** There was an error trying to obtain the state */
public static final int STATE_ERROR = -1;
@@ -76,6 +106,12 @@ public final class BluetoothMapClient implements BluetoothProfile {
private static final int UPLOADING_FEATURE_BITMASK = 0x08;
+ /** Parameters in setMessageStatus */
+ public static final int UNREAD = 0;
+ public static final int READ = 1;
+ public static final int UNDELETED = 2;
+ public static final int DELETED = 3;
+
private BluetoothAdapter mAdapter;
private final BluetoothProfileConnector<IBluetoothMapClient> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.MAP_CLIENT,
@@ -276,7 +312,6 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
@@ -325,7 +360,6 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return connection policy of the device
* @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) Log.d(TAG, "getConnectionPolicy(" + device + ")");
@@ -408,6 +442,38 @@ public final class BluetoothMapClient implements BluetoothProfile {
return false;
}
+ /**
+ * Set message status of message on MSE
+ * <p>
+ * When read status changed, the result will be published via
+ * {@link #ACTION_MESSAGE_READ_STATUS_CHANGED}
+ * When deleted status changed, the result will be published via
+ * {@link #ACTION_MESSAGE_DELETED_STATUS_CHANGED}
+ *
+ * @param device Bluetooth device
+ * @param handle message handle
+ * @param status <code>UNREAD</code> for "unread", <code>READ</code> for
+ * "read", <code>UNDELETED</code> for "undeleted", <code>DELETED</code> for
+ * "deleted", otherwise return error
+ * @return <code>true</code> if request has been sent, <code>false</code> on error
+ *
+ */
+ @RequiresPermission(Manifest.permission.READ_SMS)
+ public boolean setMessageStatus(BluetoothDevice device, String handle, int status) {
+ if (DBG) Log.d(TAG, "setMessageStatus(" + device + ", " + handle + ", " + status + ")");
+ final IBluetoothMapClient service = getService();
+ if (service != null && isEnabled() && isValidDevice(device) && handle != null &&
+ (status == READ || status == UNREAD || status == UNDELETED || status == DELETED)) {
+ try {
+ return service.setMessageStatus(device, handle, status);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ return false;
+ }
+
private boolean isEnabled() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index d3452ffb4586..f356da18fc73 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -19,7 +19,6 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -276,7 +275,6 @@ public final class BluetoothPbapClient implements BluetoothProfile {
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
@@ -329,7 +327,6 @@ public final class BluetoothPbapClient implements BluetoothProfile {
* @return connection policy of the device
* @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) {
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index 6e0348158f48..48e8c1ada255 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -18,7 +18,6 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
@@ -328,7 +327,6 @@ public final class BluetoothSap implements BluetoothProfile {
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setConnectionPolicy(BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
@@ -377,7 +375,6 @@ public final class BluetoothSap implements BluetoothProfile {
* @return connection policy of the device
* @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0e610169ffa6..62669e019558 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -46,7 +46,6 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
-import android.annotation.TestApi;
import android.apex.ApexInfo;
import android.app.ActivityTaskManager;
import android.app.ActivityThread;
@@ -2682,7 +2681,6 @@ public class PackageParser {
* not compatible with this platform
* @hide Exposed for unit testing only.
*/
- @TestApi
public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
@Nullable String targetCode, @NonNull String[] platformSdkCodenames,
@NonNull String[] outError) {
@@ -2747,7 +2745,6 @@ public class PackageParser {
* compatible with this platform
* @hide Exposed for unit testing only.
*/
- @TestApi
public static int computeMinSdkVersion(@IntRange(from = 1) int minVers,
@Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
@NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
@@ -4845,7 +4842,6 @@ public class PackageParser {
* AndroidManifest.xml.
* @hide Exposed for unit testing only.
*/
- @TestApi
public static int getActivityConfigChanges(int configChanges, int recreateOnConfigChanges) {
return configChanges | ((~recreateOnConfigChanges) & RECREATE_ON_CONFIG_CHANGES_MASK);
}
diff --git a/core/java/android/hardware/GeomagneticField.java b/core/java/android/hardware/GeomagneticField.java
index 0d7b695d7f1d..cbfe4fa58e40 100644
--- a/core/java/android/hardware/GeomagneticField.java
+++ b/core/java/android/hardware/GeomagneticField.java
@@ -16,7 +16,8 @@
package android.hardware;
-import java.util.GregorianCalendar;
+import java.util.Calendar;
+import java.util.TimeZone;
/**
* Estimates magnetic field at a given point on
@@ -26,7 +27,7 @@ import java.util.GregorianCalendar;
* <p>This uses the World Magnetic Model produced by the United States National
* Geospatial-Intelligence Agency. More details about the model can be found at
* <a href="http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml">http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml</a>.
- * This class currently uses WMM-2015 which is valid until 2020, but should
+ * This class currently uses WMM-2020 which is valid until 2025, but should
* produce acceptable results for several years after that. Future versions of
* Android may use a newer version of the model.
*/
@@ -48,69 +49,72 @@ public class GeomagneticField {
static private final float EARTH_REFERENCE_RADIUS_KM = 6371.2f;
// These coefficients and the formulae used below are from:
- // NOAA Technical Report: The US/UK World Magnetic Model for 2015-2020
- static private final float[][] G_COEFF = new float[][] {
- { 0.0f },
- { -29438.5f, -1501.1f },
- { -2445.3f, 3012.5f, 1676.6f },
- { 1351.1f, -2352.3f, 1225.6f, 581.9f },
- { 907.2f, 813.7f, 120.3f, -335.0f, 70.3f },
- { -232.6f, 360.1f, 192.4f, -141.0f, -157.4f, 4.3f },
- { 69.5f, 67.4f, 72.8f, -129.8f, -29.0f, 13.2f, -70.9f },
- { 81.6f, -76.1f, -6.8f, 51.9f, 15.0f, 9.3f, -2.8f, 6.7f },
- { 24.0f, 8.6f, -16.9f, -3.2f, -20.6f, 13.3f, 11.7f, -16.0f, -2.0f },
- { 5.4f, 8.8f, 3.1f, -3.1f, 0.6f, -13.3f, -0.1f, 8.7f, -9.1f, -10.5f },
- { -1.9f, -6.5f, 0.2f, 0.6f, -0.6f, 1.7f, -0.7f, 2.1f, 2.3f, -1.8f, -3.6f },
- { 3.1f, -1.5f, -2.3f, 2.1f, -0.9f, 0.6f, -0.7f, 0.2f, 1.7f, -0.2f, 0.4f, 3.5f },
- { -2.0f, -0.3f, 0.4f, 1.3f, -0.9f, 0.9f, 0.1f, 0.5f, -0.4f, -0.4f, 0.2f, -0.9f, 0.0f } };
-
- static private final float[][] H_COEFF = new float[][] {
- { 0.0f },
- { 0.0f, 4796.2f },
- { 0.0f, -2845.6f, -642.0f },
- { 0.0f, -115.3f, 245.0f, -538.3f },
- { 0.0f, 283.4f, -188.6f, 180.9f, -329.5f },
- { 0.0f, 47.4f, 196.9f, -119.4f, 16.1f, 100.1f },
- { 0.0f, -20.7f, 33.2f, 58.8f, -66.5f, 7.3f, 62.5f },
- { 0.0f, -54.1f, -19.4f, 5.6f, 24.4f, 3.3f, -27.5f, -2.3f },
- { 0.0f, 10.2f, -18.1f, 13.2f, -14.6f, 16.2f, 5.7f, -9.1f, 2.2f },
- { 0.0f, -21.6f, 10.8f, 11.7f, -6.8f, -6.9f, 7.8f, 1.0f, -3.9f, 8.5f },
- { 0.0f, 3.3f, -0.3f, 4.6f, 4.4f, -7.9f, -0.6f, -4.1f, -2.8f, -1.1f, -8.7f },
- { 0.0f, -0.1f, 2.1f, -0.7f, -1.1f, 0.7f, -0.2f, -2.1f, -1.5f, -2.5f, -2.0f, -2.3f },
- { 0.0f, -1.0f, 0.5f, 1.8f, -2.2f, 0.3f, 0.7f, -0.1f, 0.3f, 0.2f, -0.9f, -0.2f, 0.7f } };
-
- static private final float[][] DELTA_G = new float[][] {
- { 0.0f },
- { 10.7f, 17.9f },
- { -8.6f, -3.3f, 2.4f },
- { 3.1f, -6.2f, -0.4f, -10.4f },
- { -0.4f, 0.8f, -9.2f, 4.0f, -4.2f },
- { -0.2f, 0.1f, -1.4f, 0.0f, 1.3f, 3.8f },
- { -0.5f, -0.2f, -0.6f, 2.4f, -1.1f, 0.3f, 1.5f },
- { 0.2f, -0.2f, -0.4f, 1.3f, 0.2f, -0.4f, -0.9f, 0.3f },
- { 0.0f, 0.1f, -0.5f, 0.5f, -0.2f, 0.4f, 0.2f, -0.4f, 0.3f },
- { 0.0f, -0.1f, -0.1f, 0.4f, -0.5f, -0.2f, 0.1f, 0.0f, -0.2f, -0.1f },
- { 0.0f, 0.0f, -0.1f, 0.3f, -0.1f, -0.1f, -0.1f, 0.0f, -0.2f, -0.1f, -0.2f },
- { 0.0f, 0.0f, -0.1f, 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.1f, -0.1f },
- { 0.1f, 0.0f, 0.0f, 0.1f, -0.1f, 0.0f, 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } };
-
- static private final float[][] DELTA_H = new float[][] {
- { 0.0f },
- { 0.0f, -26.8f },
- { 0.0f, -27.1f, -13.3f },
- { 0.0f, 8.4f, -0.4f, 2.3f },
- { 0.0f, -0.6f, 5.3f, 3.0f, -5.3f },
- { 0.0f, 0.4f, 1.6f, -1.1f, 3.3f, 0.1f },
- { 0.0f, 0.0f, -2.2f, -0.7f, 0.1f, 1.0f, 1.3f },
- { 0.0f, 0.7f, 0.5f, -0.2f, -0.1f, -0.7f, 0.1f, 0.1f },
- { 0.0f, -0.3f, 0.3f, 0.3f, 0.6f, -0.1f, -0.2f, 0.3f, 0.0f },
- { 0.0f, -0.2f, -0.1f, -0.2f, 0.1f, 0.1f, 0.0f, -0.2f, 0.4f, 0.3f },
- { 0.0f, 0.1f, -0.1f, 0.0f, 0.0f, -0.2f, 0.1f, -0.1f, -0.2f, 0.1f, -0.1f },
- { 0.0f, 0.0f, 0.1f, 0.0f, 0.1f, 0.0f, 0.0f, 0.1f, 0.0f, -0.1f, 0.0f, -0.1f },
- { 0.0f, 0.0f, 0.0f, -0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } };
-
- static private final long BASE_TIME =
- new GregorianCalendar(2015, 1, 1).getTimeInMillis();
+ // NOAA Technical Report: The US/UK World Magnetic Model for 2020-2025
+ static private final float[][] G_COEFF = new float[][]{
+ {0.0f},
+ {-29404.5f, -1450.7f},
+ {-2500.0f, 2982.0f, 1676.8f},
+ {1363.9f, -2381.0f, 1236.2f, 525.7f},
+ {903.1f, 809.4f, 86.2f, -309.4f, 47.9f},
+ {-234.4f, 363.1f, 187.8f, -140.7f, -151.2f, 13.7f},
+ {65.9f, 65.6f, 73.0f, -121.5f, -36.2f, 13.5f, -64.7f},
+ {80.6f, -76.8f, -8.3f, 56.5f, 15.8f, 6.4f, -7.2f, 9.8f},
+ {23.6f, 9.8f, -17.5f, -0.4f, -21.1f, 15.3f, 13.7f, -16.5f, -0.3f},
+ {5.0f, 8.2f, 2.9f, -1.4f, -1.1f, -13.3f, 1.1f, 8.9f, -9.3f, -11.9f},
+ {-1.9f, -6.2f, -0.1f, 1.7f, -0.9f, 0.6f, -0.9f, 1.9f, 1.4f, -2.4f, -3.9f},
+ {3.0f, -1.4f, -2.5f, 2.4f, -0.9f, 0.3f, -0.7f, -0.1f, 1.4f, -0.6f, 0.2f, 3.1f},
+ {-2.0f, -0.1f, 0.5f, 1.3f, -1.2f, 0.7f, 0.3f, 0.5f, -0.2f, -0.5f, 0.1f, -1.1f, -0.3f}};
+
+ static private final float[][] H_COEFF = new float[][]{
+ {0.0f},
+ {0.0f, 4652.9f},
+ {0.0f, -2991.6f, -734.8f},
+ {0.0f, -82.2f, 241.8f, -542.9f},
+ {0.0f, 282.0f, -158.4f, 199.8f, -350.1f},
+ {0.0f, 47.7f, 208.4f, -121.3f, 32.2f, 99.1f},
+ {0.0f, -19.1f, 25.0f, 52.7f, -64.4f, 9.0f, 68.1f},
+ {0.0f, -51.4f, -16.8f, 2.3f, 23.5f, -2.2f, -27.2f, -1.9f},
+ {0.0f, 8.4f, -15.3f, 12.8f, -11.8f, 14.9f, 3.6f, -6.9f, 2.8f},
+ {0.0f, -23.3f, 11.1f, 9.8f, -5.1f, -6.2f, 7.8f, 0.4f, -1.5f, 9.7f},
+ {0.0f, 3.4f, -0.2f, 3.5f, 4.8f, -8.6f, -0.1f, -4.2f, -3.4f, -0.1f, -8.8f},
+ {0.0f, 0.0f, 2.6f, -0.5f, -0.4f, 0.6f, -0.2f, -1.7f, -1.6f, -3.0f, -2.0f, -2.6f},
+ {0.0f, -1.2f, 0.5f, 1.3f, -1.8f, 0.1f, 0.7f, -0.1f, 0.6f, 0.2f, -0.9f, 0.0f, 0.5f}};
+
+ static private final float[][] DELTA_G = new float[][]{
+ {0.0f},
+ {6.7f, 7.7f},
+ {-11.5f, -7.1f, -2.2f},
+ {2.8f, -6.2f, 3.4f, -12.2f},
+ {-1.1f, -1.6f, -6.0f, 5.4f, -5.5f},
+ {-0.3f, 0.6f, -0.7f, 0.1f, 1.2f, 1.0f},
+ {-0.6f, -0.4f, 0.5f, 1.4f, -1.4f, 0.0f, 0.8f},
+ {-0.1f, -0.3f, -0.1f, 0.7f, 0.2f, -0.5f, -0.8f, 1.0f},
+ {-0.1f, 0.1f, -0.1f, 0.5f, -0.1f, 0.4f, 0.5f, 0.0f, 0.4f},
+ {-0.1f, -0.2f, 0.0f, 0.4f, -0.3f, 0.0f, 0.3f, 0.0f, 0.0f, -0.4f},
+ {0.0f, 0.0f, 0.0f, 0.2f, -0.1f, -0.2f, 0.0f, -0.1f, -0.2f, -0.1f, 0.0f},
+ {0.0f, -0.1f, 0.0f, 0.0f, 0.0f, -0.1f, 0.0f, 0.0f, -0.1f, -0.1f, -0.1f, -0.1f},
+ {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.1f}};
+
+ static private final float[][] DELTA_H = new float[][]{
+ {0.0f},
+ {0.0f, -25.1f},
+ {0.0f, -30.2f, -23.9f},
+ {0.0f, 5.7f, -1.0f, 1.1f},
+ {0.0f, 0.2f, 6.9f, 3.7f, -5.6f},
+ {0.0f, 0.1f, 2.5f, -0.9f, 3.0f, 0.5f},
+ {0.0f, 0.1f, -1.8f, -1.4f, 0.9f, 0.1f, 1.0f},
+ {0.0f, 0.5f, 0.6f, -0.7f, -0.2f, -1.2f, 0.2f, 0.3f},
+ {0.0f, -0.3f, 0.7f, -0.2f, 0.5f, -0.3f, -0.5f, 0.4f, 0.1f},
+ {0.0f, -0.3f, 0.2f, -0.4f, 0.4f, 0.1f, 0.0f, -0.2f, 0.5f, 0.2f},
+ {0.0f, 0.0f, 0.1f, -0.3f, 0.1f, -0.2f, 0.1f, 0.0f, -0.1f, 0.2f, 0.0f},
+ {0.0f, 0.0f, 0.1f, 0.0f, 0.2f, 0.0f, 0.0f, 0.1f, 0.0f, -0.1f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, -0.1f, 0.1f, 0.0f, 0.0f, 0.0f, 0.1f, 0.0f, 0.0f, 0.0f, -0.1f}};
+
+ static private final long BASE_TIME = new Calendar.Builder()
+ .setTimeZone(TimeZone.getTimeZone("UTC"))
+ .setDate(2020, Calendar.JANUARY, 1)
+ .build()
+ .getTimeInMillis();
// The ratio between the Gauss-normalized associated Legendre functions and
// the Schmid quasi-normalized ones. Compute these once staticly since they
@@ -190,7 +194,7 @@ public class GeomagneticField {
// We now compute the magnetic field strength given the geocentric
// location. The magnetic field is the derivative of the potential
// function defined by the model. See NOAA Technical Report: The US/UK
- // World Magnetic Model for 2015-2020 for the derivation.
+ // World Magnetic Model for 2020-2025 for the derivation.
float gcX = 0.0f; // Geocentric northwards component.
float gcY = 0.0f; // Geocentric eastwards component.
float gcZ = 0.0f; // Geocentric downwards component.
@@ -203,7 +207,7 @@ public class GeomagneticField {
// Negative derivative with respect to latitude, divided by
// radius. This looks like the negation of the version in the
- // NOAA Techincal report because that report used
+ // NOAA Technical report because that report used
// P_n^m(sin(theta)) and we use P_n^m(cos(90 - theta)), so the
// derivative with respect to theta is negated.
gcX += relativeRadiusPower[n+2]
diff --git a/core/java/android/net/DnsPacket.java b/core/java/android/net/DnsPacket.java
deleted file mode 100644
index 83e57e0a047b..000000000000
--- a/core/java/android/net/DnsPacket.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2019 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.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.text.TextUtils;
-
-import com.android.internal.util.BitUtils;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.text.DecimalFormat;
-import java.text.FieldPosition;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Defines basic data for DNS protocol based on RFC 1035.
- * Subclasses create the specific format used in DNS packet.
- *
- * @hide
- */
-public abstract class DnsPacket {
- public class DnsHeader {
- private static final String TAG = "DnsHeader";
- public final int id;
- public final int flags;
- public final int rcode;
- private final int[] mRecordCount;
-
- /**
- * Create a new DnsHeader from a positioned ByteBuffer.
- *
- * The ByteBuffer must be in network byte order (which is the default).
- * Reads the passed ByteBuffer from its current position and decodes a DNS header.
- * When this constructor returns, the reading position of the ByteBuffer has been
- * advanced to the end of the DNS header record.
- * This is meant to chain with other methods reading a DNS response in sequence.
- */
- DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException {
- id = BitUtils.uint16(buf.getShort());
- flags = BitUtils.uint16(buf.getShort());
- rcode = flags & 0xF;
- mRecordCount = new int[NUM_SECTIONS];
- for (int i = 0; i < NUM_SECTIONS; ++i) {
- mRecordCount[i] = BitUtils.uint16(buf.getShort());
- }
- }
-
- /**
- * Get record count by type.
- */
- public int getRecordCount(int type) {
- return mRecordCount[type];
- }
- }
-
- /**
- * Superclass for DNS questions and DNS resource records.
- *
- * DNS questions (No TTL/RDATA)
- * DNS resource records (With TTL/RDATA)
- */
- public class DnsRecord {
- private static final int MAXNAMESIZE = 255;
- private static final int MAXLABELSIZE = 63;
- private static final int MAXLABELCOUNT = 128;
- private static final int NAME_NORMAL = 0;
- private static final int NAME_COMPRESSION = 0xC0;
- private final DecimalFormat byteFormat = new DecimalFormat();
- private final FieldPosition pos = new FieldPosition(0);
-
- private static final String TAG = "DnsRecord";
-
- public final String dName;
- public final int nsType;
- public final int nsClass;
- public final long ttl;
- private final byte[] mRdata;
-
- /**
- * Create a new DnsRecord from a positioned ByteBuffer.
- *
- * Reads the passed ByteBuffer from its current position and decodes a DNS record.
- * When this constructor returns, the reading position of the ByteBuffer has been
- * advanced to the end of the DNS header record.
- * This is meant to chain with other methods reading a DNS response in sequence.
- *
- * @param ByteBuffer input of record, must be in network byte order
- * (which is the default).
- */
- DnsRecord(int recordType, @NonNull ByteBuffer buf)
- throws BufferUnderflowException, ParseException {
- dName = parseName(buf, 0 /* Parse depth */);
- if (dName.length() > MAXNAMESIZE) {
- throw new ParseException(
- "Parse name fail, name size is too long: " + dName.length());
- }
- nsType = BitUtils.uint16(buf.getShort());
- nsClass = BitUtils.uint16(buf.getShort());
-
- if (recordType != QDSECTION) {
- ttl = BitUtils.uint32(buf.getInt());
- final int length = BitUtils.uint16(buf.getShort());
- mRdata = new byte[length];
- buf.get(mRdata);
- } else {
- ttl = 0;
- mRdata = null;
- }
- }
-
- /**
- * Get a copy of rdata.
- */
- @Nullable
- public byte[] getRR() {
- return (mRdata == null) ? null : mRdata.clone();
- }
-
- /**
- * Convert label from {@code byte[]} to {@code String}
- *
- * Follows the same conversion rules of the native code (ns_name.c in libc)
- */
- private String labelToString(@NonNull byte[] label) {
- final StringBuffer sb = new StringBuffer();
- for (int i = 0; i < label.length; ++i) {
- int b = BitUtils.uint8(label[i]);
- // Control characters and non-ASCII characters.
- if (b <= 0x20 || b >= 0x7f) {
- // Append the byte as an escaped decimal number, e.g., "\19" for 0x13.
- sb.append('\\');
- byteFormat.format(b, sb, pos);
- } else if (b == '"' || b == '.' || b == ';' || b == '\\'
- || b == '(' || b == ')' || b == '@' || b == '$') {
- // Append the byte as an escaped character, e.g., "\:" for 0x3a.
- sb.append('\\');
- sb.append((char) b);
- } else {
- // Append the byte as a character, e.g., "a" for 0x61.
- sb.append((char) b);
- }
- }
- return sb.toString();
- }
-
- private String parseName(@NonNull ByteBuffer buf, int depth) throws
- BufferUnderflowException, ParseException {
- if (depth > MAXLABELCOUNT) {
- throw new ParseException("Failed to parse name, too many labels");
- }
- final int len = BitUtils.uint8(buf.get());
- final int mask = len & NAME_COMPRESSION;
- if (0 == len) {
- return "";
- } else if (mask != NAME_NORMAL && mask != NAME_COMPRESSION) {
- throw new ParseException("Parse name fail, bad label type");
- } else if (mask == NAME_COMPRESSION) {
- // Name compression based on RFC 1035 - 4.1.4 Message compression
- final int offset = ((len & ~NAME_COMPRESSION) << 8) + BitUtils.uint8(buf.get());
- final int oldPos = buf.position();
- if (offset >= oldPos - 2) {
- throw new ParseException("Parse compression name fail, invalid compression");
- }
- buf.position(offset);
- final String pointed = parseName(buf, depth + 1);
- buf.position(oldPos);
- return pointed;
- } else {
- final byte[] label = new byte[len];
- buf.get(label);
- final String head = labelToString(label);
- if (head.length() > MAXLABELSIZE) {
- throw new ParseException("Parse name fail, invalid label length");
- }
- final String tail = parseName(buf, depth + 1);
- return TextUtils.isEmpty(tail) ? head : head + "." + tail;
- }
- }
- }
-
- public static final int QDSECTION = 0;
- public static final int ANSECTION = 1;
- public static final int NSSECTION = 2;
- public static final int ARSECTION = 3;
- private static final int NUM_SECTIONS = ARSECTION + 1;
-
- private static final String TAG = DnsPacket.class.getSimpleName();
-
- protected final DnsHeader mHeader;
- protected final List<DnsRecord>[] mRecords;
-
- protected DnsPacket(@NonNull byte[] data) throws ParseException {
- if (null == data) throw new ParseException("Parse header failed, null input data");
- final ByteBuffer buffer;
- try {
- buffer = ByteBuffer.wrap(data);
- mHeader = new DnsHeader(buffer);
- } catch (BufferUnderflowException e) {
- throw new ParseException("Parse Header fail, bad input data", e);
- }
-
- mRecords = new ArrayList[NUM_SECTIONS];
-
- for (int i = 0; i < NUM_SECTIONS; ++i) {
- final int count = mHeader.getRecordCount(i);
- if (count > 0) {
- mRecords[i] = new ArrayList(count);
- }
- for (int j = 0; j < count; ++j) {
- try {
- mRecords[i].add(new DnsRecord(i, buffer));
- } catch (BufferUnderflowException e) {
- throw new ParseException("Parse record fail", e);
- }
- }
- }
- }
-}
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 0b1a84534e38..3f7660f5709a 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -38,6 +38,8 @@ import android.os.MessageQueue;
import android.system.ErrnoException;
import android.util.Log;
+import com.android.net.module.util.DnsPacket;
+
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -97,7 +99,7 @@ public final class DnsResolver {
@interface DnsError {}
/**
* Indicates that there was an error parsing the response the query.
- * The cause of this error is available via getCause() and is a ParseException.
+ * The cause of this error is available via getCause() and is a {@link ParseException}.
*/
public static final int ERROR_PARSE = 0;
/**
@@ -290,8 +292,15 @@ public final class DnsResolver {
}
try {
mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses());
- } catch (ParseException e) {
- mDnsException = new DnsException(ERROR_PARSE, e);
+ } catch (DnsPacket.ParseException e) {
+ // Convert the com.android.net.module.util.DnsPacket.ParseException to an
+ // android.net.ParseException. This is the type that was used in Q and is implied
+ // by the public documentation of ERROR_PARSE.
+ //
+ // DnsPacket cannot throw android.net.ParseException directly because it's @hide.
+ ParseException pe = new ParseException(e.reason, e.getCause());
+ pe.setStackTrace(e.getStackTrace());
+ mDnsException = new DnsException(ERROR_PARSE, pe);
}
maybeReportAnswer();
}
diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl
index e3d075988c8a..14aa0237f24a 100644
--- a/core/java/android/net/ITetheredInterfaceCallback.aidl
+++ b/core/java/android/net/ITetheredInterfaceCallback.aidl
@@ -17,7 +17,7 @@
package android.net;
/** @hide */
-interface ITetheredInterfaceCallback {
+oneway interface ITetheredInterfaceCallback {
void onAvailable(in String iface);
void onUnavailable();
} \ No newline at end of file
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 0e10c42e61db..0eb3c1e8ad01 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -38,7 +38,9 @@ import java.util.Arrays;
* Representation of a MAC address.
*
* This class only supports 48 bits long addresses and does not support 64 bits long addresses.
- * Instances of this class are immutable.
+ * Instances of this class are immutable. This class provides implementations of hashCode()
+ * and equals() that make it suitable for use as keys in standard implementations of
+ * {@link java.util.Map}.
*/
public final class MacAddress implements Parcelable {
@@ -122,12 +124,22 @@ public final class MacAddress implements Parcelable {
}
/**
+ * Convert this MacAddress to a byte array.
+ *
+ * The returned array is in network order. For example, if this MacAddress is 1:2:3:4:5:6,
+ * the returned array is [1, 2, 3, 4, 5, 6].
+ *
* @return a byte array representation of this MacAddress.
*/
public @NonNull byte[] toByteArray() {
return byteAddrFromLongAddr(mAddr);
}
+ /**
+ * Returns a human-readable representation of this MacAddress.
+ * The exact format is implementation-dependent and should not be assumed to have any
+ * particular format.
+ */
@Override
public @NonNull String toString() {
return stringAddrFromLongAddr(mAddr);
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index cb9463a59d34..4b806e714ffe 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -84,6 +84,15 @@ public class NetworkTemplate implements Parcelable {
* @hide
*/
public static final int NETWORK_TYPE_ALL = -1;
+ /**
+ * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is
+ * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along
+ * with NR state as connected. This should not be overlapped with any of the
+ * {@code TelephonyManager.NETWORK_TYPE_*} constants.
+ *
+ * @hide
+ */
+ public static final int NETWORK_TYPE_5G_NSA = -2;
private static boolean isKnownMatchRule(final int rule) {
switch (rule) {
@@ -472,6 +481,9 @@ public class NetworkTemplate implements Parcelable {
return TelephonyManager.NETWORK_TYPE_LTE;
case TelephonyManager.NETWORK_TYPE_NR:
return TelephonyManager.NETWORK_TYPE_NR;
+ // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}.
+ case NetworkTemplate.NETWORK_TYPE_5G_NSA:
+ return NetworkTemplate.NETWORK_TYPE_5G_NSA;
default:
return TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 779f7bc91e8f..0b92b95128d3 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -155,6 +155,14 @@ public class NetworkUtils {
public static native Network getDnsNetwork() throws ErrnoException;
/**
+ * Allow/Disallow creating AF_INET/AF_INET6 sockets and DNS lookups for current process.
+ *
+ * @param allowNetworking whether to allow or disallow creating AF_INET/AF_INET6 sockets
+ * and DNS lookups.
+ */
+ public static native void setAllowNetworkingForProcess(boolean allowNetworking);
+
+ /**
* Get the tcp repair window associated with the {@code fd}.
*
* @param fd the tcp socket's {@link FileDescriptor}.
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index ffe9ae9521a8..a32b41f6be4b 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -127,18 +127,6 @@ public class ProxyInfo implements Parcelable {
}
/**
- * Create a ProxyProperties that points at a PAC URL.
- * @hide
- */
- public ProxyInfo(String pacFileUrl) {
- mHost = LOCAL_HOST;
- mPort = LOCAL_PORT;
- mExclusionList = LOCAL_EXCL_LIST;
- mParsedExclusionList = parseExclusionList(mExclusionList);
- mPacFileUrl = Uri.parse(pacFileUrl);
- }
-
- /**
* Only used in PacManager after Local Proxy is bound.
* @hide
*/
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 50379222f1a9..9418cbf27643 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1051,8 +1051,6 @@ public final class Debug
if (outStream != null)
outStream.close();
}
-
- VMDebug.startEmulatorTracing();
}
/**
@@ -1066,8 +1064,6 @@ public final class Debug
* region of code.</p>
*/
public static void stopNativeTracing() {
- VMDebug.stopEmulatorTracing();
-
// Open the sysfs file for writing and write "0" to it.
PrintWriter outStream = null;
try {
@@ -1096,7 +1092,7 @@ public final class Debug
* To temporarily enable tracing, use {@link #startNativeTracing()}.
*/
public static void enableEmulatorTraceOutput() {
- VMDebug.startEmulatorTracing();
+ Log.w(TAG, "Unimplemented");
}
/**
@@ -2028,25 +2024,6 @@ public final class Debug
public static final native int getBinderDeathObjectCount();
/**
- * Primes the register map cache.
- *
- * Only works for classes in the bootstrap class loader. Does not
- * cause classes to be loaded if they're not already present.
- *
- * The classAndMethodDesc argument is a concatentation of the VM-internal
- * class descriptor, method name, and method descriptor. Examples:
- * Landroid/os/Looper;.loop:()V
- * Landroid/app/ActivityThread;.main:([Ljava/lang/String;)V
- *
- * @param classAndMethodDesc the method to prepare
- *
- * @hide
- */
- public static final boolean cacheRegisterMap(String classAndMethodDesc) {
- return VMDebug.cacheRegisterMap(classAndMethodDesc);
- }
-
- /**
* Dumps the contents of VM reference tables (e.g. JNI locals and
* globals) to the log file.
*
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 7c42c36e7747..64ab1d711765 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -96,6 +96,15 @@ public abstract class HwBinder implements IHwBinder {
throws RemoteException, NoSuchElementException;
/**
+ * This allows getService to bypass the VINTF manifest for testing only.
+ *
+ * Disabled on user builds.
+ * @hide
+ */
+ public static native final void setTrebleTestingOverride(
+ boolean testingOverride);
+
+ /**
* Configures how many threads the process-wide hwbinder threadpool
* has to process incoming requests.
*
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 994ed2148baa..337786734bb8 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -194,6 +194,13 @@ public class Process {
*/
public static final int FSVERITY_CERT_UID = 1075;
+ /**
+ * GID that corresponds to the INTERNET permission.
+ * Must match the value of AID_INET.
+ * @hide
+ */
+ public static final int INET_GID = 3003;
+
/** {@hide} */
public static final int NOBODY_UID = 9999;
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index a95fe3c4043d..7946dda3170d 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1331,8 +1331,7 @@ public final class Telephony {
Object[] messages;
try {
messages = (Object[]) intent.getSerializableExtra("pdus");
- }
- catch (ClassCastException e) {
+ } catch (ClassCastException e) {
Rlog.e(TAG, "getMessagesFromIntent: " + e);
return null;
}
@@ -1344,9 +1343,12 @@ public final class Telephony {
String format = intent.getStringExtra("format");
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
- SubscriptionManager.getDefaultSmsSubscriptionId());
-
- Rlog.v(TAG, " getMessagesFromIntent sub_id : " + subId);
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ Rlog.v(TAG, "getMessagesFromIntent with valid subId : " + subId);
+ } else {
+ Rlog.v(TAG, "getMessagesFromIntent");
+ }
int pduCount = messages.length;
SmsMessage[] msgs = new SmsMessage[pduCount];
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 5924421decce..3611d924b904 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -18,7 +18,6 @@ package android.telephony;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
-import android.annotation.TestApi;
import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
@@ -248,7 +247,6 @@ public class TelephonyRegistryManager {
* @param incomingNumber incoming phone number.
* @hide
*/
- @TestApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void notifyCallStateChangedForAllSubscriptions(@CallState int state,
@Nullable String incomingNumber) {
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 0863a813543c..4fe6752be4d5 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -19,12 +19,13 @@ package android.text.format;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.icu.text.DateFormatSymbols;
+import android.icu.text.DateTimePatternGenerator;
import android.provider.Settings;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.SpannedString;
-import libcore.icu.ICU;
import libcore.icu.LocaleData;
import java.text.SimpleDateFormat;
@@ -251,7 +252,8 @@ public class DateFormat {
* @return a string pattern suitable for use with {@link java.text.SimpleDateFormat}.
*/
public static String getBestDateTimePattern(Locale locale, String skeleton) {
- return ICU.getBestDateTimePattern(skeleton, locale);
+ DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(locale);
+ return dtpg.getBestPattern(skeleton);
}
/**
@@ -333,7 +335,52 @@ public class DateFormat {
* order returned here.
*/
public static char[] getDateFormatOrder(Context context) {
- return ICU.getDateFormatOrder(getDateFormatString(context));
+ return getDateFormatOrder(getDateFormatString(context));
+ }
+
+ /**
+ * @hide Used by internal framework class {@link android.widget.DatePickerSpinnerDelegate}.
+ */
+ public static char[] getDateFormatOrder(String pattern) {
+ char[] result = new char[3];
+ int resultIndex = 0;
+ boolean sawDay = false;
+ boolean sawMonth = false;
+ boolean sawYear = false;
+
+ for (int i = 0; i < pattern.length(); ++i) {
+ char ch = pattern.charAt(i);
+ if (ch == 'd' || ch == 'L' || ch == 'M' || ch == 'y') {
+ if (ch == 'd' && !sawDay) {
+ result[resultIndex++] = 'd';
+ sawDay = true;
+ } else if ((ch == 'L' || ch == 'M') && !sawMonth) {
+ result[resultIndex++] = 'M';
+ sawMonth = true;
+ } else if ((ch == 'y') && !sawYear) {
+ result[resultIndex++] = 'y';
+ sawYear = true;
+ }
+ } else if (ch == 'G') {
+ // Ignore the era specifier, if present.
+ } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
+ throw new IllegalArgumentException("Bad pattern character '" + ch + "' in "
+ + pattern);
+ } else if (ch == '\'') {
+ if (i < pattern.length() - 1 && pattern.charAt(i + 1) == '\'') {
+ ++i;
+ } else {
+ i = pattern.indexOf('\'', i + 1);
+ if (i == -1) {
+ throw new IllegalArgumentException("Bad quoting in " + pattern);
+ }
+ ++i;
+ }
+ } else {
+ // Ignore spaces and punctuation.
+ }
+ }
+ return result;
}
private static String getDateFormatString(Context context) {
@@ -429,6 +476,8 @@ public class DateFormat {
int count;
LocaleData localeData = LocaleData.get(Locale.getDefault());
+ DateFormatSymbols dfs = getIcuDateFormatSymbols(Locale.getDefault());
+ String[] amPm = dfs.getAmPmStrings();
int len = inFormat.length();
@@ -450,7 +499,7 @@ public class DateFormat {
switch (c) {
case 'A':
case 'a':
- replacement = localeData.amPm[inDate.get(Calendar.AM_PM) - Calendar.AM];
+ replacement = amPm[inDate.get(Calendar.AM_PM) - Calendar.AM];
break;
case 'd':
replacement = zeroPad(inDate.get(Calendar.DATE), count);
@@ -632,4 +681,16 @@ public class DateFormat {
private static String zeroPad(int inValue, int inMinDigits) {
return String.format(Locale.getDefault(), "%0" + inMinDigits + "d", inValue);
}
+
+ /**
+ * We use Gregorian calendar for date formats in android.text.format and various UI widget
+ * historically. It's a utility method to get an {@link DateFormatSymbols} instance. Note that
+ * {@link DateFormatSymbols} has cache, and external cache is not needed unless same instance is
+ * requested repeatedly in the performance critical code.
+ *
+ * @hide
+ */
+ public static DateFormatSymbols getIcuDateFormatSymbols(Locale locale) {
+ return new DateFormatSymbols(android.icu.util.GregorianCalendar.class, locale);
+ }
}
diff --git a/core/java/android/text/format/DateIntervalFormat.java b/core/java/android/text/format/DateIntervalFormat.java
new file mode 100644
index 000000000000..de9ec7ab9ea9
--- /dev/null
+++ b/core/java/android/text/format/DateIntervalFormat.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2013 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.text.format;
+
+import static android.text.format.DateUtils.FORMAT_SHOW_TIME;
+import static android.text.format.DateUtils.FORMAT_UTC;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
+import android.icu.util.Calendar;
+import android.icu.util.ULocale;
+import android.util.LruCache;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.text.FieldPosition;
+import java.util.TimeZone;
+
+/**
+ * A wrapper of {@link android.icu.text.DateIntervalFormat} used by {@link DateUtilsBridge}.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = PACKAGE)
+public final class DateIntervalFormat {
+
+ private static final LruCache<String, android.icu.text.DateIntervalFormat> CACHED_FORMATTERS =
+ new LruCache<>(8);
+
+ private DateIntervalFormat() {
+ }
+
+ /**
+ * Format a date range.
+ */
+ @VisibleForTesting(visibility = PACKAGE)
+ public static String formatDateRange(long startMs, long endMs, int flags, String olsonId) {
+ if ((flags & FORMAT_UTC) != 0) {
+ olsonId = "UTC";
+ }
+ // We create a java.util.TimeZone here to use libcore's data and libcore's olson ID /
+ // pseudo-tz logic.
+ TimeZone tz = (olsonId != null) ? TimeZone.getTimeZone(olsonId) : TimeZone.getDefault();
+ android.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz);
+ ULocale icuLocale = ULocale.getDefault();
+ return formatDateRange(icuLocale, icuTimeZone, startMs, endMs, flags);
+ }
+
+ /**
+ * Format a date range. This is our slightly more sensible internal API.
+ * A truly sane replacement would take a skeleton instead of int flags.
+ */
+ @VisibleForTesting(visibility = PACKAGE)
+ public static String formatDateRange(ULocale icuLocale, android.icu.util.TimeZone icuTimeZone,
+ long startMs, long endMs, int flags) {
+ Calendar startCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, startMs);
+ Calendar endCalendar;
+ if (startMs == endMs) {
+ endCalendar = startCalendar;
+ } else {
+ endCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, endMs);
+ }
+
+ // Special handling when the range ends at midnight:
+ // - If we're not showing times, and the range is non-empty, we fudge the end date so we
+ // don't count the day that's about to start.
+ // - If we are showing times, and the range ends at exactly 00:00 of the day following
+ // its start (which can be thought of as 24:00 the same day), we fudge the end date so we
+ // don't show the dates --- unless the start is anything displayed as 00:00, in which case
+ // we include both dates to disambiguate.
+ // This is not the behavior of icu4j's DateIntervalFormat, but it's the required behavior
+ // of Android's DateUtils.formatDateRange.
+ if (isExactlyMidnight(endCalendar)) {
+ boolean showTime = (flags & FORMAT_SHOW_TIME) == FORMAT_SHOW_TIME;
+ boolean endsDayAfterStart = DateUtilsBridge.dayDistance(startCalendar, endCalendar)
+ == 1;
+ if ((!showTime && startMs != endMs)
+ || (endsDayAfterStart
+ && !DateUtilsBridge.isDisplayMidnightUsingSkeleton(startCalendar))) {
+ endCalendar.add(Calendar.DAY_OF_MONTH, -1);
+ }
+ }
+
+ String skeleton = DateUtilsBridge.toSkeleton(startCalendar, endCalendar, flags);
+ synchronized (CACHED_FORMATTERS) {
+ android.icu.text.DateIntervalFormat formatter =
+ getFormatter(skeleton, icuLocale, icuTimeZone);
+ return formatter.format(startCalendar, endCalendar, new StringBuffer(),
+ new FieldPosition(0)).toString();
+ }
+ }
+
+ private static android.icu.text.DateIntervalFormat getFormatter(String skeleton, ULocale locale,
+ android.icu.util.TimeZone icuTimeZone) {
+ String key = skeleton + "\t" + locale + "\t" + icuTimeZone;
+ android.icu.text.DateIntervalFormat formatter = CACHED_FORMATTERS.get(key);
+ if (formatter != null) {
+ return formatter;
+ }
+ formatter = android.icu.text.DateIntervalFormat.getInstance(skeleton, locale);
+ formatter.setTimeZone(icuTimeZone);
+ CACHED_FORMATTERS.put(key, formatter);
+ return formatter;
+ }
+
+ private static boolean isExactlyMidnight(Calendar c) {
+ return c.get(Calendar.HOUR_OF_DAY) == 0
+ && c.get(Calendar.MINUTE) == 0
+ && c.get(Calendar.SECOND) == 0
+ && c.get(Calendar.MILLISECOND) == 0;
+ }
+}
diff --git a/core/java/android/text/format/DateTimeFormat.java b/core/java/android/text/format/DateTimeFormat.java
new file mode 100644
index 000000000000..064d7172c44f
--- /dev/null
+++ b/core/java/android/text/format/DateTimeFormat.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 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.text.format;
+
+import android.icu.text.DateFormat;
+import android.icu.text.DateTimePatternGenerator;
+import android.icu.text.DisplayContext;
+import android.icu.text.SimpleDateFormat;
+import android.icu.util.Calendar;
+import android.icu.util.ULocale;
+import android.util.LruCache;
+
+/**
+ * A formatter that outputs a single date/time.
+ *
+ * @hide
+ */
+class DateTimeFormat {
+ private static final FormatterCache CACHED_FORMATTERS = new FormatterCache();
+
+ static class FormatterCache extends LruCache<String, DateFormat> {
+ FormatterCache() {
+ super(8);
+ }
+ }
+
+ private DateTimeFormat() {
+ }
+
+ public static String format(ULocale icuLocale, Calendar time, int flags,
+ DisplayContext displayContext) {
+ String skeleton = DateUtilsBridge.toSkeleton(time, flags);
+ String key = skeleton + "\t" + icuLocale + "\t" + time.getTimeZone();
+ synchronized (CACHED_FORMATTERS) {
+ DateFormat formatter = CACHED_FORMATTERS.get(key);
+ if (formatter == null) {
+ DateTimePatternGenerator generator = DateTimePatternGenerator.getInstance(
+ icuLocale);
+ formatter = new SimpleDateFormat(generator.getBestPattern(skeleton), icuLocale);
+ CACHED_FORMATTERS.put(key, formatter);
+ }
+ formatter.setContext(displayContext);
+ return formatter.format(time);
+ }
+ }
+}
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index f236f19e973f..f313faec1756 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -27,9 +27,7 @@ import android.icu.util.MeasureUnit;
import com.android.internal.R;
-import libcore.icu.DateIntervalFormat;
import libcore.icu.LocaleData;
-import libcore.icu.RelativeDateTimeFormatter;
import java.io.IOException;
import java.util.Calendar;
@@ -224,7 +222,8 @@ public class DateUtils
*/
@Deprecated
public static String getAMPMString(int ampm) {
- return LocaleData.get(Locale.getDefault()).amPm[ampm - Calendar.AM];
+ String[] amPm = DateFormat.getIcuDateFormatSymbols(Locale.getDefault()).getAmPmStrings();
+ return amPm[ampm - Calendar.AM];
}
/**
diff --git a/core/java/android/text/format/DateUtilsBridge.java b/core/java/android/text/format/DateUtilsBridge.java
new file mode 100644
index 000000000000..92ec9cf6d736
--- /dev/null
+++ b/core/java/android/text/format/DateUtilsBridge.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2015 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.text.format;
+
+import static android.text.format.DateUtils.FORMAT_12HOUR;
+import static android.text.format.DateUtils.FORMAT_24HOUR;
+import static android.text.format.DateUtils.FORMAT_ABBREV_ALL;
+import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
+import static android.text.format.DateUtils.FORMAT_ABBREV_TIME;
+import static android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY;
+import static android.text.format.DateUtils.FORMAT_NO_MONTH_DAY;
+import static android.text.format.DateUtils.FORMAT_NO_YEAR;
+import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_TIME;
+import static android.text.format.DateUtils.FORMAT_SHOW_WEEKDAY;
+import static android.text.format.DateUtils.FORMAT_SHOW_YEAR;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
+import android.icu.util.Calendar;
+import android.icu.util.GregorianCalendar;
+import android.icu.util.TimeZone;
+import android.icu.util.ULocale;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Common methods and constants for the various ICU formatters used to support {@link
+ * android.text.format.DateUtils}.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = PACKAGE)
+public final class DateUtilsBridge {
+
+ /**
+ * Creates an immutable ICU timezone backed by the specified libcore timezone data. At the time
+ * of writing the libcore implementation is faster but restricted to 1902 - 2038. Callers must
+ * not modify the {@code tz} after calling this method.
+ */
+ public static TimeZone icuTimeZone(java.util.TimeZone tz) {
+ TimeZone icuTimeZone = TimeZone.getTimeZone(tz.getID());
+ icuTimeZone.freeze(); // Optimization - allows the timezone to be copied cheaply.
+ return icuTimeZone;
+ }
+
+ /**
+ * Create a GregorianCalendar based on the arguments
+ */
+ public static Calendar createIcuCalendar(TimeZone icuTimeZone, ULocale icuLocale,
+ long timeInMillis) {
+ Calendar calendar = new GregorianCalendar(icuTimeZone, icuLocale);
+ calendar.setTimeInMillis(timeInMillis);
+ return calendar;
+ }
+
+ public static String toSkeleton(Calendar calendar, int flags) {
+ return toSkeleton(calendar, calendar, flags);
+ }
+
+ public static String toSkeleton(Calendar startCalendar, Calendar endCalendar, int flags) {
+ if ((flags & FORMAT_ABBREV_ALL) != 0) {
+ flags |= FORMAT_ABBREV_MONTH | FORMAT_ABBREV_TIME | FORMAT_ABBREV_WEEKDAY;
+ }
+
+ String monthPart = "MMMM";
+ if ((flags & FORMAT_NUMERIC_DATE) != 0) {
+ monthPart = "M";
+ } else if ((flags & FORMAT_ABBREV_MONTH) != 0) {
+ monthPart = "MMM";
+ }
+
+ String weekPart = "EEEE";
+ if ((flags & FORMAT_ABBREV_WEEKDAY) != 0) {
+ weekPart = "EEE";
+ }
+
+ String timePart = "j"; // "j" means choose 12 or 24 hour based on current locale.
+ if ((flags & FORMAT_24HOUR) != 0) {
+ timePart = "H";
+ } else if ((flags & FORMAT_12HOUR) != 0) {
+ timePart = "h";
+ }
+
+ // If we've not been asked to abbreviate times, or we're using the 24-hour clock (where it
+ // never makes sense to leave out the minutes), include minutes. This gets us times like
+ // "4 PM" while avoiding times like "16" (for "16:00").
+ if ((flags & FORMAT_ABBREV_TIME) == 0 || (flags & FORMAT_24HOUR) != 0) {
+ timePart += "m";
+ } else {
+ // Otherwise, we're abbreviating a 12-hour time, and should only show the minutes
+ // if they're not both "00".
+ if (!(onTheHour(startCalendar) && onTheHour(endCalendar))) {
+ timePart = timePart + "m";
+ }
+ }
+
+ if (fallOnDifferentDates(startCalendar, endCalendar)) {
+ flags |= FORMAT_SHOW_DATE;
+ }
+
+ if (fallInSameMonth(startCalendar, endCalendar) && (flags & FORMAT_NO_MONTH_DAY) != 0) {
+ flags &= (~FORMAT_SHOW_WEEKDAY);
+ flags &= (~FORMAT_SHOW_TIME);
+ }
+
+ if ((flags & (FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_SHOW_WEEKDAY)) == 0) {
+ flags |= FORMAT_SHOW_DATE;
+ }
+
+ // If we've been asked to show the date, work out whether we think we should show the year.
+ if ((flags & FORMAT_SHOW_DATE) != 0) {
+ if ((flags & FORMAT_SHOW_YEAR) != 0) {
+ // The caller explicitly wants us to show the year.
+ } else if ((flags & FORMAT_NO_YEAR) != 0) {
+ // The caller explicitly doesn't want us to show the year, even if we otherwise
+ // would.
+ } else if (!fallInSameYear(startCalendar, endCalendar) || !isThisYear(startCalendar)) {
+ flags |= FORMAT_SHOW_YEAR;
+ }
+ }
+
+ StringBuilder builder = new StringBuilder();
+ if ((flags & (FORMAT_SHOW_DATE | FORMAT_NO_MONTH_DAY)) != 0) {
+ if ((flags & FORMAT_SHOW_YEAR) != 0) {
+ builder.append("y");
+ }
+ builder.append(monthPart);
+ if ((flags & FORMAT_NO_MONTH_DAY) == 0) {
+ builder.append("d");
+ }
+ }
+ if ((flags & FORMAT_SHOW_WEEKDAY) != 0) {
+ builder.append(weekPart);
+ }
+ if ((flags & FORMAT_SHOW_TIME) != 0) {
+ builder.append(timePart);
+ }
+ return builder.toString();
+ }
+
+ public static int dayDistance(Calendar c1, Calendar c2) {
+ return c2.get(Calendar.JULIAN_DAY) - c1.get(Calendar.JULIAN_DAY);
+ }
+
+ /**
+ * Returns whether the argument will be displayed as if it were midnight, using any of the
+ * skeletons provided by {@link #toSkeleton}.
+ */
+ public static boolean isDisplayMidnightUsingSkeleton(Calendar c) {
+ // All the skeletons returned by toSkeleton have minute precision (they may abbreviate
+ // 4:00 PM to 4 PM but will still show the following minute as 4:01 PM).
+ return c.get(Calendar.HOUR_OF_DAY) == 0 && c.get(Calendar.MINUTE) == 0;
+ }
+
+ private static boolean onTheHour(Calendar c) {
+ return c.get(Calendar.MINUTE) == 0 && c.get(Calendar.SECOND) == 0;
+ }
+
+ private static boolean fallOnDifferentDates(Calendar c1, Calendar c2) {
+ return c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR)
+ || c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH)
+ || c1.get(Calendar.DAY_OF_MONTH) != c2.get(Calendar.DAY_OF_MONTH);
+ }
+
+ private static boolean fallInSameMonth(Calendar c1, Calendar c2) {
+ return c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH);
+ }
+
+ private static boolean fallInSameYear(Calendar c1, Calendar c2) {
+ return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR);
+ }
+
+ private static boolean isThisYear(Calendar c) {
+ Calendar now = (Calendar) c.clone();
+ now.setTimeInMillis(System.currentTimeMillis());
+ return c.get(Calendar.YEAR) == now.get(Calendar.YEAR);
+ }
+}
diff --git a/core/java/android/text/format/RelativeDateTimeFormatter.java b/core/java/android/text/format/RelativeDateTimeFormatter.java
new file mode 100644
index 000000000000..9096469699c1
--- /dev/null
+++ b/core/java/android/text/format/RelativeDateTimeFormatter.java
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2015 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.text.format;
+
+import static android.text.format.DateUtils.FORMAT_ABBREV_ALL;
+import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
+import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE;
+import static android.text.format.DateUtils.FORMAT_NO_YEAR;
+import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_TIME;
+import static android.text.format.DateUtils.FORMAT_SHOW_YEAR;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
+import android.icu.text.DisplayContext;
+import android.icu.util.Calendar;
+import android.icu.util.ULocale;
+import android.util.LruCache;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Locale;
+
+/**
+ * Exposes icu4j's RelativeDateTimeFormatter.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = PACKAGE)
+public final class RelativeDateTimeFormatter {
+
+ public static final long SECOND_IN_MILLIS = 1000;
+ public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
+ public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
+ public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
+ public static final long WEEK_IN_MILLIS = DAY_IN_MILLIS * 7;
+ // YEAR_IN_MILLIS considers 364 days as a year. However, since this
+ // constant comes from public API in DateUtils, it cannot be fixed here.
+ public static final long YEAR_IN_MILLIS = WEEK_IN_MILLIS * 52;
+
+ private static final int DAY_IN_MS = 24 * 60 * 60 * 1000;
+ private static final int EPOCH_JULIAN_DAY = 2440588;
+
+ private static final FormatterCache CACHED_FORMATTERS = new FormatterCache();
+
+ static class FormatterCache
+ extends LruCache<String, android.icu.text.RelativeDateTimeFormatter> {
+ FormatterCache() {
+ super(8);
+ }
+ }
+
+ private RelativeDateTimeFormatter() {
+ }
+
+ /**
+ * This is the internal API that implements the functionality of DateUtils
+ * .getRelativeTimeSpanString(long,
+ * long, long, int), which is to return a string describing 'time' as a time relative to 'now'
+ * such as '5 minutes ago', or 'In 2 days'. More examples can be found in DateUtils' doc.
+ * <p>
+ * In the implementation below, it selects the appropriate time unit based on the elapsed time
+ * between time' and 'now', e.g. minutes, days and etc. Callers may also specify the desired
+ * minimum resolution to show in the result. For example, '45 minutes ago' will become '0 hours
+ * ago' when minResolution is HOUR_IN_MILLIS. Once getting the quantity and unit to display, it
+ * calls icu4j's RelativeDateTimeFormatter to format the actual string according to the given
+ * locale.
+ * <p>
+ * Note that when minResolution is set to DAY_IN_MILLIS, it returns the result depending on the
+ * actual date difference. For example, it will return 'Yesterday' even if 'time' was less than
+ * 24 hours ago but falling onto a different calendar day.
+ * <p>
+ * It takes two additional parameters of Locale and TimeZone than the DateUtils' API. Caller
+ * must specify the locale and timezone. FORMAT_ABBREV_RELATIVE or FORMAT_ABBREV_ALL can be set
+ * in 'flags' to get the abbreviated forms when available. When 'time' equals to 'now', it
+ * always // returns a string like '0 seconds/minutes/... ago' according to minResolution.
+ */
+ public static String getRelativeTimeSpanString(Locale locale, java.util.TimeZone tz, long time,
+ long now, long minResolution, int flags) {
+ // Android has been inconsistent about capitalization in the past. e.g. bug
+ // http://b/20247811.
+ // Now we capitalize everything consistently.
+ final DisplayContext displayContext =
+ DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE;
+ return getRelativeTimeSpanString(locale, tz, time, now, minResolution, flags,
+ displayContext);
+ }
+
+ public static String getRelativeTimeSpanString(Locale locale, java.util.TimeZone tz, long time,
+ long now, long minResolution, int flags, DisplayContext displayContext) {
+ if (locale == null) {
+ throw new NullPointerException("locale == null");
+ }
+ if (tz == null) {
+ throw new NullPointerException("tz == null");
+ }
+ ULocale icuLocale = ULocale.forLocale(locale);
+ android.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz);
+ return getRelativeTimeSpanString(icuLocale, icuTimeZone, time, now, minResolution, flags,
+ displayContext);
+ }
+
+ private static String getRelativeTimeSpanString(ULocale icuLocale,
+ android.icu.util.TimeZone icuTimeZone, long time, long now, long minResolution,
+ int flags,
+ DisplayContext displayContext) {
+
+ long duration = Math.abs(now - time);
+ boolean past = (now >= time);
+
+ android.icu.text.RelativeDateTimeFormatter.Style style;
+ if ((flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0) {
+ style = android.icu.text.RelativeDateTimeFormatter.Style.SHORT;
+ } else {
+ style = android.icu.text.RelativeDateTimeFormatter.Style.LONG;
+ }
+
+ android.icu.text.RelativeDateTimeFormatter.Direction direction;
+ if (past) {
+ direction = android.icu.text.RelativeDateTimeFormatter.Direction.LAST;
+ } else {
+ direction = android.icu.text.RelativeDateTimeFormatter.Direction.NEXT;
+ }
+
+ // 'relative' defaults to true as we are generating relative time span
+ // string. It will be set to false when we try to display strings without
+ // a quantity, such as 'Yesterday', etc.
+ boolean relative = true;
+ int count;
+ android.icu.text.RelativeDateTimeFormatter.RelativeUnit unit;
+ android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit aunit = null;
+
+ if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) {
+ count = (int) (duration / SECOND_IN_MILLIS);
+ unit = android.icu.text.RelativeDateTimeFormatter.RelativeUnit.SECONDS;
+ } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) {
+ count = (int) (duration / MINUTE_IN_MILLIS);
+ unit = android.icu.text.RelativeDateTimeFormatter.RelativeUnit.MINUTES;
+ } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) {
+ // Even if 'time' actually happened yesterday, we don't format it as
+ // "Yesterday" in this case. Unless the duration is longer than a day,
+ // or minResolution is specified as DAY_IN_MILLIS by user.
+ count = (int) (duration / HOUR_IN_MILLIS);
+ unit = android.icu.text.RelativeDateTimeFormatter.RelativeUnit.HOURS;
+ } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
+ count = Math.abs(dayDistance(icuTimeZone, time, now));
+ unit = android.icu.text.RelativeDateTimeFormatter.RelativeUnit.DAYS;
+
+ if (count == 2) {
+ // Some locales have special terms for "2 days ago". Return them if
+ // available. Note that we cannot set up direction and unit here and
+ // make it fall through to use the call near the end of the function,
+ // because for locales that don't have special terms for "2 days ago",
+ // icu4j returns an empty string instead of falling back to strings
+ // like "2 days ago".
+ String str;
+ if (past) {
+ synchronized (CACHED_FORMATTERS) {
+ str = getFormatter(icuLocale, style, displayContext).format(
+ android.icu.text.RelativeDateTimeFormatter.Direction.LAST_2,
+ android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY);
+ }
+ } else {
+ synchronized (CACHED_FORMATTERS) {
+ str = getFormatter(icuLocale, style, displayContext).format(
+ android.icu.text.RelativeDateTimeFormatter.Direction.NEXT_2,
+ android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY);
+ }
+ }
+ if (str != null && !str.isEmpty()) {
+ return str;
+ }
+ // Fall back to show something like "2 days ago".
+ } else if (count == 1) {
+ // Show "Yesterday / Tomorrow" instead of "1 day ago / In 1 day".
+ aunit = android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY;
+ relative = false;
+ } else if (count == 0) {
+ // Show "Today" if time and now are on the same day.
+ aunit = android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY;
+ direction = android.icu.text.RelativeDateTimeFormatter.Direction.THIS;
+ relative = false;
+ }
+ } else if (minResolution == WEEK_IN_MILLIS) {
+ count = (int) (duration / WEEK_IN_MILLIS);
+ unit = android.icu.text.RelativeDateTimeFormatter.RelativeUnit.WEEKS;
+ } else {
+ Calendar timeCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, time);
+ // The duration is longer than a week and minResolution is not
+ // WEEK_IN_MILLIS. Return the absolute date instead of relative time.
+
+ // Bug 19822016:
+ // If user doesn't supply the year display flag, we need to explicitly
+ // set that to show / hide the year based on time and now. Otherwise
+ // formatDateRange() would determine that based on the current system
+ // time and may give wrong results.
+ if ((flags & (FORMAT_NO_YEAR | FORMAT_SHOW_YEAR)) == 0) {
+ Calendar nowCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale,
+ now);
+
+ if (timeCalendar.get(Calendar.YEAR) != nowCalendar.get(Calendar.YEAR)) {
+ flags |= FORMAT_SHOW_YEAR;
+ } else {
+ flags |= FORMAT_NO_YEAR;
+ }
+ }
+ return DateTimeFormat.format(icuLocale, timeCalendar, flags, displayContext);
+ }
+
+ synchronized (CACHED_FORMATTERS) {
+ android.icu.text.RelativeDateTimeFormatter formatter =
+ getFormatter(icuLocale, style, displayContext);
+ if (relative) {
+ return formatter.format(count, direction, unit);
+ } else {
+ return formatter.format(direction, aunit);
+ }
+ }
+ }
+
+ /**
+ * This is the internal API that implements DateUtils.getRelativeDateTimeString(long, long,
+ * long, long, int), which is to return a string describing 'time' as a time relative to 'now',
+ * formatted like '[relative time/date], [time]'. More examples can be found in DateUtils' doc.
+ * <p>
+ * The function is similar to getRelativeTimeSpanString, but it always appends the absolute time
+ * to the relative time string to return '[relative time/date clause], [absolute time clause]'.
+ * It also takes an extra parameter transitionResolution to determine the format of the date
+ * clause. When the elapsed time is less than the transition resolution, it displays the
+ * relative time string. Otherwise, it gives the absolute numeric date string as the date
+ * clause. With the date and time clauses, it relies on icu4j's
+ * RelativeDateTimeFormatter::combineDateAndTime()
+ * to concatenate the two.
+ * <p>
+ * It takes two additional parameters of Locale and TimeZone than the DateUtils' API. Caller
+ * must specify the locale and timezone. FORMAT_ABBREV_RELATIVE or FORMAT_ABBREV_ALL can be set
+ * in 'flags' to get the abbreviated forms when they are available.
+ * <p>
+ * Bug 5252772: Since the absolute time will always be part of the result, minResolution will be
+ * set to at least DAY_IN_MILLIS to correctly indicate the date difference. For example, when
+ * it's 1:30 AM, it will return 'Yesterday, 11:30 PM' for getRelativeDateTimeString(null, null,
+ * now - 2 hours, now, HOUR_IN_MILLIS, DAY_IN_MILLIS, 0), instead of '2 hours ago, 11:30 PM'
+ * even with minResolution being HOUR_IN_MILLIS.
+ */
+ public static String getRelativeDateTimeString(Locale locale, java.util.TimeZone tz, long time,
+ long now, long minResolution, long transitionResolution, int flags) {
+
+ if (locale == null) {
+ throw new NullPointerException("locale == null");
+ }
+ if (tz == null) {
+ throw new NullPointerException("tz == null");
+ }
+ ULocale icuLocale = ULocale.forLocale(locale);
+ android.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz);
+
+ long duration = Math.abs(now - time);
+ // It doesn't make much sense to have results like: "1 week ago, 10:50 AM".
+ if (transitionResolution > WEEK_IN_MILLIS) {
+ transitionResolution = WEEK_IN_MILLIS;
+ }
+ android.icu.text.RelativeDateTimeFormatter.Style style;
+ if ((flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0) {
+ style = android.icu.text.RelativeDateTimeFormatter.Style.SHORT;
+ } else {
+ style = android.icu.text.RelativeDateTimeFormatter.Style.LONG;
+ }
+
+ Calendar timeCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, time);
+ Calendar nowCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, now);
+
+ int days = Math.abs(DateUtilsBridge.dayDistance(timeCalendar, nowCalendar));
+
+ // Now get the date clause, either in relative format or the actual date.
+ String dateClause;
+ if (duration < transitionResolution) {
+ // This is to fix bug 5252772. If there is any date difference, we should
+ // promote the minResolution to DAY_IN_MILLIS so that it can display the
+ // date instead of "x hours/minutes ago, [time]".
+ if (days > 0 && minResolution < DAY_IN_MILLIS) {
+ minResolution = DAY_IN_MILLIS;
+ }
+ dateClause = getRelativeTimeSpanString(icuLocale, icuTimeZone, time, now, minResolution,
+ flags, DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE);
+ } else {
+ // We always use fixed flags to format the date clause. User-supplied
+ // flags are ignored.
+ if (timeCalendar.get(Calendar.YEAR) != nowCalendar.get(Calendar.YEAR)) {
+ // Different years
+ flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE;
+ } else {
+ // Default
+ flags = FORMAT_SHOW_DATE | FORMAT_NO_YEAR | FORMAT_ABBREV_MONTH;
+ }
+
+ dateClause = DateTimeFormat.format(icuLocale, timeCalendar, flags,
+ DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE);
+ }
+
+ String timeClause = DateTimeFormat.format(icuLocale, timeCalendar, FORMAT_SHOW_TIME,
+ DisplayContext.CAPITALIZATION_NONE);
+
+ // icu4j also has other options available to control the capitalization. We are currently
+ // using
+ // the _NONE option only.
+ DisplayContext capitalizationContext = DisplayContext.CAPITALIZATION_NONE;
+
+ // Combine the two clauses, such as '5 days ago, 10:50 AM'.
+ synchronized (CACHED_FORMATTERS) {
+ return getFormatter(icuLocale, style, capitalizationContext)
+ .combineDateAndTime(dateClause, timeClause);
+ }
+ }
+
+ /**
+ * getFormatter() caches the RelativeDateTimeFormatter instances based on the combination of
+ * localeName, sytle and capitalizationContext. It should always be used along with the action
+ * of the formatter in a synchronized block, because otherwise the formatter returned by
+ * getFormatter() may have been evicted by the time of the call to formatter->action().
+ */
+ private static android.icu.text.RelativeDateTimeFormatter getFormatter(
+ ULocale locale, android.icu.text.RelativeDateTimeFormatter.Style style,
+ DisplayContext displayContext) {
+ String key = locale + "\t" + style + "\t" + displayContext;
+ android.icu.text.RelativeDateTimeFormatter formatter = CACHED_FORMATTERS.get(key);
+ if (formatter == null) {
+ formatter = android.icu.text.RelativeDateTimeFormatter.getInstance(
+ locale, null, style, displayContext);
+ CACHED_FORMATTERS.put(key, formatter);
+ }
+ return formatter;
+ }
+
+ // Return the date difference for the two times in a given timezone.
+ private static int dayDistance(android.icu.util.TimeZone icuTimeZone, long startTime,
+ long endTime) {
+ return julianDay(icuTimeZone, endTime) - julianDay(icuTimeZone, startTime);
+ }
+
+ private static int julianDay(android.icu.util.TimeZone icuTimeZone, long time) {
+ long utcMs = time + icuTimeZone.getOffset(time);
+ return (int) (utcMs / DAY_IN_MS) + EPOCH_JULIAN_DAY;
+ }
+}
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 8e8409d15143..e7339380df69 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -18,8 +18,8 @@ package android.text.format;
import android.util.TimeFormatException;
-import libcore.timezone.ZoneInfoDb;
-import libcore.util.ZoneInfo;
+import com.android.i18n.timezone.ZoneInfoData;
+import com.android.i18n.timezone.ZoneInfoDb;
import java.util.Locale;
import java.util.TimeZone;
@@ -1059,15 +1059,15 @@ public class Time {
* to the enclosing object, but others do not: thus separate state is retained.
*/
private static class TimeCalculator {
- public final ZoneInfo.WallTime wallTime;
+ public final ZoneInfoData.WallTime wallTime;
public String timezone;
// Information about the current timezone.
- private ZoneInfo zoneInfo;
+ private ZoneInfoData mZoneInfoData;
public TimeCalculator(String timezoneId) {
- this.zoneInfo = lookupZoneInfo(timezoneId);
- this.wallTime = new ZoneInfo.WallTime();
+ this.mZoneInfoData = lookupZoneInfoData(timezoneId);
+ this.wallTime = new ZoneInfoData.WallTime();
}
public long toMillis(boolean ignoreDst) {
@@ -1075,7 +1075,7 @@ public class Time {
wallTime.setIsDst(-1);
}
- int r = wallTime.mktime(zoneInfo);
+ int r = wallTime.mktime(mZoneInfoData);
if (r == -1) {
return -1;
}
@@ -1087,7 +1087,7 @@ public class Time {
int intSeconds = (int) (millis / 1000);
updateZoneInfoFromTimeZone();
- wallTime.localtime(intSeconds, zoneInfo);
+ wallTime.localtime(intSeconds, mZoneInfoData);
}
public String format(String format) {
@@ -1095,31 +1095,31 @@ public class Time {
format = "%c";
}
TimeFormatter formatter = new TimeFormatter();
- return formatter.format(format, wallTime, zoneInfo);
+ return formatter.format(format, wallTime, mZoneInfoData);
}
private void updateZoneInfoFromTimeZone() {
- if (!zoneInfo.getID().equals(timezone)) {
- this.zoneInfo = lookupZoneInfo(timezone);
+ if (!mZoneInfoData.getID().equals(timezone)) {
+ this.mZoneInfoData = lookupZoneInfoData(timezone);
}
}
- private static ZoneInfo lookupZoneInfo(String timezoneId) {
- ZoneInfo zoneInfo = ZoneInfoDb.getInstance().makeTimeZone(timezoneId);
- if (zoneInfo == null) {
- zoneInfo = ZoneInfoDb.getInstance().makeTimeZone("GMT");
+ private static ZoneInfoData lookupZoneInfoData(String timezoneId) {
+ ZoneInfoData zoneInfoData = ZoneInfoDb.getInstance().makeZoneInfoData(timezoneId);
+ if (zoneInfoData == null) {
+ zoneInfoData = ZoneInfoDb.getInstance().makeZoneInfoData("GMT");
}
- if (zoneInfo == null) {
+ if (zoneInfoData == null) {
throw new AssertionError("GMT not found: \"" + timezoneId + "\"");
}
- return zoneInfo;
+ return zoneInfoData;
}
public void switchTimeZone(String timezone) {
- int seconds = wallTime.mktime(zoneInfo);
+ int seconds = wallTime.mktime(mZoneInfoData);
this.timezone = timezone;
updateZoneInfoFromTimeZone();
- wallTime.localtime(seconds, zoneInfo);
+ wallTime.localtime(seconds, mZoneInfoData);
}
public String format2445(boolean hasTime) {
diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java
index f7fd89d7d819..9393f36d1b6f 100644
--- a/core/java/android/text/format/TimeFormatter.java
+++ b/core/java/android/text/format/TimeFormatter.java
@@ -21,9 +21,11 @@
package android.text.format;
import android.content.res.Resources;
+import android.icu.text.DateFormatSymbols;
+
+import com.android.i18n.timezone.ZoneInfoData;
import libcore.icu.LocaleData;
-import libcore.util.ZoneInfo;
import java.nio.CharBuffer;
import java.time.Instant;
@@ -54,11 +56,13 @@ class TimeFormatter {
* The Locale for which the cached LocaleData and formats have been loaded.
*/
private static Locale sLocale;
+ private static DateFormatSymbols sDateFormatSymbols;
private static LocaleData sLocaleData;
private static String sTimeOnlyFormat;
private static String sDateOnlyFormat;
private static String sDateTimeFormat;
+ private final DateFormatSymbols dateFormatSymbols;
private final LocaleData localeData;
private final String dateTimeFormat;
private final String timeOnlyFormat;
@@ -73,6 +77,7 @@ class TimeFormatter {
if (sLocale == null || !(locale.equals(sLocale))) {
sLocale = locale;
+ sDateFormatSymbols = DateFormat.getIcuDateFormatSymbols(locale);
sLocaleData = LocaleData.get(locale);
Resources r = Resources.getSystem();
@@ -81,6 +86,7 @@ class TimeFormatter {
sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time);
}
+ this.dateFormatSymbols = sDateFormatSymbols;
this.dateTimeFormat = sDateTimeFormat;
this.timeOnlyFormat = sTimeOnlyFormat;
this.dateOnlyFormat = sDateOnlyFormat;
@@ -94,8 +100,8 @@ class TimeFormatter {
* incorrect digit localization behavior.
*/
String formatMillisWithFixedFormat(long timeMillis) {
- // This method is deliberately not a general purpose replacement for
- // format(String, ZoneInfo.WallTime, ZoneInfo): It hard-codes the pattern used; many of the
+ // This method is deliberately not a general purpose replacement for format(String,
+ // ZoneInfoData.WallTime, ZoneInfoData): It hard-codes the pattern used; many of the
// pattern characters supported by Time.format() have unusual behavior which would make
// using java.time.format or similar packages difficult. It would be a lot of work to share
// behavior and many internal Android usecases can be covered by this common pattern
@@ -144,7 +150,8 @@ class TimeFormatter {
/**
* Format the specified {@code wallTime} using {@code pattern}. The output is returned.
*/
- public String format(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
+ public String format(String pattern, ZoneInfoData.WallTime wallTime,
+ ZoneInfoData zoneInfoData) {
try {
StringBuilder stringBuilder = new StringBuilder();
@@ -153,7 +160,7 @@ class TimeFormatter {
// and locale sensitive strings are output directly using outputBuilder.
numberFormatter = new Formatter(stringBuilder, Locale.US);
- formatInternal(pattern, wallTime, zoneInfo);
+ formatInternal(pattern, wallTime, zoneInfoData);
String result = stringBuilder.toString();
// The localizeDigits() behavior is the source of a bug since some formats are defined
// as being in ASCII and not localized.
@@ -186,13 +193,14 @@ class TimeFormatter {
* Format the specified {@code wallTime} using {@code pattern}. The output is written to
* {@link #outputBuilder}.
*/
- private void formatInternal(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
+ private void formatInternal(String pattern, ZoneInfoData.WallTime wallTime,
+ ZoneInfoData zoneInfoData) {
CharBuffer formatBuffer = CharBuffer.wrap(pattern);
while (formatBuffer.remaining() > 0) {
boolean outputCurrentChar = true;
char currentChar = formatBuffer.get(formatBuffer.position());
if (currentChar == '%') {
- outputCurrentChar = handleToken(formatBuffer, wallTime, zoneInfo);
+ outputCurrentChar = handleToken(formatBuffer, wallTime, zoneInfoData);
}
if (outputCurrentChar) {
outputBuilder.append(formatBuffer.get(formatBuffer.position()));
@@ -201,8 +209,8 @@ class TimeFormatter {
}
}
- private boolean handleToken(CharBuffer formatBuffer, ZoneInfo.WallTime wallTime,
- ZoneInfo zoneInfo) {
+ private boolean handleToken(CharBuffer formatBuffer, ZoneInfoData.WallTime wallTime,
+ ZoneInfoData zoneInfoData) {
// The char at formatBuffer.position() is expected to be '%' at this point.
int modifier = 0;
@@ -247,10 +255,10 @@ class TimeFormatter {
outputYear(wallTime.getYear(), true, false, modifier);
return false;
case 'c':
- formatInternal(dateTimeFormat, wallTime, zoneInfo);
+ formatInternal(dateTimeFormat, wallTime, zoneInfoData);
return false;
case 'D':
- formatInternal("%m/%d/%y", wallTime, zoneInfo);
+ formatInternal("%m/%d/%y", wallTime, zoneInfoData);
return false;
case 'd':
numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
@@ -272,7 +280,7 @@ class TimeFormatter {
wallTime.getMonthDay());
return false;
case 'F':
- formatInternal("%Y-%m-%d", wallTime, zoneInfo);
+ formatInternal("%Y-%m-%d", wallTime, zoneInfoData);
return false;
case 'H':
numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
@@ -307,29 +315,31 @@ class TimeFormatter {
outputBuilder.append('\n');
return false;
case 'p':
- modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1]
- : localeData.amPm[0], modifier);
+ modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2))
+ ? dateFormatSymbols.getAmPmStrings()[1]
+ : dateFormatSymbols.getAmPmStrings()[0], modifier);
return false;
case 'P':
- modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1]
- : localeData.amPm[0], FORCE_LOWER_CASE);
+ modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2))
+ ? dateFormatSymbols.getAmPmStrings()[1]
+ : dateFormatSymbols.getAmPmStrings()[0], FORCE_LOWER_CASE);
return false;
case 'R':
- formatInternal("%H:%M", wallTime, zoneInfo);
+ formatInternal("%H:%M", wallTime, zoneInfoData);
return false;
case 'r':
- formatInternal("%I:%M:%S %p", wallTime, zoneInfo);
+ formatInternal("%I:%M:%S %p", wallTime, zoneInfoData);
return false;
case 'S':
numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
wallTime.getSecond());
return false;
case 's':
- int timeInSeconds = wallTime.mktime(zoneInfo);
+ int timeInSeconds = wallTime.mktime(zoneInfoData);
outputBuilder.append(Integer.toString(timeInSeconds));
return false;
case 'T':
- formatInternal("%H:%M:%S", wallTime, zoneInfo);
+ formatInternal("%H:%M:%S", wallTime, zoneInfoData);
return false;
case 't':
outputBuilder.append('\t');
@@ -383,7 +393,7 @@ class TimeFormatter {
return false;
}
case 'v':
- formatInternal("%e-%b-%Y", wallTime, zoneInfo);
+ formatInternal("%e-%b-%Y", wallTime, zoneInfoData);
return false;
case 'W':
int n = (wallTime.getYearDay() + DAYSPERWEEK - (
@@ -395,10 +405,10 @@ class TimeFormatter {
numberFormatter.format("%d", wallTime.getWeekDay());
return false;
case 'X':
- formatInternal(timeOnlyFormat, wallTime, zoneInfo);
+ formatInternal(timeOnlyFormat, wallTime, zoneInfoData);
return false;
case 'x':
- formatInternal(dateOnlyFormat, wallTime, zoneInfo);
+ formatInternal(dateOnlyFormat, wallTime, zoneInfoData);
return false;
case 'y':
outputYear(wallTime.getYear(), false, true, modifier);
@@ -411,7 +421,8 @@ class TimeFormatter {
return false;
}
boolean isDst = wallTime.getIsDst() != 0;
- modifyAndAppend(zoneInfo.getDisplayName(isDst, TimeZone.SHORT), modifier);
+ modifyAndAppend(TimeZone.getTimeZone(zoneInfoData.getID())
+ .getDisplayName(isDst, TimeZone.SHORT), modifier);
return false;
case 'z': {
if (wallTime.getIsDst() < 0) {
@@ -432,7 +443,7 @@ class TimeFormatter {
return false;
}
case '+':
- formatInternal("%a %b %e %H:%M:%S %Z %Y", wallTime, zoneInfo);
+ formatInternal("%a %b %e %H:%M:%S %Z %Y", wallTime, zoneInfoData);
return false;
case '%':
// If conversion char is undefined, behavior is undefined. Print out the
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index d40015ee17a8..2b038dd11348 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -29,8 +29,6 @@ import android.text.format.DateFormat;
import android.view.KeyEvent;
import android.view.View;
-import libcore.icu.LocaleData;
-
import java.util.Collection;
import java.util.Locale;
@@ -228,7 +226,7 @@ public abstract class NumberKeyListener extends BaseKeyListener
if (locale == null) {
return false;
}
- final String[] amPm = LocaleData.get(locale).amPm;
+ final String[] amPm = DateFormat.getIcuDateFormatSymbols(locale).getAmPmStrings();
for (int i = 0; i < amPm.length; i++) {
for (int j = 0; j < amPm[i].length(); j++) {
final char ch = amPm[i].charAt(j);
diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java
index 8fd303b8a64c..44d140242409 100644
--- a/core/java/android/timezone/CountryTimeZones.java
+++ b/core/java/android/timezone/CountryTimeZones.java
@@ -40,9 +40,9 @@ public final class CountryTimeZones {
public static final class TimeZoneMapping {
@NonNull
- private libcore.timezone.CountryTimeZones.TimeZoneMapping mDelegate;
+ private com.android.i18n.timezone.CountryTimeZones.TimeZoneMapping mDelegate;
- TimeZoneMapping(libcore.timezone.CountryTimeZones.TimeZoneMapping delegate) {
+ TimeZoneMapping(com.android.i18n.timezone.CountryTimeZones.TimeZoneMapping delegate) {
this.mDelegate = Objects.requireNonNull(delegate);
}
@@ -147,9 +147,9 @@ public final class CountryTimeZones {
}
@NonNull
- private final libcore.timezone.CountryTimeZones mDelegate;
+ private final com.android.i18n.timezone.CountryTimeZones mDelegate;
- CountryTimeZones(libcore.timezone.CountryTimeZones delegate) {
+ CountryTimeZones(com.android.i18n.timezone.CountryTimeZones delegate) {
mDelegate = delegate;
}
@@ -221,7 +221,7 @@ public final class CountryTimeZones {
@Nullable
public OffsetResult lookupByOffsetWithBias(long whenMillis, @Nullable TimeZone bias,
int totalOffsetMillis, boolean isDst) {
- libcore.timezone.CountryTimeZones.OffsetResult delegateOffsetResult =
+ com.android.i18n.timezone.CountryTimeZones.OffsetResult delegateOffsetResult =
mDelegate.lookupByOffsetWithBias(
whenMillis, bias, totalOffsetMillis, isDst);
return delegateOffsetResult == null ? null :
@@ -244,7 +244,7 @@ public final class CountryTimeZones {
@Nullable
public OffsetResult lookupByOffsetWithBias(long whenMillis, @Nullable TimeZone bias,
int totalOffsetMillis) {
- libcore.timezone.CountryTimeZones.OffsetResult delegateOffsetResult =
+ com.android.i18n.timezone.CountryTimeZones.OffsetResult delegateOffsetResult =
mDelegate.lookupByOffsetWithBias(whenMillis, bias, totalOffsetMillis);
return delegateOffsetResult == null ? null :
new OffsetResult(
@@ -260,11 +260,12 @@ public final class CountryTimeZones {
*/
@NonNull
public List<TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long whenMillis) {
- List<libcore.timezone.CountryTimeZones.TimeZoneMapping> delegateList =
+ List<com.android.i18n.timezone.CountryTimeZones.TimeZoneMapping> delegateList =
mDelegate.getEffectiveTimeZoneMappingsAt(whenMillis);
List<TimeZoneMapping> toReturn = new ArrayList<>(delegateList.size());
- for (libcore.timezone.CountryTimeZones.TimeZoneMapping delegateMapping : delegateList) {
+ for (com.android.i18n.timezone.CountryTimeZones.TimeZoneMapping delegateMapping
+ : delegateList) {
toReturn.add(new TimeZoneMapping(delegateMapping));
}
return Collections.unmodifiableList(toReturn);
diff --git a/core/java/android/timezone/TelephonyLookup.java b/core/java/android/timezone/TelephonyLookup.java
index a4c3fbd33410..c97bf28cebfe 100644
--- a/core/java/android/timezone/TelephonyLookup.java
+++ b/core/java/android/timezone/TelephonyLookup.java
@@ -41,16 +41,17 @@ public final class TelephonyLookup {
public static TelephonyLookup getInstance() {
synchronized (sLock) {
if (sInstance == null) {
- sInstance = new TelephonyLookup(libcore.timezone.TelephonyLookup.getInstance());
+ sInstance = new TelephonyLookup(com.android.i18n.timezone.TelephonyLookup
+ .getInstance());
}
return sInstance;
}
}
@NonNull
- private final libcore.timezone.TelephonyLookup mDelegate;
+ private final com.android.i18n.timezone.TelephonyLookup mDelegate;
- private TelephonyLookup(@NonNull libcore.timezone.TelephonyLookup delegate) {
+ private TelephonyLookup(@NonNull com.android.i18n.timezone.TelephonyLookup delegate) {
mDelegate = Objects.requireNonNull(delegate);
}
@@ -60,7 +61,7 @@ public final class TelephonyLookup {
*/
@Nullable
public TelephonyNetworkFinder getTelephonyNetworkFinder() {
- libcore.timezone.TelephonyNetworkFinder telephonyNetworkFinderDelegate =
+ com.android.i18n.timezone.TelephonyNetworkFinder telephonyNetworkFinderDelegate =
mDelegate.getTelephonyNetworkFinder();
return telephonyNetworkFinderDelegate != null
? new TelephonyNetworkFinder(telephonyNetworkFinderDelegate) : null;
diff --git a/core/java/android/timezone/TelephonyNetwork.java b/core/java/android/timezone/TelephonyNetwork.java
index 823cd251fbf0..3b65c6ffc379 100644
--- a/core/java/android/timezone/TelephonyNetwork.java
+++ b/core/java/android/timezone/TelephonyNetwork.java
@@ -28,9 +28,9 @@ import java.util.Objects;
public final class TelephonyNetwork {
@NonNull
- private final libcore.timezone.TelephonyNetwork mDelegate;
+ private final com.android.i18n.timezone.TelephonyNetwork mDelegate;
- TelephonyNetwork(@NonNull libcore.timezone.TelephonyNetwork delegate) {
+ TelephonyNetwork(@NonNull com.android.i18n.timezone.TelephonyNetwork delegate) {
mDelegate = Objects.requireNonNull(delegate);
}
diff --git a/core/java/android/timezone/TelephonyNetworkFinder.java b/core/java/android/timezone/TelephonyNetworkFinder.java
index 4bfeff8a73ad..c69ddf86d3f8 100644
--- a/core/java/android/timezone/TelephonyNetworkFinder.java
+++ b/core/java/android/timezone/TelephonyNetworkFinder.java
@@ -29,9 +29,9 @@ import java.util.Objects;
public final class TelephonyNetworkFinder {
@NonNull
- private final libcore.timezone.TelephonyNetworkFinder mDelegate;
+ private final com.android.i18n.timezone.TelephonyNetworkFinder mDelegate;
- TelephonyNetworkFinder(libcore.timezone.TelephonyNetworkFinder delegate) {
+ TelephonyNetworkFinder(com.android.i18n.timezone.TelephonyNetworkFinder delegate) {
mDelegate = Objects.requireNonNull(delegate);
}
@@ -45,7 +45,7 @@ public final class TelephonyNetworkFinder {
Objects.requireNonNull(mcc);
Objects.requireNonNull(mnc);
- libcore.timezone.TelephonyNetwork telephonyNetworkDelegate =
+ com.android.i18n.timezone.TelephonyNetwork telephonyNetworkDelegate =
mDelegate.findNetworkByMccMnc(mcc, mnc);
return telephonyNetworkDelegate != null
? new TelephonyNetwork(telephonyNetworkDelegate) : null;
diff --git a/core/java/android/timezone/TimeZoneFinder.java b/core/java/android/timezone/TimeZoneFinder.java
index 03f5013f230c..bf4275fb5b56 100644
--- a/core/java/android/timezone/TimeZoneFinder.java
+++ b/core/java/android/timezone/TimeZoneFinder.java
@@ -41,16 +41,17 @@ public final class TimeZoneFinder {
public static TimeZoneFinder getInstance() {
synchronized (sLock) {
if (sInstance == null) {
- sInstance = new TimeZoneFinder(libcore.timezone.TimeZoneFinder.getInstance());
+ sInstance = new TimeZoneFinder(com.android.i18n.timezone.TimeZoneFinder
+ .getInstance());
}
}
return sInstance;
}
@NonNull
- private final libcore.timezone.TimeZoneFinder mDelegate;
+ private final com.android.i18n.timezone.TimeZoneFinder mDelegate;
- private TimeZoneFinder(@NonNull libcore.timezone.TimeZoneFinder delegate) {
+ private TimeZoneFinder(@NonNull com.android.i18n.timezone.TimeZoneFinder delegate) {
mDelegate = Objects.requireNonNull(delegate);
}
@@ -70,7 +71,8 @@ public final class TimeZoneFinder {
*/
@Nullable
public CountryTimeZones lookupCountryTimeZones(@NonNull String countryIso) {
- libcore.timezone.CountryTimeZones delegate = mDelegate.lookupCountryTimeZones(countryIso);
+ com.android.i18n.timezone.CountryTimeZones delegate = mDelegate
+ .lookupCountryTimeZones(countryIso);
return delegate == null ? null : new CountryTimeZones(delegate);
}
}
diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java
index f993012aeb1c..e1fb932b977d 100644
--- a/core/java/android/timezone/TzDataSetVersion.java
+++ b/core/java/android/timezone/TzDataSetVersion.java
@@ -50,14 +50,14 @@ public final class TzDataSetVersion {
* Returns the major tz data format version supported by this device.
*/
public static int currentFormatMajorVersion() {
- return libcore.timezone.TzDataSetVersion.currentFormatMajorVersion();
+ return com.android.i18n.timezone.TzDataSetVersion.currentFormatMajorVersion();
}
/**
* Returns the minor tz data format version supported by this device.
*/
public static int currentFormatMinorVersion() {
- return libcore.timezone.TzDataSetVersion.currentFormatMinorVersion();
+ return com.android.i18n.timezone.TzDataSetVersion.currentFormatMinorVersion();
}
/**
@@ -65,7 +65,7 @@ public final class TzDataSetVersion {
* with the current system image, and set of active modules.
*/
public static boolean isCompatibleWithThisDevice(TzDataSetVersion tzDataSetVersion) {
- return libcore.timezone.TzDataSetVersion.isCompatibleWithThisDevice(
+ return com.android.i18n.timezone.TzDataSetVersion.isCompatibleWithThisDevice(
tzDataSetVersion.mDelegate);
}
@@ -76,8 +76,8 @@ public final class TzDataSetVersion {
public static TzDataSetVersion read() throws IOException, TzDataSetException {
try {
return new TzDataSetVersion(
- libcore.timezone.TzDataSetVersion.readTimeZoneModuleVersion());
- } catch (libcore.timezone.TzDataSetVersion.TzDataSetException e) {
+ com.android.i18n.timezone.TzDataSetVersion.readTimeZoneModuleVersion());
+ } catch (com.android.i18n.timezone.TzDataSetVersion.TzDataSetException e) {
throw new TzDataSetException(e.getMessage(), e);
}
}
@@ -100,9 +100,9 @@ public final class TzDataSetVersion {
}
@NonNull
- private final libcore.timezone.TzDataSetVersion mDelegate;
+ private final com.android.i18n.timezone.TzDataSetVersion mDelegate;
- private TzDataSetVersion(@NonNull libcore.timezone.TzDataSetVersion delegate) {
+ private TzDataSetVersion(@NonNull com.android.i18n.timezone.TzDataSetVersion delegate) {
mDelegate = Objects.requireNonNull(delegate);
}
diff --git a/core/java/android/timezone/ZoneInfoDb.java b/core/java/android/timezone/ZoneInfoDb.java
index 9354a695812d..65d6eaddf824 100644
--- a/core/java/android/timezone/ZoneInfoDb.java
+++ b/core/java/android/timezone/ZoneInfoDb.java
@@ -41,16 +41,16 @@ public final class ZoneInfoDb {
public static ZoneInfoDb getInstance() {
synchronized (sLock) {
if (sInstance == null) {
- sInstance = new ZoneInfoDb(libcore.timezone.ZoneInfoDb.getInstance());
+ sInstance = new ZoneInfoDb(com.android.i18n.timezone.ZoneInfoDb.getInstance());
}
}
return sInstance;
}
@NonNull
- private final libcore.timezone.ZoneInfoDb mDelegate;
+ private final com.android.i18n.timezone.ZoneInfoDb mDelegate;
- private ZoneInfoDb(libcore.timezone.ZoneInfoDb delegate) {
+ private ZoneInfoDb(com.android.i18n.timezone.ZoneInfoDb delegate) {
mDelegate = Objects.requireNonNull(delegate);
}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 6e41fc8017c1..384040013a6d 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -23,10 +23,10 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.SystemClock;
-import libcore.timezone.CountryTimeZones;
-import libcore.timezone.CountryTimeZones.TimeZoneMapping;
-import libcore.timezone.TimeZoneFinder;
-import libcore.timezone.ZoneInfoDb;
+import com.android.i18n.timezone.CountryTimeZones;
+import com.android.i18n.timezone.CountryTimeZones.TimeZoneMapping;
+import com.android.i18n.timezone.TimeZoneFinder;
+import com.android.i18n.timezone.ZoneInfoDb;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 096e6ea52c8a..fd89b2e09131 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -34,8 +34,6 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.DatePicker.AbstractDatePickerDelegate;
import android.widget.NumberPicker.OnValueChangeListener;
-import libcore.icu.ICU;
-
import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -459,7 +457,7 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
// We use numeric spinners for year and day, but textual months. Ask icu4c what
// order the user's locale uses for that combination. http://b/7207103.
String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), "yyyyMMMdd");
- char[] order = ICU.getDateFormatOrder(pattern);
+ char[] order = DateFormat.getDateFormatOrder(pattern);
final int spinnerCount = order.length;
for (int i = 0; i < spinnerCount; i++) {
switch (order[i]) {
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index d0f80936f477..da2039560306 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -105,16 +105,43 @@ public final class SelectionActionModeHelper {
}
/**
+ * Swap the selection index if the start index is greater than end index.
+ *
+ * @return the swap result, index 0 is the start index and index 1 is the end index.
+ */
+ private static int[] sortSelectionIndices(int selectionStart, int selectionEnd) {
+ if (selectionStart < selectionEnd) {
+ return new int[]{selectionStart, selectionEnd};
+ }
+ return new int[]{selectionEnd, selectionStart};
+ }
+
+ /**
+ * The {@link TextView} selection start and end index may not be sorted, this method will swap
+ * the {@link TextView} selection index if the start index is greater than end index.
+ *
+ * @param textView the selected TextView.
+ * @return the swap result, index 0 is the start index and index 1 is the end index.
+ */
+ private static int[] sortSelectionIndicesFromTextView(TextView textView) {
+ int selectionStart = textView.getSelectionStart();
+ int selectionEnd = textView.getSelectionEnd();
+
+ return sortSelectionIndices(selectionStart, selectionEnd);
+ }
+
+ /**
* Starts Selection ActionMode.
*/
public void startSelectionActionModeAsync(boolean adjustSelection) {
// Check if the smart selection should run for editable text.
adjustSelection &= getTextClassificationSettings().isSmartSelectionEnabled();
+ int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
mSelectionTracker.onOriginalSelection(
getText(mTextView),
- mTextView.getSelectionStart(),
- mTextView.getSelectionEnd(),
+ sortedSelectionIndices[0],
+ sortedSelectionIndices[1],
false /*isLink*/);
cancelAsyncTask();
if (skipTextClassification()) {
@@ -139,12 +166,14 @@ public final class SelectionActionModeHelper {
* Starts Link ActionMode.
*/
public void startLinkActionModeAsync(int start, int end) {
- mSelectionTracker.onOriginalSelection(getText(mTextView), start, end, true /*isLink*/);
+ int[] indexResult = sortSelectionIndices(start, end);
+ mSelectionTracker.onOriginalSelection(getText(mTextView), indexResult[0], indexResult[1],
+ true /*isLink*/);
cancelAsyncTask();
if (skipTextClassification()) {
startLinkActionMode(null);
} else {
- resetTextClassificationHelper(start, end);
+ resetTextClassificationHelper(indexResult[0], indexResult[1]);
mTextClassificationAsyncTask = new TextClassificationAsyncTask(
mTextView,
mTextClassificationHelper.getTimeoutDuration(),
@@ -173,19 +202,23 @@ public final class SelectionActionModeHelper {
/** Reports a selection action event. */
public void onSelectionAction(int menuItemId, @Nullable String actionLabel) {
+ int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
mSelectionTracker.onSelectionAction(
- mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
+ sortedSelectionIndices[0], sortedSelectionIndices[1],
getActionType(menuItemId), actionLabel, mTextClassification);
}
public void onSelectionDrag() {
+ int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
mSelectionTracker.onSelectionAction(
- mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
+ sortedSelectionIndices[0], sortedSelectionIndices[1],
SelectionEvent.ACTION_DRAG, /* actionLabel= */ null, mTextClassification);
}
public void onTextChanged(int start, int end) {
- mSelectionTracker.onTextChanged(start, end, mTextClassification);
+ int[] sortedSelectionIndices = sortSelectionIndices(start, end);
+ mSelectionTracker.onTextChanged(sortedSelectionIndices[0], sortedSelectionIndices[1],
+ mTextClassification);
}
public boolean resetSelection(int textIndex) {
@@ -302,9 +335,10 @@ public final class SelectionActionModeHelper {
startSelectionActionMode(startSelectionResult);
};
// TODO do not trigger the animation if the change included only non-printable characters
+ int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
final boolean didSelectionChange =
- result != null && (mTextView.getSelectionStart() != result.mStart
- || mTextView.getSelectionEnd() != result.mEnd);
+ result != null && (sortedSelectionIndices[0] != result.mStart
+ || sortedSelectionIndices[1] != result.mEnd);
if (!didSelectionChange) {
onAnimationEndCallback.run();
@@ -454,16 +488,18 @@ public final class SelectionActionModeHelper {
if (actionMode != null) {
actionMode.invalidate();
}
+ final int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
mSelectionTracker.onSelectionUpdated(
- mTextView.getSelectionStart(), mTextView.getSelectionEnd(), mTextClassification);
+ sortedSelectionIndices[0], sortedSelectionIndices[1], mTextClassification);
mTextClassificationAsyncTask = null;
}
private void resetTextClassificationHelper(int selectionStart, int selectionEnd) {
if (selectionStart < 0 || selectionEnd < 0) {
// Use selection indices
- selectionStart = mTextView.getSelectionStart();
- selectionEnd = mTextView.getSelectionEnd();
+ int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
+ selectionStart = sortedSelectionIndices[0];
+ selectionEnd = sortedSelectionIndices[1];
}
mTextClassificationHelper.init(
mTextView::getTextClassifier,
@@ -603,10 +639,11 @@ public final class SelectionActionModeHelper {
mAllowReset = false;
boolean selected = editor.selectCurrentWord();
if (selected) {
- mSelectionStart = editor.getTextView().getSelectionStart();
- mSelectionEnd = editor.getTextView().getSelectionEnd();
+ final int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(textView);
+ mSelectionStart = sortedSelectionIndices[0];
+ mSelectionEnd = sortedSelectionIndices[1];
mLogger.logSelectionAction(
- textView.getSelectionStart(), textView.getSelectionEnd(),
+ sortedSelectionIndices[0], sortedSelectionIndices[1],
SelectionEvent.ACTION_RESET,
/* actionLabel= */ null, /* classification= */ null);
}
@@ -1179,8 +1216,9 @@ public final class SelectionActionModeHelper {
SelectionResult(int start, int end,
@Nullable TextClassification classification, @Nullable TextSelection selection) {
- mStart = start;
- mEnd = end;
+ int[] sortedIndices = sortSelectionIndices(start, end);
+ mStart = sortedIndices[0];
+ mEnd = sortedIndices[1];
mClassification = classification;
mSelection = selection;
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 51b18473f1ac..1c219eb95479 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -24,9 +24,11 @@ import android.annotation.Widget;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
+import android.icu.text.DateFormatSymbols;
import android.icu.util.Calendar;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
@@ -39,8 +41,6 @@ import android.view.inspector.InspectableProperty;
import com.android.internal.R;
-import libcore.icu.LocaleData;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
@@ -421,11 +421,13 @@ public class TimePicker extends FrameLayout {
static String[] getAmPmStrings(Context context) {
final Locale locale = context.getResources().getConfiguration().locale;
- final LocaleData d = LocaleData.get(locale);
+ DateFormatSymbols dfs = DateFormat.getIcuDateFormatSymbols(locale);
+ String[] amPm = dfs.getAmPmStrings();
+ String[] narrowAmPm = dfs.getAmpmNarrowStrings();
final String[] result = new String[2];
- result[0] = d.amPm[0].length() > 4 ? d.narrowAm : d.amPm[0];
- result[1] = d.amPm[1].length() > 4 ? d.narrowPm : d.amPm[1];
+ result[0] = amPm[0].length() > 4 ? narrowAmPm[0] : amPm[0];
+ result[1] = amPm[1].length() > 4 ? narrowAmPm[1] : amPm[1];
return result;
}
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 83c86d5ce36b..bd2fa5965bc9 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -35,8 +35,6 @@ import android.view.inputmethod.InputMethodManager;
import com.android.internal.R;
-import libcore.icu.LocaleData;
-
import java.util.Calendar;
/**
@@ -143,7 +141,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
// Get the localized am/pm strings and use them in the spinner.
- mAmPmStrings = getAmPmStrings(context);
+ mAmPmStrings = TimePicker.getAmPmStrings(context);
// am/pm
final View amPmView = mDelegator.findViewById(R.id.amPm);
@@ -574,12 +572,4 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
target.setContentDescription(mContext.getString(contDescResId));
}
}
-
- public static String[] getAmPmStrings(Context context) {
- String[] result = new String[2];
- LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
- result[0] = d.amPm[0].length() > 4 ? d.narrowAm : d.amPm[0];
- result[1] = d.amPm[1].length() > 4 ? d.narrowPm : d.amPm[1];
- return result;
- }
}
diff --git a/core/java/com/android/internal/logging/AndroidHandler.java b/core/java/com/android/internal/logging/AndroidHandler.java
index f55a31fcc986..119f3662a94f 100644
--- a/core/java/com/android/internal/logging/AndroidHandler.java
+++ b/core/java/com/android/internal/logging/AndroidHandler.java
@@ -17,9 +17,8 @@
package com.android.internal.logging;
import android.util.Log;
+
import com.android.internal.util.FastPrintWriter;
-import dalvik.system.DalvikLogging;
-import dalvik.system.DalvikLogHandler;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -82,7 +81,7 @@ import java.util.logging.Logger;
* </tr>
* </table>
*/
-public class AndroidHandler extends Handler implements DalvikLogHandler {
+public class AndroidHandler extends Handler {
/**
* Holds the formatter for all Android log handlers.
*/
@@ -121,10 +120,32 @@ public class AndroidHandler extends Handler implements DalvikLogHandler {
// No need to flush, but must implement abstract method.
}
+ /**
+ * Returns the short logger tag (up to 23 chars) for the given logger name.
+ * Traditionally loggers are named by fully-qualified Java classes; this
+ * method attempts to return a concise identifying part of such names.
+ */
+ private static String loggerNameToTag(String loggerName) {
+ // Anonymous logger.
+ if (loggerName == null) {
+ return "null";
+ }
+
+ int length = loggerName.length();
+ if (length <= 23) {
+ return loggerName;
+ }
+
+ int lastPeriod = loggerName.lastIndexOf(".");
+ return length - (lastPeriod + 1) <= 23
+ ? loggerName.substring(lastPeriod + 1)
+ : loggerName.substring(loggerName.length() - 23);
+ }
+
@Override
public void publish(LogRecord record) {
int level = getAndroidLevel(record.getLevel());
- String tag = DalvikLogging.loggerNameToTag(record.getLoggerName());
+ String tag = loggerNameToTag(record.getLoggerName());
if (!Log.isLoggable(tag, level)) {
return;
}
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 8ea5aa815a1c..b4727499d8ef 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -21,6 +21,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.net.Ikev2VpnProfile;
import android.net.PlatformVpnProfile;
import android.net.ProxyInfo;
+import android.net.Uri;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -287,7 +288,7 @@ public final class VpnProfile implements Cloneable, Parcelable {
profile.proxy = new ProxyInfo(host, port.isEmpty() ?
0 : Integer.parseInt(port), exclList);
} else if (!pacFileUrl.isEmpty()) {
- profile.proxy = new ProxyInfo(pacFileUrl);
+ profile.proxy = new ProxyInfo(Uri.parse(pacFileUrl));
}
} // else profile.proxy = null
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index cffb0ad9fdb9..3d35d2fbaa82 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -153,19 +153,32 @@ public class KernelWakelockReader {
}
/**
+ * Attempt to wait for suspend_control service if not immediately available.
+ */
+ private ISuspendControlService waitForSuspendControlService() throws ServiceNotFoundException {
+ final String name = "suspend_control";
+ final int numRetries = 5;
+ for (int i = 0; i < numRetries; i++) {
+ mSuspendControlService = ISuspendControlService.Stub.asInterface(
+ ServiceManager.getService(name));
+ if (mSuspendControlService != null) {
+ return mSuspendControlService;
+ }
+ }
+ throw new ServiceNotFoundException(name);
+ }
+
+ /**
* On success, returns the updated stats from SystemSupend, else returns null.
*/
private KernelWakelockStats getWakelockStatsFromSystemSuspend(
final KernelWakelockStats staleStats) {
WakeLockInfo[] wlStats = null;
- if (mSuspendControlService == null) {
- try {
- mSuspendControlService = ISuspendControlService.Stub.asInterface(
- ServiceManager.getServiceOrThrow("suspend_control"));
- } catch (ServiceNotFoundException e) {
- Slog.wtf(TAG, "Required service suspend_control not available", e);
- return null;
- }
+ try {
+ mSuspendControlService = waitForSuspendControlService();
+ } catch (ServiceNotFoundException e) {
+ Slog.wtf(TAG, "Required service suspend_control not available", e);
+ return null;
}
try {
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index f3c3ac1b94e5..2a29dfb71e6c 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -24,6 +24,7 @@ import android.content.pm.ApplicationInfo;
import android.net.Credentials;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
+import android.net.NetworkUtils;
import android.os.FactoryTest;
import android.os.IVold;
import android.os.Process;
@@ -239,6 +240,13 @@ public final class Zygote {
private Zygote() {}
+ private static boolean containsInetGid(int[] gids) {
+ for (int i = 0; i < gids.length; i++) {
+ if (gids[i] == android.os.Process.INET_GID) return true;
+ }
+ return false;
+ }
+
/**
* Forks a new VM instance. The current VM must have been started
* with the -Xzygote flag. <b>NOTE: new instance keeps all
@@ -286,6 +294,11 @@ public final class Zygote {
if (pid == 0) {
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
+
+ // If no GIDs were specified, don't make any permissions changes based on groups.
+ if (gids != null && gids.length > 0) {
+ NetworkUtils.setAllowNetworkingForProcess(containsInetGid(gids));
+ }
}
// Set the Java Language thread priority to the default value for new apps.
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 0c2406559dcc..7a79cc9ef868 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -2088,10 +2088,11 @@ public class StateMachine {
pw.println(getName() + ":");
pw.println(" total records=" + getLogRecCount());
for (int i = 0; i < getLogRecSize(); i++) {
- pw.println(" rec[" + i + "]: " + getLogRec(i).toString());
+ pw.println(" rec[" + i + "]: " + getLogRec(i));
pw.flush();
}
- pw.println("curState=" + getCurrentState().getName());
+ final IState curState = getCurrentState();
+ pw.println("curState=" + (curState == null ? "<QUIT>" : curState.getName()));
}
@Override
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 37365111b0c5..bcb0460ace0f 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -371,7 +371,7 @@ public class PointerLocationView extends View implements InputDeviceListener,
}
if (haveLast) {
canvas.drawLine(lastX, lastY, x, y, mPathPaint);
- final Paint paint = ps.mTraceCurrent[i] ? mCurrentPointPaint : mPaint;
+ final Paint paint = ps.mTraceCurrent[i - 1] ? mCurrentPointPaint : mPaint;
canvas.drawPoint(lastX, lastY, paint);
drawn = true;
}
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index f040f11ffac4..8cc1b8161de9 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -22,7 +22,7 @@
#include "core_jni_helpers.h"
#include <HardwareBitmapUploader.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <androidfw/Asset.h>
#include <androidfw/ResourceTypes.h>
#include <cutils/compiler.h>
diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
index fc88193a8502..002f36cf586d 100644
--- a/core/jni/android_app_ActivityThread.cpp
+++ b/core/jni/android_app_ActivityThread.cpp
@@ -15,8 +15,9 @@
*/
#include "jni.h"
+
#include "GraphicsJNI.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <minikin/Layout.h>
#include <renderthread/RenderProxy.h>
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index aa8acc16bc3f..79fa2a28666c 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "FileBackupHelper_native"
#include <utils/Log.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <androidfw/BackupHelpers.h>
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index 4f5d1f80dffc..324b3e71b8cc 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "FileBackupHelper_native"
#include <utils/Log.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "core_jni_helpers.h"
#include <androidfw/BackupHelpers.h>
diff --git a/core/jni/android_backup_BackupHelperDispatcher.cpp b/core/jni/android_backup_BackupHelperDispatcher.cpp
index fac7eba4c0a2..efe7d0b6ad0a 100644
--- a/core/jni/android_backup_BackupHelperDispatcher.cpp
+++ b/core/jni/android_backup_BackupHelperDispatcher.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "BackupHelperDispatcher_native"
#include <utils/Log.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <sys/types.h>
diff --git a/core/jni/android_backup_FileBackupHelperBase.cpp b/core/jni/android_backup_FileBackupHelperBase.cpp
index 65840ee2c016..5f84fafa383e 100644
--- a/core/jni/android_backup_FileBackupHelperBase.cpp
+++ b/core/jni/android_backup_FileBackupHelperBase.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "FileBackupHelper_native"
#include <utils/Log.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "core_jni_helpers.h"
#include <androidfw/BackupHelpers.h>
diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp
index 3ff24468e3aa..d06107e2e0b2 100644
--- a/core/jni/android_hardware_SerialPort.cpp
+++ b/core/jni/android_hardware_SerialPort.cpp
@@ -19,7 +19,7 @@
#include "utils/Log.h"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "core_jni_helpers.h"
#include <stdio.h>
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index b885c285e380..845d65c67719 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -19,7 +19,7 @@
#include "utils/Log.h"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "core_jni_helpers.h"
#include <usbhost/usbhost.h>
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index 1163b860977d..42cf1f479122 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "LocalSocketImpl"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "jni.h"
#include "utils/Log.h"
#include "utils/misc.h"
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 03b9793ccba8..e56809f66dc7 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -30,7 +30,7 @@
#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
#include <android_runtime/AndroidRuntime.h>
#include <cutils/properties.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <utils/Log.h>
#include <utils/misc.h>
@@ -226,6 +226,11 @@ static jobject android_net_utils_getDnsNetwork(JNIEnv *env, jobject thiz) {
class_Network, ctor, dnsNetId & ~NETID_USE_LOCAL_NAMESERVERS, privateDnsBypass);
}
+static void android_net_utils_setAllowNetworkingForProcess(JNIEnv *env, jobject thiz,
+ jboolean hasConnectivity) {
+ setAllowNetworkingForProcess(hasConnectivity == JNI_TRUE);
+}
+
static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
if (javaFd == NULL) {
jniThrowNullPointerException(env, NULL);
@@ -266,6 +271,7 @@ static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, j
/*
* JNI registration.
*/
+// clang-format off
static const JNINativeMethod gNetworkUtilMethods[] = {
/* name, signature, funcPtr */
{ "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
@@ -282,7 +288,9 @@ static const JNINativeMethod gNetworkUtilMethods[] = {
{ "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
{ "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
{ "getDnsNetwork", "()Landroid/net/Network;", (void*) android_net_utils_getDnsNetwork },
+ { "setAllowNetworkingForProcess", "(Z)V", (void *)android_net_utils_setAllowNetworkingForProcess },
};
+// clang-format on
int register_android_net_NetworkUtils(JNIEnv* env)
{
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index de5e3a52a0c1..2f29cae42d07 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -20,7 +20,7 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/core/jni/android_opengl_EGL15.cpp b/core/jni/android_opengl_EGL15.cpp
index 4aeed8765165..b9c36b9ed9aa 100644
--- a/core/jni/android_opengl_EGL15.cpp
+++ b/core/jni/android_opengl_EGL15.cpp
@@ -20,7 +20,7 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index fef8116dc93a..1758807304bf 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -20,7 +20,7 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index 3d9a3b6687b1..e4d138d92621 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -24,7 +24,7 @@
#include <GLES/glext.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index 6d7f41e5b3b2..3638b87e201f 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -24,7 +24,7 @@
#include <GLES/glext.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 39ef41a0e19e..1069a1d3acb1 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -24,7 +24,7 @@
#include <GLES/glext.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 1144d5bfb4e6..86d7ecdce44d 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -24,7 +24,7 @@
#include <GLES/glext.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index 2add72d14c7b..49baa51f2342 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -24,7 +24,7 @@
#include <GLES2/gl2ext.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index a9c021951758..32a2a24c2d2d 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -24,7 +24,7 @@
#include <GLES3/gl3ext.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 456da93784d5..afe7c63b6d47 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -22,7 +22,7 @@
#include <stdint.h>
#include <GLES3/gl31.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp
index dcaf4a58cd53..81274331ffa4 100644
--- a/core/jni/android_opengl_GLES31Ext.cpp
+++ b/core/jni/android_opengl_GLES31Ext.cpp
@@ -23,7 +23,7 @@
#include <GLES2/gl2ext.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/core/jni/android_opengl_GLES32.cpp b/core/jni/android_opengl_GLES32.cpp
index 6bdc711d64a2..07a794d0ef19 100644
--- a/core/jni/android_opengl_GLES32.cpp
+++ b/core/jni/android_opengl_GLES32.cpp
@@ -22,7 +22,7 @@
#include <stdint.h>
#include <GLES3/gl32.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
#include <assert.h>
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 8f9f8d211596..cd3611546852 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -40,7 +40,7 @@
#include <utils/misc.h>
#include <utils/String8.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include "jni.h"
#include <dmabufinfo/dmabufinfo.h>
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index b6427c9aa01c..48f33a6a3d77 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -339,6 +339,10 @@ static jobject JHwBinder_native_getService(
return JHwRemoteBinder::NewObject(env, service);
}
+void JHwBinder_native_setTrebleTestingOverride(JNIEnv*, jclass, jboolean testingOverride) {
+ hardware::details::setTrebleTestingOverride(testingOverride);
+}
+
void JHwBinder_native_configureRpcThreadpool(JNIEnv *, jclass,
jlong maxThreads, jboolean callerWillJoin) {
CHECK(maxThreads > 0);
@@ -368,6 +372,9 @@ static JNINativeMethod gMethods[] = {
{ "getService", "(Ljava/lang/String;Ljava/lang/String;Z)L" PACKAGE_PATH "/IHwBinder;",
(void *)JHwBinder_native_getService },
+ { "setTrebleTestingOverride", "(Z)V",
+ (void *)JHwBinder_native_setTrebleTestingOverride },
+
{ "configureRpcThreadpool", "(JZ)V",
(void *)JHwBinder_native_configureRpcThreadpool },
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index a88f8919ed08..ff336ee64b54 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -122,10 +122,18 @@ void signalExceptionForError(JNIEnv *env, status_t err, bool canThrowRemoteExcep
std::stringstream ss;
ss << "HwBinder Error: (" << err << ")";
- jniThrowException(
- env,
- canThrowRemoteException ? "android/os/RemoteException" : "java/lang/RuntimeException",
- ss.str().c_str());
+ const char* exception = nullptr;
+ if (canThrowRemoteException) {
+ if (err == DEAD_OBJECT) {
+ exception = "android/os/DeadObjectException";
+ } else {
+ exception = "android/os/RemoteException";
+ }
+ } else {
+ exception = "java/lang/RuntimeException";
+ }
+
+ jniThrowException(env, exception, ss.str().c_str());
break;
}
diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp
index b21566bbc186..8d91e635454c 100644
--- a/core/jni/android_os_MemoryFile.cpp
+++ b/core/jni/android_os_MemoryFile.cpp
@@ -19,7 +19,7 @@
#include <cutils/ashmem.h>
#include "core_jni_helpers.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <unistd.h>
#include <sys/mman.h>
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index eb8d26e7bf71..7247ee068334 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -20,7 +20,7 @@
#include "android_os_Parcel.h"
#include "android_util_Binder.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <fcntl.h>
#include <stdio.h>
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 7634547ae0bf..b772dfd1eb14 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -21,7 +21,7 @@
#include <utils/Log.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "jni.h"
#include "core_jni_helpers.h"
#include "selinux/selinux.h"
diff --git a/core/jni/android_os_SharedMemory.cpp b/core/jni/android_os_SharedMemory.cpp
index a812c35036f3..dc86187d8fea 100644
--- a/core/jni/android_os_SharedMemory.cpp
+++ b/core/jni/android_os_SharedMemory.cpp
@@ -22,7 +22,7 @@
#include <utils/Log.h>
#include <nativehelper/jni_macros.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <algorithm>
diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp
index 58295af50135..afad08a87d37 100644
--- a/core/jni/android_server_NetworkManagementSocketTagger.cpp
+++ b/core/jni/android_server_NetworkManagementSocketTagger.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "NMST_QTagUidNative"
#include <utils/Log.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "jni.h"
#include <utils/misc.h>
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 9342088cef3f..6fd9c7ef9bdc 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -48,7 +48,7 @@
#include "core_jni_helpers.h"
#include "jni.h"
-#include "nativehelper/JNIHelp.h"
+#include "nativehelper/JNIPlatformHelp.h"
#include "nativehelper/ScopedPrimitiveArray.h"
#include "nativehelper/ScopedStringChars.h"
#include "nativehelper/ScopedUtfChars.h"
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 18be3741e805..fbb35e055e16 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -95,6 +95,19 @@
#include "nativebridge/native_bridge.h"
+/* Functions in the callchain during the fork shall not be protected with
+ Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#define NO_PAC_FUNC __attribute__((target("branch-protection=bti")))
+#else
+#define NO_PAC_FUNC __attribute__((target("branch-protection=none")))
+#endif /* __ARM_FEATURE_BTI_DEFAULT */
+#else /* !__ARM_FEATURE_PAC_DEFAULT */
+#define NO_PAC_FUNC
+#endif /* __ARM_FEATURE_PAC_DEFAULT */
+
+
namespace {
// TODO (chriswailes): Add a function to initialize native Zygote data.
@@ -985,7 +998,23 @@ static void ClearUsapTable() {
gUsapPoolCount = 0;
}
+NO_PAC_FUNC
+static void PAuthKeyChange(JNIEnv* env) {
+#ifdef __aarch64__
+ unsigned long int hwcaps = getauxval(AT_HWCAP);
+ if (hwcaps & HWCAP_PACA) {
+ const unsigned long key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
+ PR_PAC_APDAKEY | PR_PAC_APDBKEY | PR_PAC_APGAKEY;
+ if (prctl(PR_PAC_RESET_KEYS, key_mask, 0, 0, 0) != 0) {
+ ALOGE("Failed to change the PAC keys: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "PAC key change failed.");
+ }
+ }
+#endif
+}
+
// Utility routine to fork a process from the zygote.
+NO_PAC_FUNC
static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
const std::vector<int>& fds_to_ignore,
@@ -1036,6 +1065,7 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
}
// The child process.
+ PAuthKeyChange(env);
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
@@ -1486,6 +1516,7 @@ static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jcl
PreApplicationInit();
}
+NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits,
@@ -1533,6 +1564,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
return pid;
}
+NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
@@ -1600,6 +1632,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
* @param is_priority_fork Controls the nice level assigned to the newly created process
* @return
*/
+NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env,
jclass,
jint read_pipe_fd,
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index 6b893cb94444..ffc1ddc03355 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -21,7 +21,7 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
diff --git a/core/jni/core_jni_helpers.h b/core/jni/core_jni_helpers.h
index f03f42737134..41ccd56925aa 100644
--- a/core/jni/core_jni_helpers.h
+++ b/core/jni/core_jni_helpers.h
@@ -17,7 +17,7 @@
#ifndef CORE_JNI_HELPERS
#define CORE_JNI_HELPERS
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/scoped_local_ref.h>
#include <nativehelper/scoped_utf_chars.h>
#include <android_runtime/AndroidRuntime.h>
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 59797f7f4bf6..51266de83355 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2422,6 +2422,11 @@ enum PageId {
// OS: Q
SETTINGS_GESTURE_TAP = 1751;
+ // OPEN: Settings > Security & screen lock -> Encryption & credentials > Install a certificate
+ // CATEGORY: SETTINGS
+ // OS: R
+ INSTALL_CERTIFICATE_FROM_STORAGE = 1803;
+
// OPEN: Settings > Developer Options > Platform Compat
// CATEGORY: SETTINGS
// OS: R
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cc988ff94926..85a224206346 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -228,6 +228,8 @@
<protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED" />
<protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY" />
<protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED" />
<protected-broadcast
android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
<protected-broadcast
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ad1f1f005baa..3d73ade33d5b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3064,6 +3064,11 @@
empty string is passed in -->
<string name="config_wlan_data_service_package" translatable="false"></string>
+ <!-- Boolean indicating whether the Iwlan data service supports persistence of iwlan ipsec
+ tunnels across service restart. If iwlan tunnels are not persisted across restart,
+ Framework will clean up dangling data connections when service restarts -->
+ <bool name="config_wlan_data_service_conn_persistence_on_restart">true</bool>
+
<!-- Cellular data service class name to bind to by default. If none is specified in an overlay, an
empty string is passed in -->
<string name="config_wwan_data_service_class" translatable="false"></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b0ee810fee41..ece65ff21487 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -298,6 +298,7 @@
<java-symbol type="string" name="config_wlan_network_service_package" />
<java-symbol type="string" name="config_wwan_network_service_class" />
<java-symbol type="string" name="config_wlan_network_service_class" />
+ <java-symbol type="bool" name="config_wlan_data_service_conn_persistence_on_restart" />
<java-symbol type="string" name="config_wwan_data_service_package" />
<java-symbol type="string" name="config_wlan_data_service_package" />
<java-symbol type="string" name="config_wwan_data_service_class" />
diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml
index 7f9d8749358c..6849a90f5010 100644
--- a/core/tests/bluetoothtests/AndroidManifest.xml
+++ b/core/tests/bluetoothtests/AndroidManifest.xml
@@ -15,14 +15,18 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.bluetooth.tests" >
+ package="com.android.bluetooth.tests"
+ android:sharedUserId="android.uid.bluetooth" >
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+ <uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
index 4b32ceae0617..89dbe3f75b56 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
@@ -360,6 +360,30 @@ public class BluetoothStressTest extends InstrumentationTestCase {
mTestUtils.unpair(mAdapter, device);
}
+ /* Make sure there is at least 1 unread message in the last week on remote device */
+ public void testMceSetMessageStatus() {
+ int iterations = BluetoothTestRunner.sMceSetMessageStatusIterations;
+ if (iterations == 0) {
+ return;
+ }
+
+ BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+ mTestUtils.enable(mAdapter);
+ mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.MAP_CLIENT, null);
+ mTestUtils.mceGetUnreadMessage(mAdapter, device);
+
+ for (int i = 0; i < iterations; i++) {
+ mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.READ);
+ mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.UNREAD);
+ }
+
+ /**
+ * It is hard to find device to support set undeleted status, so just
+ * set deleted in 1 iteration
+ **/
+ mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.DELETED);
+ }
+
private void sleep(long time) {
try {
Thread.sleep(time);
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java
index 56e691d8c246..d19c2c3e7e24 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java
@@ -40,6 +40,7 @@ import android.util.Log;
* [-e connect_input_iterations <iterations>] \
* [-e connect_pan_iterations <iterations>] \
* [-e start_stop_sco_iterations <iterations>] \
+ * [-e mce_set_message_status_iterations <iterations>] \
* [-e pair_address <address>] \
* [-e headset_address <address>] \
* [-e a2dp_address <address>] \
@@ -64,6 +65,7 @@ public class BluetoothTestRunner extends InstrumentationTestRunner {
public static int sConnectInputIterations = 100;
public static int sConnectPanIterations = 100;
public static int sStartStopScoIterations = 100;
+ public static int sMceSetMessageStatusIterations = 100;
public static String sDeviceAddress = "";
public static byte[] sDevicePairPin = {'1', '2', '3', '4'};
@@ -173,6 +175,15 @@ public class BluetoothTestRunner extends InstrumentationTestRunner {
}
}
+ val = arguments.getString("mce_set_message_status_iterations");
+ if (val != null) {
+ try {
+ sMceSetMessageStatusIterations = Integer.parseInt(val);
+ } catch (NumberFormatException e) {
+ // Invalid argument, fall back to default value
+ }
+ }
+
val = arguments.getString("device_address");
if (val != null) {
sDeviceAddress = val;
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
index ed613c36b89b..409025bc670d 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
@@ -56,6 +56,10 @@ public class BluetoothTestUtils extends Assert {
private static final int CONNECT_PROXY_TIMEOUT = 5000;
/** Time between polls in ms. */
private static final int POLL_TIME = 100;
+ /** Timeout to get map message in ms. */
+ private static final int GET_UNREAD_MESSAGE_TIMEOUT = 10000;
+ /** Timeout to set map message status in ms. */
+ private static final int SET_MESSAGE_STATUS_TIMEOUT = 2000;
private abstract class FlagReceiver extends BroadcastReceiver {
private int mExpectedFlags = 0;
@@ -98,6 +102,8 @@ public class BluetoothTestUtils extends Assert {
private static final int STATE_TURNING_ON_FLAG = 1 << 6;
private static final int STATE_ON_FLAG = 1 << 7;
private static final int STATE_TURNING_OFF_FLAG = 1 << 8;
+ private static final int STATE_GET_MESSAGE_FINISHED_FLAG = 1 << 9;
+ private static final int STATE_SET_MESSAGE_STATUS_FINISHED_FLAG = 1 << 10;
public BluetoothReceiver(int expectedFlags) {
super(expectedFlags);
@@ -231,6 +237,9 @@ public class BluetoothTestUtils extends Assert {
case BluetoothProfile.PAN:
mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED;
break;
+ case BluetoothProfile.MAP_CLIENT:
+ mConnectionAction = BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED;
+ break;
default:
mConnectionAction = null;
}
@@ -308,6 +317,34 @@ public class BluetoothTestUtils extends Assert {
}
}
+
+ private class MceSetMessageStatusReceiver extends FlagReceiver {
+ private static final int MESSAGE_RECEIVED_FLAG = 1;
+ private static final int STATUS_CHANGED_FLAG = 1 << 1;
+
+ public MceSetMessageStatusReceiver(int expectedFlags) {
+ super(expectedFlags);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (BluetoothMapClient.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
+ String handle = intent.getStringExtra(BluetoothMapClient.EXTRA_MESSAGE_HANDLE);
+ assertNotNull(handle);
+ setFiredFlag(MESSAGE_RECEIVED_FLAG);
+ mMsgHandle = handle;
+ } else if (BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED.equals(intent.getAction())) {
+ int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE);
+ assertEquals(result, BluetoothMapClient.RESULT_SUCCESS);
+ setFiredFlag(STATUS_CHANGED_FLAG);
+ } else if (BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED.equals(intent.getAction())) {
+ int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE);
+ assertEquals(result, BluetoothMapClient.RESULT_SUCCESS);
+ setFiredFlag(STATUS_CHANGED_FLAG);
+ }
+ }
+ }
+
private BluetoothProfile.ServiceListener mServiceListener =
new BluetoothProfile.ServiceListener() {
@Override
@@ -326,6 +363,9 @@ public class BluetoothTestUtils extends Assert {
case BluetoothProfile.PAN:
mPan = (BluetoothPan) proxy;
break;
+ case BluetoothProfile.MAP_CLIENT:
+ mMce = (BluetoothMapClient) proxy;
+ break;
}
}
}
@@ -346,6 +386,9 @@ public class BluetoothTestUtils extends Assert {
case BluetoothProfile.PAN:
mPan = null;
break;
+ case BluetoothProfile.MAP_CLIENT:
+ mMce = null;
+ break;
}
}
}
@@ -362,6 +405,8 @@ public class BluetoothTestUtils extends Assert {
private BluetoothHeadset mHeadset = null;
private BluetoothHidHost mInput = null;
private BluetoothPan mPan = null;
+ private BluetoothMapClient mMce = null;
+ private String mMsgHandle = null;
/**
* Creates a utility instance for testing Bluetooth.
@@ -898,7 +943,7 @@ public class BluetoothTestUtils extends Assert {
* @param adapter The BT adapter.
* @param device The remote device.
* @param profile The profile to connect. One of {@link BluetoothProfile#A2DP},
- * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#HID_HOST}.
+ * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#HID_HOST} or {@link BluetoothProfile#MAP_CLIENT}..
* @param methodName The method name to printed in the logs. If null, will be
* "connectProfile(profile=&lt;profile&gt;, device=&lt;device&gt;)"
*/
@@ -941,6 +986,8 @@ public class BluetoothTestUtils extends Assert {
assertTrue(((BluetoothHeadset)proxy).connect(device));
} else if (profile == BluetoothProfile.HID_HOST) {
assertTrue(((BluetoothHidHost)proxy).connect(device));
+ } else if (profile == BluetoothProfile.MAP_CLIENT) {
+ assertTrue(((BluetoothMapClient)proxy).connect(device));
}
break;
default:
@@ -1016,6 +1063,8 @@ public class BluetoothTestUtils extends Assert {
assertTrue(((BluetoothHeadset)proxy).disconnect(device));
} else if (profile == BluetoothProfile.HID_HOST) {
assertTrue(((BluetoothHidHost)proxy).disconnect(device));
+ } else if (profile == BluetoothProfile.MAP_CLIENT) {
+ assertTrue(((BluetoothMapClient)proxy).disconnect(device));
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
@@ -1373,6 +1422,89 @@ public class BluetoothTestUtils extends Assert {
}
}
+ public void mceGetUnreadMessage(BluetoothAdapter adapter, BluetoothDevice device) {
+ int mask;
+ String methodName = "getUnreadMessage";
+
+ if (!adapter.isEnabled()) {
+ fail(String.format("%s bluetooth not enabled", methodName));
+ }
+
+ if (!adapter.getBondedDevices().contains(device)) {
+ fail(String.format("%s device not paired", methodName));
+ }
+
+ mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT);
+ assertNotNull(mMce);
+
+ if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
+ fail(String.format("%s device is not connected", methodName));
+ }
+
+ mMsgHandle = null;
+ mask = MceSetMessageStatusReceiver.MESSAGE_RECEIVED_FLAG;
+ MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask);
+ assertTrue(mMce.getUnreadMessages(device));
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < GET_UNREAD_MESSAGE_TIMEOUT) {
+ if ((receiver.getFiredFlags() & mask) == mask) {
+ writeOutput(String.format("%s completed", methodName));
+ removeReceiver(receiver);
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+ int firedFlags = receiver.getFiredFlags();
+ removeReceiver(receiver);
+ fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
+ methodName, mMce.getConnectionState(device), BluetoothMapClient.STATE_CONNECTED, firedFlags, mask));
+ }
+
+ /**
+ * Set a message to read/unread/deleted/undeleted
+ */
+ public void mceSetMessageStatus(BluetoothAdapter adapter, BluetoothDevice device, int status) {
+ int mask;
+ String methodName = "setMessageStatus";
+
+ if (!adapter.isEnabled()) {
+ fail(String.format("%s bluetooth not enabled", methodName));
+ }
+
+ if (!adapter.getBondedDevices().contains(device)) {
+ fail(String.format("%s device not paired", methodName));
+ }
+
+ mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT);
+ assertNotNull(mMce);
+
+ if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
+ fail(String.format("%s device is not connected", methodName));
+ }
+
+ assertNotNull(mMsgHandle);
+ mask = MceSetMessageStatusReceiver.STATUS_CHANGED_FLAG;
+ MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask);
+
+ assertTrue(mMce.setMessageStatus(device, mMsgHandle, status));
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < SET_MESSAGE_STATUS_TIMEOUT) {
+ if ((receiver.getFiredFlags() & mask) == mask) {
+ writeOutput(String.format("%s completed", methodName));
+ removeReceiver(receiver);
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = receiver.getFiredFlags();
+ removeReceiver(receiver);
+ fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
+ methodName, mMce.getConnectionState(device), BluetoothPan.STATE_CONNECTED, firedFlags, mask));
+ }
+
private void addReceiver(BroadcastReceiver receiver, String[] actions) {
IntentFilter filter = new IntentFilter();
for (String action: actions) {
@@ -1408,7 +1540,8 @@ public class BluetoothTestUtils extends Assert {
String[] actions = {
BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
- BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED};
+ BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED,
+ BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED};
ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
expectedFlags);
addReceiver(receiver, actions);
@@ -1430,6 +1563,16 @@ public class BluetoothTestUtils extends Assert {
return receiver;
}
+ private MceSetMessageStatusReceiver getMceSetMessageStatusReceiver(BluetoothDevice device,
+ int expectedFlags) {
+ String[] actions = {BluetoothMapClient.ACTION_MESSAGE_RECEIVED,
+ BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED,
+ BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED};
+ MceSetMessageStatusReceiver receiver = new MceSetMessageStatusReceiver(expectedFlags);
+ addReceiver(receiver, actions);
+ return receiver;
+ }
+
private void removeReceiver(BroadcastReceiver receiver) {
mContext.unregisterReceiver(receiver);
mReceivers.remove(receiver);
@@ -1456,6 +1599,10 @@ public class BluetoothTestUtils extends Assert {
if (mPan != null) {
return mPan;
}
+ case BluetoothProfile.MAP_CLIENT:
+ if (mMce != null) {
+ return mMce;
+ }
break;
default:
return null;
@@ -1483,6 +1630,11 @@ public class BluetoothTestUtils extends Assert {
sleep(POLL_TIME);
}
return mPan;
+ case BluetoothProfile.MAP_CLIENT:
+ while (mMce == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+ sleep(POLL_TIME);
+ }
+ return mMce;
default:
return null;
}
diff --git a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
index d00d052db590..0af8c728aba3 100644
--- a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
+++ b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
@@ -154,6 +154,29 @@ public class EuiccProfileInfoTest {
}
@Test
+ public void testBuilder_BasedOnAnotherProfileWithEmptyAccessRules() {
+ EuiccProfileInfo p =
+ new EuiccProfileInfo.Builder("21430000000000006587")
+ .setNickname("profile nickname")
+ .setProfileName("profile name")
+ .setServiceProviderName("service provider")
+ .setCarrierIdentifier(
+ new CarrierIdentifier(
+ new byte[] {0x23, 0x45, 0x67},
+ "123",
+ "45"))
+ .setState(EuiccProfileInfo.PROFILE_STATE_ENABLED)
+ .setProfileClass(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL)
+ .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE)
+ .setUiccAccessRule(null)
+ .build();
+
+ EuiccProfileInfo copied = new EuiccProfileInfo.Builder(p).build();
+
+ assertEquals(null, copied.getUiccAccessRules());
+ }
+
+ @Test
public void testEqualsHashCode() {
EuiccProfileInfo p =
new EuiccProfileInfo.Builder("21430000000000006587")
diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java
index 5a0a84db5905..a3434e885012 100644
--- a/core/tests/coretests/src/android/text/format/DateFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java
@@ -16,9 +16,12 @@
package android.text.format;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import android.icu.text.DateFormatSymbols;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -27,6 +30,7 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
import java.util.Locale;
@Presubmit
@@ -55,4 +59,80 @@ public class DateFormatTest {
assertFalse(DateFormat.is24HourLocale(Locale.US));
assertTrue(DateFormat.is24HourLocale(Locale.GERMANY));
}
+
+ @Test
+ public void testgetIcuDateFormatSymbols() {
+ DateFormatSymbols dfs = DateFormat.getIcuDateFormatSymbols(Locale.US);
+ assertEquals("AM", dfs.getAmPmStrings()[0]);
+ assertEquals("PM", dfs.getAmPmStrings()[1]);
+ assertEquals("a", dfs.getAmpmNarrowStrings()[0]);
+ assertEquals("p", dfs.getAmpmNarrowStrings()[1]);
+ }
+
+ @Test
+ public void testGetDateFormatOrder() {
+ // lv and fa use differing orders depending on whether you're using numeric or
+ // textual months.
+ Locale lv = new Locale("lv");
+ assertEquals("[d, M, y]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(lv, "yyyy-M-dd"))));
+ assertEquals("[y, d, M]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(lv, "yyyy-MMM-dd"))));
+ assertEquals("[d, M, \u0000]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(lv, "MMM-dd"))));
+ Locale fa = new Locale("fa");
+ assertEquals("[y, M, d]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(fa, "yyyy-M-dd"))));
+ assertEquals("[d, M, y]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(fa, "yyyy-MMM-dd"))));
+ assertEquals("[d, M, \u0000]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(fa, "MMM-dd"))));
+
+ // English differs on each side of the Atlantic.
+ Locale enUS = Locale.US;
+ assertEquals("[M, d, y]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(enUS, "yyyy-M-dd"))));
+ assertEquals("[M, d, y]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(enUS, "yyyy-MMM-dd"))));
+ assertEquals("[M, d, \u0000]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(enUS, "MMM-dd"))));
+ Locale enGB = Locale.UK;
+ assertEquals("[d, M, y]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(enGB, "yyyy-M-dd"))));
+ assertEquals("[d, M, y]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(enGB, "yyyy-MMM-dd"))));
+ assertEquals("[d, M, \u0000]", Arrays.toString(DateFormat.getDateFormatOrder(
+ best(enGB, "MMM-dd"))));
+
+ assertEquals("[y, M, d]", Arrays.toString(DateFormat.getDateFormatOrder(
+ "yyyy - 'why' '' 'ddd' MMM-dd")));
+
+ try {
+ DateFormat.getDateFormatOrder("the quick brown fox jumped over the lazy dog");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ DateFormat.getDateFormatOrder("'");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ DateFormat.getDateFormatOrder("yyyy'");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ DateFormat.getDateFormatOrder("yyyy'MMM");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ private static String best(Locale l, String skeleton) {
+ return DateFormat.getBestDateTimePattern(l, skeleton);
+ }
}
diff --git a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
new file mode 100644
index 000000000000..0f17d27048f3
--- /dev/null
+++ b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
@@ -0,0 +1,671 @@
+/*
+ * Copyright (C) 2013 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.text.format;
+
+import static android.icu.util.TimeZone.GMT_ZONE;
+import static android.icu.util.ULocale.ENGLISH;
+import static android.text.format.DateIntervalFormat.formatDateRange;
+import static android.text.format.DateUtils.FORMAT_12HOUR;
+import static android.text.format.DateUtils.FORMAT_24HOUR;
+import static android.text.format.DateUtils.FORMAT_ABBREV_ALL;
+import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
+import static android.text.format.DateUtils.FORMAT_ABBREV_TIME;
+import static android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY;
+import static android.text.format.DateUtils.FORMAT_NO_MONTH_DAY;
+import static android.text.format.DateUtils.FORMAT_NO_YEAR;
+import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_TIME;
+import static android.text.format.DateUtils.FORMAT_SHOW_WEEKDAY;
+import static android.text.format.DateUtils.FORMAT_SHOW_YEAR;
+import static android.text.format.DateUtils.FORMAT_UTC;
+
+import static org.junit.Assert.assertEquals;
+
+import android.icu.util.Calendar;
+import android.icu.util.TimeZone;
+import android.icu.util.ULocale;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.BiFunction;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DateIntervalFormatTest {
+ private static final long MINUTE = 60 * 1000;
+ private static final long HOUR = 60 * MINUTE;
+ private static final long DAY = 24 * HOUR;
+ private static final long MONTH = 31 * DAY;
+ private static final long YEAR = 12 * MONTH;
+
+ // These are the old CTS tests for DateIntervalFormat.formatDateRange.
+ @Test
+ public void test_formatDateInterval() throws Exception {
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+
+ Calendar c = Calendar.getInstance(tz, ULocale.US);
+ c.set(Calendar.MONTH, Calendar.JANUARY);
+ c.set(Calendar.DAY_OF_MONTH, 19);
+ c.set(Calendar.HOUR_OF_DAY, 3);
+ c.set(Calendar.MINUTE, 30);
+ c.set(Calendar.SECOND, 15);
+ c.set(Calendar.MILLISECOND, 0);
+ long timeWithCurrentYear = c.getTimeInMillis();
+
+ c.set(Calendar.YEAR, 2009);
+ long fixedTime = c.getTimeInMillis();
+
+ c.set(Calendar.MINUTE, 0);
+ c.set(Calendar.SECOND, 0);
+ long onTheHour = c.getTimeInMillis();
+
+ long noonDuration = (8 * 60 + 30) * 60 * 1000 - 15 * 1000;
+ long midnightDuration = (3 * 60 + 30) * 60 * 1000 + 15 * 1000;
+
+ ULocale de_DE = new ULocale("de", "DE");
+ ULocale en_US = new ULocale("en", "US");
+ ULocale es_ES = new ULocale("es", "ES");
+ ULocale es_US = new ULocale("es", "US");
+
+ assertEquals("Monday",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_WEEKDAY));
+ assertEquals("January 19",
+ formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR,
+ FORMAT_SHOW_DATE));
+ assertEquals("3:30 AM", formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_SHOW_TIME));
+ assertEquals("January 19, 2009",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR));
+ assertEquals("January 19",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_NO_YEAR));
+ assertEquals("January",
+ formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR,
+ FORMAT_NO_MONTH_DAY));
+ assertEquals("3:30 AM",
+ formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_12HOUR | FORMAT_SHOW_TIME));
+ assertEquals("03:30",
+ formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_24HOUR | FORMAT_SHOW_TIME));
+ assertEquals("3:30 AM", formatDateRange(en_US, tz, fixedTime, fixedTime,
+ FORMAT_12HOUR /*| FORMAT_CAP_AMPM*/ | FORMAT_SHOW_TIME));
+ assertEquals("12:00 PM",
+ formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration,
+ FORMAT_12HOUR | FORMAT_SHOW_TIME));
+ assertEquals("12:00 PM",
+ formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration,
+ FORMAT_12HOUR | FORMAT_SHOW_TIME /*| FORMAT_CAP_NOON*/));
+ assertEquals("12:00 PM",
+ formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration,
+ FORMAT_12HOUR /*| FORMAT_NO_NOON*/ | FORMAT_SHOW_TIME));
+ assertEquals("12:00 AM", formatDateRange(en_US, tz, fixedTime - midnightDuration,
+ fixedTime - midnightDuration,
+ FORMAT_12HOUR | FORMAT_SHOW_TIME /*| FORMAT_NO_MIDNIGHT*/));
+ assertEquals("3:30 AM",
+ formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_SHOW_TIME | FORMAT_UTC));
+ assertEquals("3 AM", formatDateRange(en_US, tz, onTheHour, onTheHour,
+ FORMAT_SHOW_TIME | FORMAT_ABBREV_TIME));
+ assertEquals("Mon", formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR,
+ FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_WEEKDAY));
+ assertEquals("Jan 19",
+ formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH));
+ assertEquals("Jan 19",
+ formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+
+ assertEquals("1/19/2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * HOUR,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("1/19/2009 – 1/22/2009",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("1/19/2009 – 4/22/2009",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("1/19/2009 – 2/9/2012",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+
+ assertEquals("19.1.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + HOUR,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19.–22.01.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19.01. – 22.04.2009",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19.01.2009 – 09.02.2012",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+
+ assertEquals("19/1/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + HOUR,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19/1/2009–22/1/2009",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19/1/2009–22/4/2009",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19/1/2009–9/2/2012",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+
+ assertEquals("19/1/2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + HOUR,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19/1/2009–22/1/2009",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19/1/2009–22/4/2009",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19/1/2009–9/2/2012",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+
+ // These are some random other test cases I came up with.
+
+ assertEquals("January 19 – 22, 2009",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
+ assertEquals("Jan 19 – 22, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Mon, Jan 19 – Thu, Jan 22, 2009",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("Monday, January 19 – Thursday, January 22, 2009",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+
+ assertEquals("January 19 – April 22, 2009",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+ assertEquals("Jan 19 – Apr 22, 2009",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Mon, Jan 19 – Wed, Apr 22, 2009",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("January – April 2009",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
+
+ assertEquals("Jan 19, 2009 – Feb 9, 2012",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Jan 2009 – Feb 2012",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+ assertEquals("January 19, 2009 – February 9, 2012",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+ assertEquals("Monday, January 19, 2009 – Thursday, February 9, 2012",
+ formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+
+ // The same tests but for de_DE.
+
+ assertEquals("19.–22. Januar 2009",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, 0));
+ assertEquals("19.–22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Mo., 19. – Do., 22. Jan. 2009",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("Montag, 19. – Donnerstag, 22. Januar 2009",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+
+ assertEquals("19. Januar – 22. April 2009",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+ assertEquals("19. Jan. – 22. Apr. 2009",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Mo., 19. Jan. – Mi., 22. Apr. 2009",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("Januar–April 2009",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
+
+ assertEquals("19. Jan. 2009 – 9. Feb. 2012",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Jan. 2009 – Feb. 2012",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+ assertEquals("19. Januar 2009 – 9. Februar 2012",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+ assertEquals("Montag, 19. Januar 2009 – Donnerstag, 9. Februar 2012",
+ formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+
+ // The same tests but for es_US.
+
+ assertEquals("19–22 de enero de 2009",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
+ assertEquals("19–22 de ene. de 2009",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("lun., 19 de ene. – jue., 22 de ene. de 2009",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+
+ assertEquals("19 de enero–22 de abril de 2009",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+ assertEquals("19 de ene. – 22 de abr. 2009",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("lun., 19 de ene. – mié., 22 de abr. de 2009",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("enero–abril de 2009",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
+
+ assertEquals("19 de ene. de 2009 – 9 de feb. de 2012",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("ene. de 2009 – feb. de 2012",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+ assertEquals("19 de enero de 2009–9 de febrero de 2012",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+ assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012",
+ formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+
+ // The same tests but for es_ES.
+
+ assertEquals("19–22 de enero de 2009",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
+ assertEquals("19–22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("lun., 19 ene. – jue., 22 ene. 2009",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
+ FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+
+ assertEquals("19 de enero–22 de abril de 2009",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+ assertEquals("19 ene. – 22 abr. 2009",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("lun., 19 ene. – mié., 22 abr. 2009",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
+ FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("enero–abril de 2009",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
+
+ assertEquals("19 ene. 2009 – 9 feb. 2012",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("ene. 2009 – feb. 2012",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
+ FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+ assertEquals("19 de enero de 2009–9 de febrero de 2012",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+ assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012",
+ formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+ }
+
+ // http://b/8862241 - we should be able to format dates past 2038.
+ // See also http://code.google.com/p/android/issues/detail?id=13050.
+ @Test
+ public void test8862241() throws Exception {
+ ULocale l = ULocale.US;
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar c = Calendar.getInstance(tz, l);
+ c.clear();
+ c.set(2042, Calendar.JANUARY, 19, 3, 30);
+ long jan_19_2042 = c.getTimeInMillis();
+ c.set(2046, Calendar.OCTOBER, 4, 3, 30);
+ long oct_4_2046 = c.getTimeInMillis();
+ int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL;
+ assertEquals("Jan 19, 2042 – Oct 4, 2046",
+ formatDateRange(l, tz, jan_19_2042, oct_4_2046, flags));
+ }
+
+ // http://b/10089890 - we should take the given time zone into account.
+ @Test
+ public void test10089890() throws Exception {
+ ULocale l = ULocale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+ TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles");
+ int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL | FORMAT_SHOW_TIME | FORMAT_24HOUR;
+
+ // The Unix epoch is UTC, so 0 is 1970-01-01T00:00Z...
+ assertEquals("Jan 1, 1970, 00:00 – Jan 2, 1970, 00:00",
+ formatDateRange(l, utc, 0, DAY + 1, flags));
+ // But MTV is hours behind, so 0 was still the afternoon of the previous day...
+ assertEquals("Dec 31, 1969, 16:00 – Jan 1, 1970, 16:00",
+ formatDateRange(l, pacific, 0, DAY, flags));
+ }
+
+ // http://b/10318326 - we can drop the minutes in a 12-hour time if they're zero,
+ // but not if we're using the 24-hour clock. That is: "4 PM" is reasonable, "16" is not.
+ @Test
+ public void test10318326() throws Exception {
+ long midnight = 0;
+ long teaTime = 16 * HOUR;
+
+ int time12 = FORMAT_12HOUR | FORMAT_SHOW_TIME;
+ int time24 = FORMAT_24HOUR | FORMAT_SHOW_TIME;
+ int abbr12 = time12 | FORMAT_ABBREV_ALL;
+ int abbr24 = time24 | FORMAT_ABBREV_ALL;
+
+ ULocale l = ULocale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+
+ // Full length on-the-hour times.
+ assertEquals("00:00", formatDateRange(l, utc, midnight, midnight, time24));
+ assertEquals("12:00 AM", formatDateRange(l, utc, midnight, midnight, time12));
+ assertEquals("16:00", formatDateRange(l, utc, teaTime, teaTime, time24));
+ assertEquals("4:00 PM", formatDateRange(l, utc, teaTime, teaTime, time12));
+
+ // Abbreviated on-the-hour times.
+ assertEquals("00:00", formatDateRange(l, utc, midnight, midnight, abbr24));
+ assertEquals("12 AM", formatDateRange(l, utc, midnight, midnight, abbr12));
+ assertEquals("16:00", formatDateRange(l, utc, teaTime, teaTime, abbr24));
+ assertEquals("4 PM", formatDateRange(l, utc, teaTime, teaTime, abbr12));
+
+ // Abbreviated on-the-hour ranges.
+ assertEquals("00:00 – 16:00", formatDateRange(l, utc, midnight, teaTime, abbr24));
+ assertEquals("12 AM – 4 PM", formatDateRange(l, utc, midnight, teaTime, abbr12));
+
+ // Abbreviated mixed ranges.
+ assertEquals("00:00 – 16:01", formatDateRange(l, utc, midnight, teaTime + MINUTE, abbr24));
+ assertEquals("12:00 AM – 4:01 PM",
+ formatDateRange(l, utc, midnight, teaTime + MINUTE, abbr12));
+ }
+
+ // http://b/10560853 - when the time is not displayed, an end time 0 ms into the next day is
+ // considered to belong to the previous day.
+ @Test
+ public void test10560853_when_time_not_displayed() throws Exception {
+ ULocale l = ULocale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+
+ long midnight = 0;
+ long midnightNext = 1 * DAY;
+
+ int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY;
+
+ // An all-day event runs until 0 milliseconds into the next day, but is formatted as if it's
+ // just the first day.
+ assertEquals("Thursday, January 1, 1970",
+ formatDateRange(l, utc, midnight, midnightNext, flags));
+
+ // Run one millisecond over, though, and you're into the next day.
+ long nextMorning = 1 * DAY + 1;
+ assertEquals("Thursday, January 1 – Friday, January 2, 1970",
+ formatDateRange(l, utc, midnight, nextMorning, flags));
+
+ // But the same reasoning applies for that day.
+ long nextMidnight = 2 * DAY;
+ assertEquals("Thursday, January 1 – Friday, January 2, 1970",
+ formatDateRange(l, utc, midnight, nextMidnight, flags));
+ }
+
+ // http://b/10560853 - when the start and end times are otherwise on the same day,
+ // an end time 0 ms into the next day is considered to belong to the previous day.
+ @Test
+ public void test10560853_for_single_day_events() throws Exception {
+ ULocale l = ULocale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+
+ int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
+
+ assertEquals("January 1, 1970, 22:00 – 00:00",
+ formatDateRange(l, utc, 22 * HOUR, 24 * HOUR, flags));
+ assertEquals("January 1, 1970, 22:00 – January 2, 1970, 00:30",
+ formatDateRange(l, utc, 22 * HOUR, 24 * HOUR + 30 * MINUTE, flags));
+ }
+
+ // The fix for http://b/10560853 didn't work except for the day around the epoch, which was
+ // all the unit test checked!
+ @Test
+ public void test_single_day_events_later_than_epoch() throws Exception {
+ ULocale l = ULocale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+
+ int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
+
+ Calendar c = Calendar.getInstance(utc, l);
+ c.clear();
+ c.set(1980, Calendar.JANUARY, 1, 0, 0);
+ long jan_1_1980 = c.getTimeInMillis();
+ assertEquals("January 1, 1980, 22:00 – 00:00",
+ formatDateRange(l, utc, jan_1_1980 + 22 * HOUR, jan_1_1980 + 24 * HOUR, flags));
+ assertEquals("January 1, 1980, 22:00 – January 2, 1980, 00:30",
+ formatDateRange(l, utc, jan_1_1980 + 22 * HOUR,
+ jan_1_1980 + 24 * HOUR + 30 * MINUTE, flags));
+ }
+
+ // The fix for http://b/10560853 didn't work except for UTC, which was
+ // all the unit test checked!
+ @Test
+ public void test_single_day_events_not_in_UTC() throws Exception {
+ ULocale l = ULocale.US;
+ TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles");
+
+ int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
+
+ Calendar c = Calendar.getInstance(pacific, l);
+ c.clear();
+ c.set(1980, Calendar.JANUARY, 1, 0, 0);
+ long jan_1_1980 = c.getTimeInMillis();
+ assertEquals("January 1, 1980, 22:00 – 00:00",
+ formatDateRange(l, pacific, jan_1_1980 + 22 * HOUR, jan_1_1980 + 24 * HOUR, flags));
+
+ c.set(1980, Calendar.JULY, 1, 0, 0);
+ long jul_1_1980 = c.getTimeInMillis();
+ assertEquals("July 1, 1980, 22:00 – 00:00",
+ formatDateRange(l, pacific, jul_1_1980 + 22 * HOUR, jul_1_1980 + 24 * HOUR, flags));
+ }
+
+ // http://b/10209343 - even if the caller didn't explicitly ask us to include the year,
+ // we should do so for years other than the current year.
+ @Test
+ public void test10209343_when_not_this_year() {
+ ULocale l = ULocale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+
+ int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_TIME | FORMAT_24HOUR;
+
+ assertEquals("Thursday, January 1, 1970, 00:00", formatDateRange(l, utc, 0L, 0L, flags));
+
+ long t1833 = ((long) Integer.MIN_VALUE + Integer.MIN_VALUE) * 1000L;
+ assertEquals("Sunday, November 24, 1833, 17:31",
+ formatDateRange(l, utc, t1833, t1833, flags));
+
+ long t1901 = Integer.MIN_VALUE * 1000L;
+ assertEquals("Friday, December 13, 1901, 20:45",
+ formatDateRange(l, utc, t1901, t1901, flags));
+
+ long t2038 = Integer.MAX_VALUE * 1000L;
+ assertEquals("Tuesday, January 19, 2038, 03:14",
+ formatDateRange(l, utc, t2038, t2038, flags));
+
+ long t2106 = (2L + Integer.MAX_VALUE + Integer.MAX_VALUE) * 1000L;
+ assertEquals("Sunday, February 7, 2106, 06:28",
+ formatDateRange(l, utc, t2106, t2106, flags));
+ }
+
+ // http://b/10209343 - for the current year, we should honor the FORMAT_SHOW_YEAR flags.
+ @Test
+ public void test10209343_when_this_year() {
+ // Construct a date in the current year (whenever the test happens to be run).
+ ULocale l = ULocale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+ Calendar c = Calendar.getInstance(utc, l);
+ c.set(Calendar.MONTH, Calendar.FEBRUARY);
+ c.set(Calendar.DAY_OF_MONTH, 10);
+ c.set(Calendar.HOUR_OF_DAY, 0);
+ long thisYear = c.getTimeInMillis();
+
+ // You don't get the year if it's this year...
+ assertEquals("February 10", formatDateRange(l, utc, thisYear, thisYear, FORMAT_SHOW_DATE));
+
+ // ...unless you explicitly ask for it.
+ assertEquals(String.format("February 10, %d", c.get(Calendar.YEAR)),
+ formatDateRange(l, utc, thisYear, thisYear, FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR));
+
+ // ...or it's not actually this year...
+ Calendar c2 = (Calendar) c.clone();
+ c2.set(Calendar.YEAR, 1980);
+ long oldYear = c2.getTimeInMillis();
+ assertEquals("February 10, 1980",
+ formatDateRange(l, utc, oldYear, oldYear, FORMAT_SHOW_DATE));
+
+ // (But you can disable that!)
+ assertEquals("February 10",
+ formatDateRange(l, utc, oldYear, oldYear, FORMAT_SHOW_DATE | FORMAT_NO_YEAR));
+
+ // ...or the start and end years aren't the same...
+ assertEquals(String.format("February 10, 1980 – February 10, %d", c.get(Calendar.YEAR)),
+ formatDateRange(l, utc, oldYear, thisYear, FORMAT_SHOW_DATE));
+
+ // (And you can't avoid that --- icu4c steps in and overrides you.)
+ assertEquals(String.format("February 10, 1980 – February 10, %d", c.get(Calendar.YEAR)),
+ formatDateRange(l, utc, oldYear, thisYear, FORMAT_SHOW_DATE | FORMAT_NO_YEAR));
+ }
+
+ // http://b/8467515 - yet another y2k38 bug report.
+ @Test
+ public void test8467515() throws Exception {
+ ULocale l = ULocale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+ int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR | FORMAT_ABBREV_MONTH
+ | FORMAT_ABBREV_WEEKDAY;
+ long t;
+
+ Calendar calendar = Calendar.getInstance(utc, l);
+ calendar.clear();
+
+ calendar.set(2038, Calendar.JANUARY, 19, 12, 0, 0);
+ t = calendar.getTimeInMillis();
+ assertEquals("Tue, Jan 19, 2038", formatDateRange(l, utc, t, t, flags));
+
+ calendar.set(1900, Calendar.JANUARY, 1, 0, 0, 0);
+ t = calendar.getTimeInMillis();
+ assertEquals("Mon, Jan 1, 1900", formatDateRange(l, utc, t, t, flags));
+ }
+
+ // http://b/12004664
+ @Test
+ public void test12004664() throws Exception {
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+ Calendar c = Calendar.getInstance(utc, ULocale.US);
+ c.clear();
+ c.set(Calendar.YEAR, 1980);
+ c.set(Calendar.MONTH, Calendar.FEBRUARY);
+ c.set(Calendar.DAY_OF_MONTH, 10);
+ c.set(Calendar.HOUR_OF_DAY, 0);
+ long thisYear = c.getTimeInMillis();
+
+ int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR;
+ assertEquals("Sunday, February 10, 1980",
+ formatDateRange(new ULocale("en", "US"), utc, thisYear, thisYear, flags));
+
+ // If we supported non-Gregorian calendars, this is what that we'd expect for these
+ // ULocales.
+ // This is really the correct behavior, but since java.util.Calendar currently only supports
+ // the Gregorian calendar, we want to deliberately force icu4c to agree, otherwise we'd have
+ // a mix of calendars throughout an app's UI depending on whether Java or native code
+ // formatted
+ // the date.
+ // assertEquals("یکشنبه ۲۱ بهمن ۱۳۵۸ ه‍.ش.", formatDateRange(new ULocale("fa"), utc,
+ // thisYear, thisYear, flags));
+ // assertEquals("AP ۱۳۵۸ سلواغه ۲۱, یکشنبه", formatDateRange(new ULocale("ps"), utc,
+ // thisYear, thisYear, flags));
+ // assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 2523", formatDateRange(new ULocale("th"), utc,
+ // thisYear, thisYear, flags));
+
+ // For now, here are the localized Gregorian strings instead...
+ assertEquals("یکشنبه ۱۰ فوریهٔ ۱۹۸۰",
+ formatDateRange(new ULocale("fa"), utc, thisYear, thisYear, flags));
+ assertEquals("يونۍ د ۱۹۸۰ د فبروري ۱۰",
+ formatDateRange(new ULocale("ps"), utc, thisYear, thisYear, flags));
+ assertEquals("วันอาทิตย์ที่ 10 กุมภาพันธ์ ค.ศ. 1980",
+ formatDateRange(new ULocale("th"), utc, thisYear, thisYear, flags));
+ }
+
+ // http://b/13234532
+ @Test
+ public void test13234532() throws Exception {
+ ULocale l = ULocale.US;
+ TimeZone utc = TimeZone.getTimeZone("UTC");
+
+ int flags = FORMAT_SHOW_TIME | FORMAT_ABBREV_ALL | FORMAT_12HOUR;
+
+ assertEquals("10 – 11 AM", formatDateRange(l, utc, 10 * HOUR, 11 * HOUR, flags));
+ assertEquals("11 AM – 1 PM", formatDateRange(l, utc, 11 * HOUR, 13 * HOUR, flags));
+ assertEquals("2 – 3 PM", formatDateRange(l, utc, 14 * HOUR, 15 * HOUR, flags));
+ }
+
+ // http://b/20708022
+ @Test
+ public void testEndOfDayOnLastDayOfMonth() throws Exception {
+ final ULocale locale = new ULocale("en");
+ final TimeZone timeZone = TimeZone.getTimeZone("UTC");
+
+ assertEquals("11:00 PM – 12:00 AM", formatDateRange(locale, timeZone,
+ 1430434800000L, 1430438400000L, FORMAT_SHOW_TIME));
+ }
+
+ // http://b/68847519
+ @Test
+ public void testEndAtMidnight_dateAndTime() {
+ BiFunction<Long, Long, String> fmt = (from, to) -> formatDateRange(
+ ENGLISH, GMT_ZONE, from, to, FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_24HOUR);
+ // If we're showing times and the end-point is midnight the following day, we want the
+ // behaviour of suppressing the date for the end...
+ assertEquals("February 27, 2007, 04:00 – 00:00", fmt.apply(1172548800000L, 1172620800000L));
+ // ...unless the start-point is also midnight, in which case we need dates to disambiguate.
+ assertEquals("February 27, 2007, 00:00 – February 28, 2007, 00:00",
+ fmt.apply(1172534400000L, 1172620800000L));
+ // We want to show the date if the end-point is a millisecond after midnight the following
+ // day, or if it is exactly midnight the day after that.
+ assertEquals("February 27, 2007, 04:00 – February 28, 2007, 00:00",
+ fmt.apply(1172548800000L, 1172620800001L));
+ assertEquals("February 27, 2007, 04:00 – March 1, 2007, 00:00",
+ fmt.apply(1172548800000L, 1172707200000L));
+ // We want to show the date if the start-point is anything less than a minute after
+ // midnight,
+ // since that gets displayed as midnight...
+ assertEquals("February 27, 2007, 00:00 – February 28, 2007, 00:00",
+ fmt.apply(1172534459999L, 1172620800000L));
+ // ...but not if it is exactly one minute after midnight.
+ assertEquals("February 27, 2007, 00:01 – 00:00", fmt.apply(1172534460000L, 1172620800000L));
+ }
+
+ // http://b/68847519
+ @Test
+ public void testEndAtMidnight_dateOnly() {
+ BiFunction<Long, Long, String> fmt = (from, to) -> formatDateRange(
+ ENGLISH, GMT_ZONE, from, to, FORMAT_SHOW_DATE);
+ // If we're only showing dates and the end-point is midnight of any day, we want the
+ // behaviour of showing an end date one earlier. So if the end-point is March 2, 2007 00:00,
+ // show March 1, 2007 instead (whether the start-point is midnight or not).
+ assertEquals("February 27 – March 1, 2007", fmt.apply(1172534400000L, 1172793600000L));
+ assertEquals("February 27 – March 1, 2007", fmt.apply(1172548800000L, 1172793600000L));
+ // We want to show the true date if the end-point is a millisecond after midnight.
+ assertEquals("February 27 – March 2, 2007", fmt.apply(1172534400000L, 1172793600001L));
+
+ // 2006-02-27 00:00:00.000 GMT - 2007-03-02 00:00:00.000 GMT
+ assertEquals("February 27, 2006 – March 1, 2007",
+ fmt.apply(1140998400000L, 1172793600000L));
+
+ // Spans a leap year's Feb 29th.
+ assertEquals("February 27 – March 1, 2004", fmt.apply(1077840000000L, 1078185600000L));
+ }
+}
diff --git a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
new file mode 100644
index 000000000000..4b3b5735b4f3
--- /dev/null
+++ b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
@@ -0,0 +1,762 @@
+/*
+ * Copyright (C) 2015 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.text.format;
+
+import static android.text.format.DateUtils.FORMAT_ABBREV_ALL;
+import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE;
+import static android.text.format.DateUtils.FORMAT_NO_YEAR;
+import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_YEAR;
+import static android.text.format.RelativeDateTimeFormatter.DAY_IN_MILLIS;
+import static android.text.format.RelativeDateTimeFormatter.HOUR_IN_MILLIS;
+import static android.text.format.RelativeDateTimeFormatter.MINUTE_IN_MILLIS;
+import static android.text.format.RelativeDateTimeFormatter.SECOND_IN_MILLIS;
+import static android.text.format.RelativeDateTimeFormatter.WEEK_IN_MILLIS;
+import static android.text.format.RelativeDateTimeFormatter.YEAR_IN_MILLIS;
+import static android.text.format.RelativeDateTimeFormatter.getRelativeDateTimeString;
+import static android.text.format.RelativeDateTimeFormatter.getRelativeTimeSpanString;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RelativeDateTimeFormatterTest {
+
+ // Tests adopted from CTS tests for DateUtils.getRelativeTimeSpanString.
+ @Test
+ public void test_getRelativeTimeSpanStringCTS() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("GMT");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2015 at 10:50 GMT
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long baseTime = cal.getTimeInMillis();
+
+ assertEquals("0 minutes ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - SECOND_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("In 0 minutes",
+ getRelativeTimeSpanString(en_US, tz, baseTime + SECOND_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+
+ assertEquals("1 minute ago",
+ getRelativeTimeSpanString(en_US, tz, 0, MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 0));
+ assertEquals("In 1 minute",
+ getRelativeTimeSpanString(en_US, tz, MINUTE_IN_MILLIS, 0, MINUTE_IN_MILLIS, 0));
+
+ assertEquals("42 minutes ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - 42 * MINUTE_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("In 42 minutes",
+ getRelativeTimeSpanString(en_US, tz, baseTime + 42 * MINUTE_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+
+ final long TWO_HOURS_IN_MS = 2 * HOUR_IN_MILLIS;
+ assertEquals("2 hours ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - TWO_HOURS_IN_MS, baseTime,
+ MINUTE_IN_MILLIS, FORMAT_NUMERIC_DATE));
+ assertEquals("In 2 hours",
+ getRelativeTimeSpanString(en_US, tz, baseTime + TWO_HOURS_IN_MS, baseTime,
+ MINUTE_IN_MILLIS, FORMAT_NUMERIC_DATE));
+
+ assertEquals("In 42 min.",
+ getRelativeTimeSpanString(en_US, tz, baseTime + (42 * MINUTE_IN_MILLIS), baseTime,
+ MINUTE_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+
+ assertEquals("Tomorrow",
+ getRelativeTimeSpanString(en_US, tz, DAY_IN_MILLIS, 0, DAY_IN_MILLIS, 0));
+ assertEquals("In 2 days",
+ getRelativeTimeSpanString(en_US, tz, 2 * DAY_IN_MILLIS, 0, DAY_IN_MILLIS, 0));
+ assertEquals("Yesterday",
+ getRelativeTimeSpanString(en_US, tz, 0, DAY_IN_MILLIS, DAY_IN_MILLIS, 0));
+ assertEquals("2 days ago",
+ getRelativeTimeSpanString(en_US, tz, 0, 2 * DAY_IN_MILLIS, DAY_IN_MILLIS, 0));
+
+ final long DAY_DURATION = 5 * 24 * 60 * 60 * 1000;
+ assertEquals("5 days ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - DAY_DURATION, baseTime,
+ DAY_IN_MILLIS, 0));
+ }
+
+ private void test_getRelativeTimeSpanString_helper(long delta, long minResolution, int flags,
+ String expectedInPast,
+ String expectedInFuture) throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2015 at 10:50 PST
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long base = cal.getTimeInMillis();
+
+ assertEquals(expectedInPast,
+ getRelativeTimeSpanString(en_US, tz, base - delta, base, minResolution, flags));
+ assertEquals(expectedInFuture,
+ getRelativeTimeSpanString(en_US, tz, base + delta, base, minResolution, flags));
+ }
+
+ private void test_getRelativeTimeSpanString_helper(long delta, long minResolution,
+ String expectedInPast,
+ String expectedInFuture) throws Exception {
+ test_getRelativeTimeSpanString_helper(delta, minResolution, 0, expectedInPast,
+ expectedInFuture);
+ }
+
+ @Test
+ public void test_getRelativeTimeSpanString() throws Exception {
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, 0, "0 seconds ago",
+ "0 seconds ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, 0, "5 days ago", "In 5 days");
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
+ "0 seconds ago",
+ "0 seconds ago");
+ test_getRelativeTimeSpanString_helper(1 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
+ "1 second ago",
+ "In 1 second");
+ test_getRelativeTimeSpanString_helper(2 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
+ "2 seconds ago",
+ "In 2 seconds");
+ test_getRelativeTimeSpanString_helper(25 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
+ "25 seconds ago",
+ "In 25 seconds");
+ test_getRelativeTimeSpanString_helper(75 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
+ "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(5000 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
+ "1 hour ago",
+ "In 1 hour");
+
+ test_getRelativeTimeSpanString_helper(0 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
+ "0 minutes ago",
+ "0 minutes ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
+ "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(2 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
+ "2 minutes ago",
+ "In 2 minutes");
+ test_getRelativeTimeSpanString_helper(25 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
+ "25 minutes ago",
+ "In 25 minutes");
+ test_getRelativeTimeSpanString_helper(75 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(720 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
+ "12 hours ago",
+ "In 12 hours");
+
+ test_getRelativeTimeSpanString_helper(0 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "0 hours ago",
+ "0 hours ago");
+ test_getRelativeTimeSpanString_helper(1 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "2 hours ago",
+ "In 2 hours");
+ test_getRelativeTimeSpanString_helper(5 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "5 hours ago",
+ "In 5 hours");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "20 hours ago",
+ "In 20 hours");
+
+ test_getRelativeTimeSpanString_helper(0 * DAY_IN_MILLIS, DAY_IN_MILLIS, "Today", "Today");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(2 * DAY_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
+ "In 2 days");
+ test_getRelativeTimeSpanString_helper(25 * DAY_IN_MILLIS, DAY_IN_MILLIS, "January 11",
+ "March 2");
+
+ test_getRelativeTimeSpanString_helper(0 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "0 weeks ago",
+ "0 weeks ago");
+ test_getRelativeTimeSpanString_helper(1 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "1 week ago",
+ "In 1 week");
+ test_getRelativeTimeSpanString_helper(2 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "2 weeks ago",
+ "In 2 weeks");
+ test_getRelativeTimeSpanString_helper(25 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "25 weeks ago",
+ "In 25 weeks");
+
+ // duration >= minResolution
+ test_getRelativeTimeSpanString_helper(30 * SECOND_IN_MILLIS, 0, "30 seconds ago",
+ "In 30 seconds");
+ test_getRelativeTimeSpanString_helper(30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
+ "30 minutes ago", "In 30 minutes");
+ test_getRelativeTimeSpanString_helper(30 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, "5 days ago",
+ "In 5 days");
+ test_getRelativeTimeSpanString_helper(30 * WEEK_IN_MILLIS, MINUTE_IN_MILLIS,
+ "July 10, 2014",
+ "September 3");
+ test_getRelativeTimeSpanString_helper(5 * 365 * DAY_IN_MILLIS, MINUTE_IN_MILLIS,
+ "February 6, 2010", "February 4, 2020");
+
+ test_getRelativeTimeSpanString_helper(60 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS,
+ "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(120 * SECOND_IN_MILLIS - 1, MINUTE_IN_MILLIS,
+ "1 minute ago", "In 1 minute");
+ test_getRelativeTimeSpanString_helper(60 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(120 * MINUTE_IN_MILLIS - 1, HOUR_IN_MILLIS,
+ "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Today", "Today");
+ test_getRelativeTimeSpanString_helper(12 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Today");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(48 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
+ "In 2 days");
+ test_getRelativeTimeSpanString_helper(45 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
+ "In 2 days");
+ test_getRelativeTimeSpanString_helper(7 * DAY_IN_MILLIS, WEEK_IN_MILLIS, "1 week ago",
+ "In 1 week");
+ test_getRelativeTimeSpanString_helper(14 * DAY_IN_MILLIS - 1, WEEK_IN_MILLIS, "1 week ago",
+ "In 1 week");
+
+ // duration < minResolution
+ test_getRelativeTimeSpanString_helper(59 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS,
+ "0 minutes ago",
+ "In 0 minutes");
+ test_getRelativeTimeSpanString_helper(59 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, "0 hours ago",
+ "In 0 hours");
+ test_getRelativeTimeSpanString_helper(HOUR_IN_MILLIS - 1, HOUR_IN_MILLIS, "0 hours ago",
+ "In 0 hours");
+ test_getRelativeTimeSpanString_helper(DAY_IN_MILLIS - 1, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(20 * SECOND_IN_MILLIS, WEEK_IN_MILLIS, "0 weeks ago",
+ "In 0 weeks");
+ test_getRelativeTimeSpanString_helper(WEEK_IN_MILLIS - 1, WEEK_IN_MILLIS, "0 weeks ago",
+ "In 0 weeks");
+ }
+
+ @Test
+ public void test_getRelativeTimeSpanStringAbbrev() throws Exception {
+ int flags = FORMAT_ABBREV_RELATIVE;
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, 0, flags, "0 sec. ago",
+ "0 sec. ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, flags, "1 min. ago",
+ "In 1 min.");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, 0, flags, "5 days ago",
+ "In 5 days");
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "0 sec. ago", "0 sec. ago");
+ test_getRelativeTimeSpanString_helper(1 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "1 sec. ago", "In 1 sec.");
+ test_getRelativeTimeSpanString_helper(2 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "2 sec. ago", "In 2 sec.");
+ test_getRelativeTimeSpanString_helper(25 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "25 sec. ago", "In 25 sec.");
+ test_getRelativeTimeSpanString_helper(75 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(5000 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+
+ test_getRelativeTimeSpanString_helper(0 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "0 min. ago", "0 min. ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(2 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "2 min. ago", "In 2 min.");
+ test_getRelativeTimeSpanString_helper(25 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "25 min. ago", "In 25 min.");
+ test_getRelativeTimeSpanString_helper(75 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(720 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "12 hr. ago", "In 12 hr.");
+
+ test_getRelativeTimeSpanString_helper(0 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "0 hr. ago", "0 hr. ago");
+ test_getRelativeTimeSpanString_helper(1 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "2 hr. ago", "In 2 hr.");
+ test_getRelativeTimeSpanString_helper(5 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "5 hr. ago", "In 5 hr.");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "20 hr. ago", "In 20 hr.");
+
+ test_getRelativeTimeSpanString_helper(0 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags, "Today",
+ "Today");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(2 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "2 days ago", "In 2 days");
+ test_getRelativeTimeSpanString_helper(25 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "January 11", "March 2");
+
+ test_getRelativeTimeSpanString_helper(0 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "0 wk. ago", "0 wk. ago");
+ test_getRelativeTimeSpanString_helper(1 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "1 wk. ago", "In 1 wk.");
+ test_getRelativeTimeSpanString_helper(2 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "2 wk. ago", "In 2 wk.");
+ test_getRelativeTimeSpanString_helper(25 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "25 wk. ago", "In 25 wk.");
+
+ // duration >= minResolution
+ test_getRelativeTimeSpanString_helper(30 * SECOND_IN_MILLIS, 0, flags, "30 sec. ago",
+ "In 30 sec.");
+ test_getRelativeTimeSpanString_helper(30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "30 min. ago", "In 30 min.");
+ test_getRelativeTimeSpanString_helper(30 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "5 days ago", "In 5 days");
+ test_getRelativeTimeSpanString_helper(30 * WEEK_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "July 10, 2014", "September 3");
+ test_getRelativeTimeSpanString_helper(5 * 365 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "February 6, 2010", "February 4, 2020");
+
+ test_getRelativeTimeSpanString_helper(60 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(120 * SECOND_IN_MILLIS - 1, MINUTE_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(60 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(120 * MINUTE_IN_MILLIS - 1, HOUR_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags, "Today",
+ "Today");
+ test_getRelativeTimeSpanString_helper(12 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Today");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(48 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "2 days ago", "In 2 days");
+ test_getRelativeTimeSpanString_helper(45 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "2 days ago", "In 2 days");
+ test_getRelativeTimeSpanString_helper(7 * DAY_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "1 wk. ago", "In 1 wk.");
+ test_getRelativeTimeSpanString_helper(14 * DAY_IN_MILLIS - 1, WEEK_IN_MILLIS, flags,
+ "1 wk. ago", "In 1 wk.");
+
+ // duration < minResolution
+ test_getRelativeTimeSpanString_helper(59 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "0 min. ago", "In 0 min.");
+ test_getRelativeTimeSpanString_helper(59 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "0 hr. ago", "In 0 hr.");
+ test_getRelativeTimeSpanString_helper(HOUR_IN_MILLIS - 1, HOUR_IN_MILLIS, flags,
+ "0 hr. ago", "In 0 hr.");
+ test_getRelativeTimeSpanString_helper(DAY_IN_MILLIS - 1, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(20 * SECOND_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "0 wk. ago", "In 0 wk.");
+ test_getRelativeTimeSpanString_helper(WEEK_IN_MILLIS - 1, WEEK_IN_MILLIS, flags,
+ "0 wk. ago", "In 0 wk.");
+
+ }
+
+ @Test
+ public void test_getRelativeTimeSpanStringGerman() throws Exception {
+ // Bug: 19744876
+ // We need to specify the timezone and the time explicitly. Otherwise it
+ // may not always give a correct answer of "tomorrow" by using
+ // (now + DAY_IN_MILLIS).
+ Locale de_DE = new Locale("de", "DE");
+ TimeZone tz = TimeZone.getTimeZone("Europe/Berlin");
+ Calendar cal = Calendar.getInstance(tz, de_DE);
+ // Feb 5, 2015 at 10:50 CET
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long now = cal.getTimeInMillis();
+
+ // 42 minutes ago
+ assertEquals("Vor 42 Minuten", getRelativeTimeSpanString(de_DE, tz,
+ now - 42 * MINUTE_IN_MILLIS, now, MINUTE_IN_MILLIS, 0));
+ // In 42 minutes
+ assertEquals("In 42 Minuten", getRelativeTimeSpanString(de_DE, tz,
+ now + 42 * MINUTE_IN_MILLIS, now, MINUTE_IN_MILLIS, 0));
+ // Yesterday
+ assertEquals("Gestern", getRelativeTimeSpanString(de_DE, tz,
+ now - DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day before yesterday
+ assertEquals("Vorgestern", getRelativeTimeSpanString(de_DE, tz,
+ now - 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // Tomorrow
+ assertEquals("Morgen", getRelativeTimeSpanString(de_DE, tz,
+ now + DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day after tomorrow
+ assertEquals("Übermorgen", getRelativeTimeSpanString(de_DE, tz,
+ now + 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ }
+
+ @Test
+ public void test_getRelativeTimeSpanStringFrench() throws Exception {
+ Locale fr_FR = new Locale("fr", "FR");
+ TimeZone tz = TimeZone.getTimeZone("Europe/Paris");
+ Calendar cal = Calendar.getInstance(tz, fr_FR);
+ // Feb 5, 2015 at 10:50 CET
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long now = cal.getTimeInMillis();
+
+ // 42 minutes ago
+ assertEquals("Il y a 42 minutes", getRelativeTimeSpanString(fr_FR, tz,
+ now - (42 * MINUTE_IN_MILLIS), now, MINUTE_IN_MILLIS, 0));
+ // In 42 minutes
+ assertEquals("Dans 42 minutes", getRelativeTimeSpanString(fr_FR, tz,
+ now + (42 * MINUTE_IN_MILLIS), now, MINUTE_IN_MILLIS, 0));
+ // Yesterday
+ assertEquals("Hier", getRelativeTimeSpanString(fr_FR, tz,
+ now - DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day before yesterday
+ assertEquals("Avant-hier", getRelativeTimeSpanString(fr_FR, tz,
+ now - 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // Tomorrow
+ assertEquals("Demain", getRelativeTimeSpanString(fr_FR, tz,
+ now + DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day after tomorrow
+ assertEquals("Après-demain", getRelativeTimeSpanString(fr_FR, tz,
+ now + 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ }
+
+ // Tests adopted from CTS tests for DateUtils.getRelativeDateTimeString.
+ @Test
+ public void test_getRelativeDateTimeStringCTS() throws Exception {
+ Locale en_US = Locale.getDefault();
+ TimeZone tz = TimeZone.getDefault();
+ final long baseTime = System.currentTimeMillis();
+
+ final long DAY_DURATION = 5 * 24 * 60 * 60 * 1000;
+ assertNotNull(getRelativeDateTimeString(en_US, tz, baseTime - DAY_DURATION, baseTime,
+ MINUTE_IN_MILLIS, DAY_IN_MILLIS,
+ FORMAT_NUMERIC_DATE));
+ }
+
+ @Test
+ public void test_getRelativeDateTimeString() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2015 at 10:50 PST
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long base = cal.getTimeInMillis();
+
+ assertEquals("5 seconds ago, 10:49 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * SECOND_IN_MILLIS, base, 0,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("5 min. ago, 10:45 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * MINUTE_IN_MILLIS, base, 0,
+ HOUR_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("0 hr. ago, 10:45 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * MINUTE_IN_MILLIS, base,
+ HOUR_IN_MILLIS, DAY_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("5 hours ago, 5:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * HOUR_IN_MILLIS, base,
+ HOUR_IN_MILLIS, DAY_IN_MILLIS, 0));
+ assertEquals("Yesterday, 7:50 PM",
+ getRelativeDateTimeString(en_US, tz, base - 15 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("5 days ago, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * DAY_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("Jan 29, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 7 * DAY_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2014, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2014, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ YEAR_IN_MILLIS, 0));
+
+ // User-supplied flags should be ignored when formatting the date clause.
+ final int FORMAT_SHOW_WEEKDAY = 0x00002;
+ assertEquals("11/27/2014, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS,
+ FORMAT_ABBREV_ALL | FORMAT_SHOW_WEEKDAY));
+ }
+
+ @Test
+ public void test_getRelativeDateTimeStringDST() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+
+ // DST starts on Mar 9, 2014 at 2:00 AM.
+ // So 5 hours before 3:15 AM should be formatted as 'Yesterday, 9:15 PM'.
+ cal.set(2014, Calendar.MARCH, 9, 3, 15, 0);
+ long base = cal.getTimeInMillis();
+ assertEquals("Yesterday, 9:15 PM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+
+ // 1 hour after 2:00 AM should be formatted as 'In 1 hour, 4:00 AM'.
+ cal.set(2014, Calendar.MARCH, 9, 2, 0, 0);
+ base = cal.getTimeInMillis();
+ assertEquals("In 1 hour, 4:00 AM",
+ getRelativeDateTimeString(en_US, tz, base + 1 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+
+ // DST ends on Nov 2, 2014 at 2:00 AM. Clocks are turned backward 1 hour to
+ // 1:00 AM. 8 hours before 5:20 AM should be 'Yesterday, 10:20 PM'.
+ cal.set(2014, Calendar.NOVEMBER, 2, 5, 20, 0);
+ base = cal.getTimeInMillis();
+ assertEquals("Yesterday, 10:20 PM",
+ getRelativeDateTimeString(en_US, tz, base - 8 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+
+ cal.set(2014, Calendar.NOVEMBER, 2, 0, 45, 0);
+ base = cal.getTimeInMillis();
+ // 45 minutes after 0:45 AM should be 'In 45 minutes, 1:30 AM'.
+ assertEquals("In 45 minutes, 1:30 AM",
+ getRelativeDateTimeString(en_US, tz, base + 45 * MINUTE_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ // 45 minutes later, it should be 'In 45 minutes, 1:15 AM'.
+ assertEquals("In 45 minutes, 1:15 AM",
+ getRelativeDateTimeString(en_US, tz, base + 90 * MINUTE_IN_MILLIS,
+ base + 45 * MINUTE_IN_MILLIS, 0, WEEK_IN_MILLIS, 0));
+ // Another 45 minutes later, it should be 'In 45 minutes, 2:00 AM'.
+ assertEquals("In 45 minutes, 2:00 AM",
+ getRelativeDateTimeString(en_US, tz, base + 135 * MINUTE_IN_MILLIS,
+ base + 90 * MINUTE_IN_MILLIS, 0, WEEK_IN_MILLIS, 0));
+ }
+
+ @Test
+ public void test_getRelativeDateTimeStringItalian() throws Exception {
+ Locale it_IT = new Locale("it", "IT");
+ TimeZone tz = TimeZone.getTimeZone("Europe/Rome");
+ Calendar cal = Calendar.getInstance(tz, it_IT);
+ // 05 febbraio 2015 20:15
+ cal.set(2015, Calendar.FEBRUARY, 5, 20, 15, 0);
+ final long base = cal.getTimeInMillis();
+
+ assertEquals("5 secondi fa, 20:14",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * SECOND_IN_MILLIS, base, 0,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("5 min fa, 20:10",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * MINUTE_IN_MILLIS, base, 0,
+ HOUR_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("0 h fa, 20:10",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * MINUTE_IN_MILLIS, base,
+ HOUR_IN_MILLIS, DAY_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("Ieri, 22:15",
+ getRelativeDateTimeString(it_IT, tz, base - 22 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("5 giorni fa, 20:15",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * DAY_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("27/11/2014, 20:15",
+ getRelativeDateTimeString(it_IT, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ }
+
+ // http://b/5252772: detect the actual date difference
+ @Test
+ public void test5252772() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+
+ // Now is Sep 2, 2011, 10:23 AM PDT.
+ Calendar nowCalendar = Calendar.getInstance(tz, en_US);
+ nowCalendar.set(2011, Calendar.SEPTEMBER, 2, 10, 23, 0);
+ final long now = nowCalendar.getTimeInMillis();
+
+ // Sep 1, 2011, 10:24 AM
+ Calendar yesterdayCalendar1 = Calendar.getInstance(tz, en_US);
+ yesterdayCalendar1.set(2011, Calendar.SEPTEMBER, 1, 10, 24, 0);
+ long yesterday1 = yesterdayCalendar1.getTimeInMillis();
+ assertEquals("Yesterday, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, yesterday1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 1, 2011, 10:22 AM
+ Calendar yesterdayCalendar2 = Calendar.getInstance(tz, en_US);
+ yesterdayCalendar2.set(2011, Calendar.SEPTEMBER, 1, 10, 22, 0);
+ long yesterday2 = yesterdayCalendar2.getTimeInMillis();
+ assertEquals("Yesterday, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, yesterday2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Aug 31, 2011, 10:24 AM
+ Calendar twoDaysAgoCalendar1 = Calendar.getInstance(tz, en_US);
+ twoDaysAgoCalendar1.set(2011, Calendar.AUGUST, 31, 10, 24, 0);
+ long twoDaysAgo1 = twoDaysAgoCalendar1.getTimeInMillis();
+ assertEquals("2 days ago, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysAgo1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Aug 31, 2011, 10:22 AM
+ Calendar twoDaysAgoCalendar2 = Calendar.getInstance(tz, en_US);
+ twoDaysAgoCalendar2.set(2011, Calendar.AUGUST, 31, 10, 22, 0);
+ long twoDaysAgo2 = twoDaysAgoCalendar2.getTimeInMillis();
+ assertEquals("2 days ago, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysAgo2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 3, 2011, 10:22 AM
+ Calendar tomorrowCalendar1 = Calendar.getInstance(tz, en_US);
+ tomorrowCalendar1.set(2011, Calendar.SEPTEMBER, 3, 10, 22, 0);
+ long tomorrow1 = tomorrowCalendar1.getTimeInMillis();
+ assertEquals("Tomorrow, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, tomorrow1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 3, 2011, 10:24 AM
+ Calendar tomorrowCalendar2 = Calendar.getInstance(tz, en_US);
+ tomorrowCalendar2.set(2011, Calendar.SEPTEMBER, 3, 10, 24, 0);
+ long tomorrow2 = tomorrowCalendar2.getTimeInMillis();
+ assertEquals("Tomorrow, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, tomorrow2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 4, 2011, 10:22 AM
+ Calendar twoDaysLaterCalendar1 = Calendar.getInstance(tz, en_US);
+ twoDaysLaterCalendar1.set(2011, Calendar.SEPTEMBER, 4, 10, 22, 0);
+ long twoDaysLater1 = twoDaysLaterCalendar1.getTimeInMillis();
+ assertEquals("In 2 days, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysLater1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 4, 2011, 10:24 AM
+ Calendar twoDaysLaterCalendar2 = Calendar.getInstance(tz, en_US);
+ twoDaysLaterCalendar2.set(2011, Calendar.SEPTEMBER, 4, 10, 24, 0);
+ long twoDaysLater2 = twoDaysLaterCalendar2.getTimeInMillis();
+ assertEquals("In 2 days, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysLater2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+ }
+
+ // b/19822016: show / hide the year based on the dates in the arguments.
+ @Test
+ public void test_bug19822016() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2012 at 10:50 PST
+ cal.set(2012, Calendar.FEBRUARY, 5, 10, 50, 0);
+ long base = cal.getTimeInMillis();
+
+ assertEquals("Feb 5, 5:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 5 * HOUR_IN_MILLIS, base, 0, MINUTE_IN_MILLIS, 0));
+ assertEquals("Jan 29, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 7 * DAY_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2011, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 10 * WEEK_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+ assertEquals("January 6, 2012", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7, 2011", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("December 7, 2011", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+
+ // Feb 5, 2018 at 10:50 PST
+ cal.set(2018, Calendar.FEBRUARY, 5, 10, 50, 0);
+ base = cal.getTimeInMillis();
+ assertEquals("Feb 5, 5:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 5 * HOUR_IN_MILLIS, base, 0, MINUTE_IN_MILLIS, 0));
+ assertEquals("Jan 29, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 7 * DAY_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2017, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 10 * WEEK_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+ assertEquals("January 6, 2018", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7, 2017", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("December 7, 2017", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+ }
+
+ // Check for missing ICU data. http://b/25821045
+ @Test
+ public void test_bug25821045() {
+ final TimeZone tz = TimeZone.getDefault();
+ final long now = System.currentTimeMillis();
+ final long time = now + 1000;
+ final int minResolution = 1000 * 60;
+ final int transitionResolution = minResolution;
+ final int flags = FORMAT_ABBREV_RELATIVE;
+ // Exercise all available locales, forcing the ICU implementation to pre-cache the data.
+ // This
+ // highlights data issues. It can take a while.
+ for (Locale locale : Locale.getAvailableLocales()) {
+ // In (e.g.) ICU56 an exception is thrown on the first use for a locale if required
+ // data for
+ // the "other" plural is missing. It doesn't matter what is actually formatted.
+ try {
+ RelativeDateTimeFormatter.getRelativeDateTimeString(
+ locale, tz, time, now, minResolution, transitionResolution, flags);
+ } catch (IllegalStateException e) {
+ fail("Failed to format for " + locale);
+ }
+ }
+ }
+
+ // Check for ICU data lookup fallback failure. http://b/25883157
+ @Test
+ public void test_bug25883157() {
+ final Locale locale = new Locale("en", "GB");
+ final TimeZone tz = TimeZone.getTimeZone("GMT");
+
+ final Calendar cal = Calendar.getInstance(tz, locale);
+ cal.set(2015, Calendar.JUNE, 19, 12, 0, 0);
+
+ final long base = cal.getTimeInMillis();
+ final long time = base + 2 * WEEK_IN_MILLIS;
+
+ assertEquals("In 2 wk", getRelativeTimeSpanString(
+ locale, tz, time, base, WEEK_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ }
+
+ // http://b/63745717
+ @Test
+ public void test_combineDateAndTime_apostrophe() {
+ final Locale locale = new Locale("fr");
+ android.icu.text.RelativeDateTimeFormatter icuFormatter =
+ android.icu.text.RelativeDateTimeFormatter.getInstance(locale);
+ assertEquals("D à T", icuFormatter.combineDateAndTime("D", "T"));
+ // Ensure single quote ' and curly braces {} are not interpreted in input values.
+ assertEquals("D'x' à T{0}", icuFormatter.combineDateAndTime("D'x'", "T{0}"));
+ }
+}
diff --git a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
index 76aa93f7e8be..edf473eac1b1 100644
--- a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
@@ -16,27 +16,25 @@
package com.android.internal.util;
-import java.util.Collection;
-import java.util.Iterator;
-
import android.os.Debug;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.os.test.TestLooper;
-
-import android.test.suitebuilder.annotation.Suppress;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-import com.android.internal.util.StateMachine.LogRec;
-
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import com.android.internal.util.StateMachine.LogRec;
+
import junit.framework.TestCase;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collection;
+import java.util.Iterator;
+
/**
* Test for StateMachine.
*/
@@ -2013,4 +2011,12 @@ public class StateMachineTest extends TestCase {
private static void tloge(String s) {
Log.e(TAG, s);
}
+
+ public void testDumpDoesNotThrowNpeAfterQuit() {
+ final Hsm1 sm = Hsm1.makeHsm1();
+ sm.quitNow();
+ final StringWriter stringWriter = new StringWriter();
+ final PrintWriter printWriter = new PrintWriter(stringWriter);
+ sm.dump(null, printWriter, new String[0]);
+ }
}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 0d12e1f7f83d..99b5a062e44e 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -50,6 +50,14 @@ prebuilt_etc {
}
prebuilt_etc {
+ name: "privapp_whitelist_com.android.cellbroadcastreceiver",
+ system_ext_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.cellbroadcastreceiver.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
name: "privapp_whitelist_com.android.contacts",
product_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.cellbroadcastreceiver.xml b/data/etc/com.android.cellbroadcastreceiver.xml
new file mode 100644
index 000000000000..dd2df42e442f
--- /dev/null
+++ b/data/etc/com.android.cellbroadcastreceiver.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.cellbroadcastreceiver">
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
+ <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 8699cb491dff..e0fca1e044df 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -352,7 +352,7 @@ key 397 CALENDAR
key 402 CHANNEL_UP
key 403 CHANNEL_DOWN
# key 404 "KEY_FIRST"
-# key 405 "KEY_LAST"
+key 405 LAST_CHANNEL
# key 406 "KEY_AB"
# key 407 "KEY_NEXT"
# key 408 "KEY_RESTART"
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index 52ea8e3b161f..e2bb6a6f4d1a 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -19,7 +19,7 @@
#include <utils/Log.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <android_runtime/AndroidRuntime.h>
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index 493c85a930be..4eb6e420c07f 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -41,19 +41,18 @@ public abstract class IdentityCredential {
/**
* Create an ephemeral key pair to use to establish a secure channel with a reader.
*
- * <p>Most applications will use only the public key, and only to send it to the reader,
- * allowing the private key to be used internally for {@link #encryptMessageToReader(byte[])}
- * and {@link #decryptMessageFromReader(byte[])}. The private key is also provided for
- * applications that wish to use a cipher suite that is not supported by
- * {@link IdentityCredentialStore}.
+ * <p>Applications should use this key-pair for the communications channel with the reader
+ * using a protocol / cipher-suite appropriate for the application. One example of such a
+ * protocol is the one used for Mobile Driving Licenses, see ISO 18013-5 section 9.2.1 "Session
+ * encryption".
*
* @return ephemeral key pair to use to establish a secure channel with a reader.
*/
public @NonNull abstract KeyPair createEphemeralKeyPair();
/**
- * Set the ephemeral public key provided by the reader. This must be called before
- * {@link #encryptMessageToReader} or {@link #decryptMessageFromReader} can be called.
+ * Set the ephemeral public key provided by the reader. If called, this must be called before
+ * {@link #getEntries(byte[], Map, byte[], byte[])} is called.
*
* @param readerEphemeralPublicKey The ephemeral public key provided by the reader to
* establish a secure session.
@@ -65,6 +64,11 @@ public abstract class IdentityCredential {
/**
* Encrypt a message for transmission to the reader.
*
+ * <p>Do not use. In this version of the API, this method produces an incorrect
+ * result. Instead, applications should implement message encryption/decryption themselves as
+ * detailed in the {@link #createEphemeralKeyPair()} method. In a future API-level, this
+ * method will be deprecated.
+ *
* @param messagePlaintext unencrypted message to encrypt.
* @return encrypted message.
*/
@@ -73,6 +77,11 @@ public abstract class IdentityCredential {
/**
* Decrypt a message received from the reader.
*
+ * <p>Do not use. In this version of the API, this method produces an incorrect
+ * result. Instead, applications should implement message encryption/decryption themselves as
+ * detailed in the {@link #createEphemeralKeyPair()} method. In a future API-level, this
+ * method will be deprecated.
+ *
* @param messageCiphertext encrypted message to decrypt.
* @return decrypted message.
* @throws MessageDecryptionException if the ciphertext couldn't be decrypted.
@@ -178,7 +187,7 @@ public abstract class IdentityCredential {
*
* <p>If {@code readerAuth} is not {@code null} it must be the bytes of a {@code COSE_Sign1}
* structure as defined in RFC 8152. For the payload nil shall be used and the
- * detached payload is the ReaderAuthentication CBOR described below.
+ * detached payload is the ReaderAuthenticationBytes CBOR described below.
* <pre>
* ReaderAuthentication = [
* "ReaderAuthentication",
@@ -186,7 +195,9 @@ public abstract class IdentityCredential {
* ItemsRequestBytes
* ]
*
- * ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest) ; Bytes of ItemsRequest
+ * ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest)
+ *
+ * ReaderAuthenticationBytes = #6.24(bstr .cbor ReaderAuthentication)
* </pre>
*
* <p>where {@code ItemsRequestBytes} are the bytes in the {@code requestMessage} parameter.
diff --git a/identity/java/android/security/identity/ResultData.java b/identity/java/android/security/identity/ResultData.java
index 37de2c4a50ea..71860d261285 100644
--- a/identity/java/android/security/identity/ResultData.java
+++ b/identity/java/android/security/identity/ResultData.java
@@ -68,8 +68,8 @@ public abstract class ResultData {
* {@link #getMessageAuthenticationCode()} can be used to get a MAC.
*
* <p>The CBOR structure which is cryptographically authenticated is the
- * {@code DeviceAuthentication} structure according to the following
- * <a href="https://tools.ietf.org/html/draft-ietf-cbor-cddl-06">CDDL</a> schema:
+ * {@code DeviceAuthenticationBytes} structure according to the following
+ * <a href="https://tools.ietf.org/html/rfc8610">CDDL</a> schema:
*
* <pre>
* DeviceAuthentication = [
@@ -80,15 +80,9 @@ public abstract class ResultData {
* ]
*
* DocType = tstr
- *
- * SessionTranscript = [
- * DeviceEngagementBytes,
- * EReaderKeyBytes
- * ]
- *
- * DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement)
- * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub)
+ * SessionTranscript = any
* DeviceNameSpacesBytes = #6.24(bstr .cbor DeviceNameSpaces)
+ * DeviceAuthenticationBytes = #6.24(bstr .cbor DeviceAuthentication)
* </pre>
*
* <p>where
@@ -115,7 +109,7 @@ public abstract class ResultData {
public abstract @NonNull byte[] getAuthenticatedData();
/**
- * Returns a message authentication code over the {@code DeviceAuthentication} CBOR
+ * Returns a message authentication code over the {@code DeviceAuthenticationBytes} CBOR
* specified in {@link #getAuthenticatedData()}, to prove to the reader that the data
* is from a trusted credential.
*
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 7282bcfe4445..62194d84f4f5 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -74,6 +74,15 @@ public class Credentials {
/** Key containing suffix of lockdown VPN profile. */
public static final String LOCKDOWN_VPN = "LOCKDOWN_VPN";
+ /** Name of CA certificate usage. */
+ public static final String CERTIFICATE_USAGE_CA = "ca";
+
+ /** Name of User certificate usage. */
+ public static final String CERTIFICATE_USAGE_USER = "user";
+
+ /** Name of WIFI certificate usage. */
+ public static final String CERTIFICATE_USAGE_WIFI = "wifi";
+
/** Data type for public keys. */
public static final String EXTRA_PUBLIC_KEY = "KEY";
@@ -94,19 +103,19 @@ public class Credentials {
public static final String EXTRA_INSTALL_AS_UID = "install_as_uid";
/**
- * Intent extra: name for the user's private key.
+ * Intent extra: type of the certificate to install
*/
- public static final String EXTRA_USER_PRIVATE_KEY_NAME = "user_private_key_name";
+ public static final String EXTRA_CERTIFICATE_USAGE = "certificate_install_usage";
/**
- * Intent extra: data for the user's private key in PEM-encoded PKCS#8.
+ * Intent extra: name for the user's key pair.
*/
- public static final String EXTRA_USER_PRIVATE_KEY_DATA = "user_private_key_data";
+ public static final String EXTRA_USER_KEY_ALIAS = "user_key_pair_name";
/**
- * Intent extra: name for the user's certificate.
+ * Intent extra: data for the user's private key in PEM-encoded PKCS#8.
*/
- public static final String EXTRA_USER_CERTIFICATE_NAME = "user_certificate_name";
+ public static final String EXTRA_USER_PRIVATE_KEY_DATA = "user_private_key_data";
/**
* Intent extra: data for the user's certificate in PEM-encoded X.509.
@@ -114,11 +123,6 @@ public class Credentials {
public static final String EXTRA_USER_CERTIFICATE_DATA = "user_certificate_data";
/**
- * Intent extra: name for CA certificate chain
- */
- public static final String EXTRA_CA_CERTIFICATES_NAME = "ca_certificates_name";
-
- /**
* Intent extra: data for CA certificate chain in PEM-encoded X.509.
*/
public static final String EXTRA_CA_CERTIFICATES_DATA = "ca_certificates_data";
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index b3cdff7eedf7..97da3cc6f80f 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -43,7 +43,8 @@ interface IKeyChainService {
String installCaCertificate(in byte[] caCertificate);
// APIs used by DevicePolicyManager
- boolean installKeyPair(in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias);
+ boolean installKeyPair(
+ in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias, int uid);
boolean removeKeyPair(String alias);
// APIs used by Settings
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 1829d2f406b4..254456cea536 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -343,6 +343,16 @@ public final class KeyChain {
public static final int KEY_ATTESTATION_FAILURE = 4;
/**
+ * Used by DPC or delegated app in
+ * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias} or
+ * {@link android.app.admin.DelegatedAdminReceiver#onChoosePrivateKeyAlias} to identify that
+ * the requesting app is not granted access to any key, and nor will the user be able to grant
+ * access manually.
+ */
+ public static final String KEY_ALIAS_SELECTION_DENIED =
+ "android:alias-selection-denied";
+
+ /**
* Returns an {@code Intent} that can be used for credential
* installation. The intent may be used without any extras, in
* which case the user will be able to install credentials from
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 11775caa8ad4..6e389389fbc0 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -31,7 +31,6 @@ import com.android.org.bouncycastle.asn1.ASN1InputStream;
import com.android.org.bouncycastle.asn1.ASN1Integer;
import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
import com.android.org.bouncycastle.asn1.DERBitString;
-import com.android.org.bouncycastle.asn1.DERInteger;
import com.android.org.bouncycastle.asn1.DERNull;
import com.android.org.bouncycastle.asn1.DERSequence;
import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -699,8 +698,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256;
sigAlgId = new AlgorithmIdentifier(sigAlgOid);
ASN1EncodableVector v = new ASN1EncodableVector();
- v.add(new DERInteger(0));
- v.add(new DERInteger(0));
+ v.add(new ASN1Integer(BigInteger.valueOf(0)));
+ v.add(new ASN1Integer(BigInteger.valueOf(0)));
signature = new DERSequence().getEncoded();
break;
case KeymasterDefs.KM_ALGORITHM_RSA:
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 5c2ef15cbd1e..5e480a66c355 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -24,37 +24,10 @@
#include <log/log.h>
-#include <SkBitmap.h>
-#include <SkCanvas.h>
-#include <SkColor.h>
-#include <SkPaint.h>
-#include <SkBlendMode.h>
+#include <memory>
namespace android {
-// --- WeakLooperCallback ---
-
-class WeakLooperCallback: public LooperCallback {
-protected:
- virtual ~WeakLooperCallback() { }
-
-public:
- explicit WeakLooperCallback(const wp<LooperCallback>& callback) :
- mCallback(callback) {
- }
-
- virtual int handleEvent(int fd, int events, void* data) {
- sp<LooperCallback> callback = mCallback.promote();
- if (callback != NULL) {
- return callback->handleEvent(fd, events, data);
- }
- return 0; // the client is gone, remove the callback
- }
-
-private:
- wp<LooperCallback> mCallback;
-};
-
// --- PointerController ---
// Time to wait before starting the fade when the pointer is inactive.
@@ -70,29 +43,50 @@ static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
// The number of events to be read at once for DisplayEventReceiver.
static const int EVENT_BUFFER_SIZE = 100;
-// --- PointerController ---
-
-PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
- mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
- mHandler = new WeakMessageHandler(this);
- mCallback = new WeakLooperCallback(this);
-
- if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
- mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
- Looper::EVENT_INPUT, mCallback, nullptr);
+std::shared_ptr<PointerController> PointerController::create(
+ const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController) {
+ std::shared_ptr<PointerController> controller = std::shared_ptr<PointerController>(
+ new PointerController(policy, looper, spriteController));
+
+ /*
+ * Now we need to hook up the constructed PointerController object to its callbacks.
+ *
+ * This must be executed after the constructor but before any other methods on PointerController
+ * in order to ensure that the fully constructed object is visible on the Looper thread, since
+ * that may be a different thread than where the PointerController is initially constructed.
+ *
+ * Unfortunately, this cannot be done as part of the constructor since we need to hand out
+ * weak_ptr's which themselves cannot be constructed until there's at least one shared_ptr.
+ */
+
+ controller->mHandler->pointerController = controller;
+ controller->mCallback->pointerController = controller;
+ if (controller->mDisplayEventReceiver.initCheck() == NO_ERROR) {
+ controller->mLooper->addFd(controller->mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
+ Looper::EVENT_INPUT, controller->mCallback, nullptr);
} else {
ALOGE("Failed to initialize DisplayEventReceiver.");
}
+ return controller;
+}
+PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
+ const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController)
+ : mPolicy(policy),
+ mLooper(looper),
+ mSpriteController(spriteController),
+ mHandler(new MessageHandler()),
+ mCallback(new LooperCallback()) {
AutoMutex _l(mLock);
mLocked.animationPending = false;
- mLocked.presentation = PRESENTATION_POINTER;
+ mLocked.presentation = Presentation::POINTER;
mLocked.presentationChanged = false;
- mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL;
+ mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
mLocked.pointerFadeDirection = 0;
mLocked.pointerX = 0;
@@ -227,7 +221,7 @@ void PointerController::fade(Transition transition) {
removeInactivityTimeoutLocked();
// Start fading.
- if (transition == TRANSITION_IMMEDIATE) {
+ if (transition == Transition::IMMEDIATE) {
mLocked.pointerFadeDirection = 0;
mLocked.pointerAlpha = 0.0f;
updatePointerLocked();
@@ -244,7 +238,7 @@ void PointerController::unfade(Transition transition) {
resetInactivityTimeoutLocked();
// Start unfading.
- if (transition == TRANSITION_IMMEDIATE) {
+ if (transition == Transition::IMMEDIATE) {
mLocked.pointerFadeDirection = 0;
mLocked.pointerAlpha = 1.0f;
updatePointerLocked();
@@ -268,7 +262,7 @@ void PointerController::setPresentation(Presentation presentation) {
return;
}
- if (presentation == PRESENTATION_POINTER) {
+ if (presentation == Presentation::POINTER) {
if (mLocked.additionalMouseResources.empty()) {
mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
&mLocked.animationResources,
@@ -486,24 +480,35 @@ void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
updatePointerLocked();
}
-void PointerController::handleMessage(const Message& message) {
+void PointerController::MessageHandler::handleMessage(const Message& message) {
+ std::shared_ptr<PointerController> controller = pointerController.lock();
+
+ if (controller == nullptr) {
+ ALOGE("PointerController instance was released before processing message: what=%d",
+ message.what);
+ return;
+ }
switch (message.what) {
case MSG_INACTIVITY_TIMEOUT:
- doInactivityTimeout();
+ controller->doInactivityTimeout();
break;
}
}
-int PointerController::handleEvent(int /* fd */, int events, void* /* data */) {
+int PointerController::LooperCallback::handleEvent(int /* fd */, int events, void* /* data */) {
+ std::shared_ptr<PointerController> controller = pointerController.lock();
+ if (controller == nullptr) {
+ ALOGW("PointerController instance was released with pending callbacks. events=0x%x",
+ events);
+ return 0; // Remove the callback, the PointerController is gone anyways
+ }
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
- ALOGE("Display event receiver pipe was closed or an error occurred. "
- "events=0x%x", events);
+ ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x", events);
return 0; // remove the callback
}
if (!(events & Looper::EVENT_INPUT)) {
- ALOGW("Received spurious callback for unhandled poll event. "
- "events=0x%x", events);
+ ALOGW("Received spurious callback for unhandled poll event. events=0x%x", events);
return 1; // keep the callback
}
@@ -511,7 +516,7 @@ int PointerController::handleEvent(int /* fd */, int events, void* /* data */) {
ssize_t n;
nsecs_t timestamp;
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
- while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
+ while ((n = controller->mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
timestamp = buf[i].header.timestamp;
@@ -520,7 +525,7 @@ int PointerController::handleEvent(int /* fd */, int events, void* /* data */) {
}
}
if (gotVsync) {
- doAnimate(timestamp);
+ controller->doAnimate(timestamp);
}
return 1; // keep the callback
}
@@ -619,7 +624,7 @@ bool PointerController::doBitmapAnimationLocked(nsecs_t timestamp) {
}
void PointerController::doInactivityTimeout() {
- fade(TRANSITION_GRADUAL);
+ fade(Transition::GRADUAL);
}
void PointerController::startAnimationLocked() {
@@ -633,8 +638,9 @@ void PointerController::startAnimationLocked() {
void PointerController::resetInactivityTimeoutLocked() {
mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
- nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT
- ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
+ nsecs_t timeout = mLocked.inactivityTimeout == InactivityTimeout::SHORT
+ ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT
+ : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
}
@@ -661,7 +667,7 @@ void PointerController::updatePointerLocked() REQUIRES(mLock) {
}
if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
- if (mLocked.presentation == PRESENTATION_POINTER) {
+ if (mLocked.presentation == Presentation::POINTER) {
if (mLocked.requestedPointerType == mPolicy->getDefaultPointerIconId()) {
mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
} else {
@@ -737,7 +743,7 @@ PointerController::Spot* PointerController::removeFirstFadingSpotLocked(std::vec
return spot;
}
}
- return NULL;
+ return nullptr;
}
void PointerController::releaseSpotLocked(Spot* spot) {
@@ -778,7 +784,7 @@ void PointerController::loadResourcesLocked() REQUIRES(mLock) {
mLocked.additionalMouseResources.clear();
mLocked.animationResources.clear();
- if (mLocked.presentation == PRESENTATION_POINTER) {
+ if (mLocked.presentation == Presentation::POINTER) {
mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
&mLocked.animationResources, mLocked.viewport.displayId);
}
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index ebc622bae302..14c0679654c6 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -17,19 +17,20 @@
#ifndef _UI_POINTER_CONTROLLER_H
#define _UI_POINTER_CONTROLLER_H
-#include "SpriteController.h"
-
-#include <map>
-#include <vector>
-
-#include <ui/DisplayInfo.h>
+#include <PointerControllerInterface.h>
+#include <gui/DisplayEventReceiver.h>
#include <input/DisplayViewport.h>
#include <input/Input.h>
-#include <PointerControllerInterface.h>
+#include <ui/DisplayInfo.h>
#include <utils/BitSet.h>
-#include <utils/RefBase.h>
#include <utils/Looper.h>
-#include <gui/DisplayEventReceiver.h>
+#include <utils/RefBase.h>
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "SpriteController.h"
namespace android {
@@ -70,25 +71,22 @@ public:
virtual int32_t getCustomPointerIconId() = 0;
};
-
/*
* Tracks pointer movements and draws the pointer sprite to a surface.
*
* Handles pointer acceleration and animation.
*/
-class PointerController : public PointerControllerInterface, public MessageHandler,
- public LooperCallback {
-protected:
- virtual ~PointerController();
-
+class PointerController : public PointerControllerInterface {
public:
- enum InactivityTimeout {
- INACTIVITY_TIMEOUT_NORMAL = 0,
- INACTIVITY_TIMEOUT_SHORT = 1,
+ static std::shared_ptr<PointerController> create(
+ const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController);
+ enum class InactivityTimeout {
+ NORMAL = 0,
+ SHORT = 1,
};
- PointerController(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper, const sp<SpriteController>& spriteController);
+ virtual ~PointerController();
virtual bool getBounds(float* outMinX, float* outMinY,
float* outMaxX, float* outMaxY) const;
@@ -113,8 +111,8 @@ public:
void reloadPointerResources();
private:
- static const size_t MAX_RECYCLED_SPRITES = 12;
- static const size_t MAX_SPOTS = 12;
+ static constexpr size_t MAX_RECYCLED_SPRITES = 12;
+ static constexpr size_t MAX_SPOTS = 12;
enum {
MSG_INACTIVITY_TIMEOUT,
@@ -130,8 +128,13 @@ private:
float x, y;
inline Spot(uint32_t id, const sp<Sprite>& sprite)
- : id(id), sprite(sprite), alpha(1.0f), scale(1.0f),
- x(0.0f), y(0.0f), lastIcon(NULL) { }
+ : id(id),
+ sprite(sprite),
+ alpha(1.0f),
+ scale(1.0f),
+ x(0.0f),
+ y(0.0f),
+ lastIcon(nullptr) {}
void updateSprite(const SpriteIcon* icon, float x, float y, int32_t displayId);
@@ -139,12 +142,24 @@ private:
const SpriteIcon* lastIcon;
};
+ class MessageHandler : public virtual android::MessageHandler {
+ public:
+ void handleMessage(const Message& message) override;
+ std::weak_ptr<PointerController> pointerController;
+ };
+
+ class LooperCallback : public virtual android::LooperCallback {
+ public:
+ int handleEvent(int fd, int events, void* data) override;
+ std::weak_ptr<PointerController> pointerController;
+ };
+
mutable Mutex mLock;
sp<PointerControllerPolicyInterface> mPolicy;
sp<Looper> mLooper;
sp<SpriteController> mSpriteController;
- sp<WeakMessageHandler> mHandler;
+ sp<MessageHandler> mHandler;
sp<LooperCallback> mCallback;
DisplayEventReceiver mDisplayEventReceiver;
@@ -181,14 +196,15 @@ private:
int32_t buttonState;
std::map<int32_t /* displayId */, std::vector<Spot*>> spotsByDisplay;
- std::vector<sp<Sprite> > recycledSprites;
+ std::vector<sp<Sprite>> recycledSprites;
} mLocked GUARDED_BY(mLock);
+ PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController);
+
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
void setPositionLocked(float x, float y);
- void handleMessage(const Message& message);
- int handleEvent(int fd, int events, void* data);
void doAnimate(nsecs_t timestamp);
bool doFadingAnimationLocked(nsecs_t timestamp);
bool doBitmapAnimationLocked(nsecs_t timestamp);
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index a15742671dc7..6e129a064385 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -136,7 +136,7 @@ protected:
sp<MockSprite> mPointerSprite;
sp<MockPointerControllerPolicyInterface> mPolicy;
sp<MockSpriteController> mSpriteController;
- sp<PointerController> mPointerController;
+ std::shared_ptr<PointerController> mPointerController;
private:
void loopThread();
@@ -160,7 +160,7 @@ PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<Moc
EXPECT_CALL(*mSpriteController, createSprite())
.WillOnce(Return(mPointerSprite));
- mPointerController = new PointerController(mPolicy, mLooper, mSpriteController);
+ mPointerController = PointerController::create(mPolicy, mLooper, mSpriteController);
}
PointerControllerTest::~PointerControllerTest() {
@@ -193,7 +193,7 @@ void PointerControllerTest::loopThread() {
TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
ensureDisplayViewportIsSet();
- mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+ mPointerController->unfade(PointerController::Transition::IMMEDIATE);
std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT);
EXPECT_CALL(*mPointerSprite, setVisible(true));
@@ -208,7 +208,7 @@ TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
TEST_F(PointerControllerTest, updatePointerIcon) {
ensureDisplayViewportIsSet();
- mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+ mPointerController->unfade(PointerController::Transition::IMMEDIATE);
int32_t type = CURSOR_TYPE_ADDITIONAL;
std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type);
@@ -224,7 +224,7 @@ TEST_F(PointerControllerTest, updatePointerIcon) {
TEST_F(PointerControllerTest, setCustomPointerIcon) {
ensureDisplayViewportIsSet();
- mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+ mPointerController->unfade(PointerController::Transition::IMMEDIATE);
int32_t style = CURSOR_TYPE_CUSTOM;
float hotSpotX = 15;
@@ -246,13 +246,13 @@ TEST_F(PointerControllerTest, setCustomPointerIcon) {
}
TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) {
- mPointerController->setPresentation(PointerController::PRESENTATION_POINTER);
+ mPointerController->setPresentation(PointerController::Presentation::POINTER);
mPointerController->setSpots(nullptr, nullptr, BitSet32(), -1);
mPointerController->clearSpots();
mPointerController->setPosition(1.0f, 1.0f);
mPointerController->move(1.0f, 1.0f);
- mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
- mPointerController->fade(PointerController::TRANSITION_IMMEDIATE);
+ mPointerController->unfade(PointerController::Transition::IMMEDIATE);
+ mPointerController->fade(PointerController::Transition::IMMEDIATE);
EXPECT_TRUE(mPolicy->noResourcesAreLoaded());
diff --git a/media/jni/android_media_JetPlayer.cpp b/media/jni/android_media_JetPlayer.cpp
index 8a05f85e4285..481f80b278f8 100644
--- a/media/jni/android_media_JetPlayer.cpp
+++ b/media/jni/android_media_JetPlayer.cpp
@@ -23,7 +23,7 @@
#include <fcntl.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "core_jni_helpers.h"
#include <utils/Log.h>
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index f5ae9d0d5d2f..0d395e58a3c5 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -28,7 +28,7 @@
#include "android_runtime/Log.h"
#include "android_util_Binder.h"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android/hardware/cas/1.0/BpHwCas.h>
#include <android/hardware/cas/1.0/BnHwCas.h>
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index a4807843d7d8..91cd6d3826f6 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -30,7 +30,7 @@
#include <private/media/VideoFrame.h>
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_media_MediaDataSource.h"
#include "android_media_Streams.h"
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index f0aa4c3f1ab6..243ee4f7ebba 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -21,7 +21,7 @@
#include "android_media_Streams.h"
#include "android_runtime/AndroidRuntime.h"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <unistd.h>
#include <fcntl.h>
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index ec0ce8759571..52e266129875 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -32,7 +32,7 @@
#include <fcntl.h>
#include <utils/threads.h>
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
#include "android_runtime/Log.h"
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 24fff0635238..a70de6d6f5d3 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -37,7 +37,7 @@
#include <nativehelper/ScopedUtfChars.h>
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "android_media_AudioErrors.h"
#include "android_media_MediaMetricsJNI.h"
#include "android_media_MicrophoneInfo.h"
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 58044c0307eb..1fb0faa5cd58 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -24,7 +24,7 @@
#include <private/media/VideoFrame.h>
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
#include <android-base/macros.h> // for FALLTHROUGH_INTENDED
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 39ff04ab2a0a..8a1ae9252ca3 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -25,7 +25,7 @@
#include <utils/threads.h>
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include "private/android_filesystem_config.h"
diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp
index efeb3352d393..f4d65d0a397f 100644
--- a/media/jni/audioeffect/Visualizer.cpp
+++ b/media/jni/audioeffect/Visualizer.cpp
@@ -25,6 +25,7 @@
#include <limits.h>
#include <audio_utils/fixedfft.h>
+#include <cutils/bitops.h>
#include <utils/Thread.h>
#include "Visualizer.h"
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index f6706369f379..bfecd6b30179 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -21,7 +21,7 @@
#include <utils/Log.h>
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include "SoundPool.h"
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 3ad076f60c08..c55eeeb50b26 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -40944,6 +40944,7 @@ package android.security {
field public static final String EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS";
field public static final String EXTRA_NAME = "name";
field public static final String EXTRA_PKCS12 = "PKCS12";
+ field public static final String KEY_ALIAS_SELECTION_DENIED = "android:alias-selection-denied";
}
public interface KeyChainAliasCallback {
@@ -44999,7 +45000,7 @@ package android.telephony {
public abstract class CellLocation {
ctor public CellLocation();
method public static android.telephony.CellLocation getEmpty();
- method public static void requestLocationUpdate();
+ method @Deprecated public static void requestLocationUpdate();
}
public abstract class CellSignalStrength {
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 231809bfece4..e5fd0ba5d9bc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -32,12 +32,11 @@ import androidx.annotation.VisibleForTesting;
import androidx.core.text.BidiFormatter;
import androidx.core.text.TextDirectionHeuristicsCompat;
+import com.android.i18n.timezone.CountryTimeZones;
+import com.android.i18n.timezone.CountryTimeZones.TimeZoneMapping;
+import com.android.i18n.timezone.TimeZoneFinder;
import com.android.settingslib.R;
-import libcore.timezone.CountryTimeZones;
-import libcore.timezone.CountryTimeZones.TimeZoneMapping;
-import libcore.timezone.TimeZoneFinder;
-
import org.xmlpull.v1.XmlPullParserException;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 17481bf601e1..c8aa22fc28f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -640,8 +640,7 @@ public class MobileSignalController extends SignalController<
+ " dataState=" + state.getDataRegistrationState());
}
mServiceState = state;
- // onDisplayInfoChanged is invoked directly after onServiceStateChanged, so not calling
- // updateTelephony() to prevent icon flickering in case of overrides.
+ updateTelephony();
}
@Override
@@ -651,10 +650,6 @@ public class MobileSignalController extends SignalController<
+ " type=" + networkType);
}
mDataState = state;
- if (networkType != mTelephonyDisplayInfo.getNetworkType()) {
- mTelephonyDisplayInfo = new TelephonyDisplayInfo(networkType,
- TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
- }
updateTelephony();
}
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 4116afca9816..f89ee24f9594 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -27,7 +27,8 @@ java_defaults {
"androidx.annotation_annotation",
"netd_aidl_interface-unstable-java",
"netlink-client",
- "networkstack-aidl-interfaces-java",
+ // TODO: use networkstack-client instead of just including the AIDL interface
+ "networkstack-aidl-interfaces-unstable-java",
"android.hardware.tetheroffload.config-V1.0-java",
"android.hardware.tetheroffload.control-V1.0-java",
"net-utils-framework-common",
diff --git a/packages/Tethering/common/TetheringLib/api/module-lib-current.txt b/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
index 754584e70fad..6ddb122936e7 100644
--- a/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
+++ b/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
@@ -1,24 +1,6 @@
// Signature format: 2.0
package android.net {
- public final class TetheredClient implements android.os.Parcelable {
- ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
- method public int describeContents();
- method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
- method @NonNull public android.net.MacAddress getMacAddress();
- method public int getTetheringType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
- }
-
- public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.LinkAddress getAddress();
- method @Nullable public String getHostname();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
- }
-
public final class TetheringConstants {
field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
@@ -38,69 +20,15 @@ package android.net {
method @NonNull public String[] getTetheringErroredIfaces();
method public boolean isTetheringSupported();
method public boolean isTetheringSupported(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
method @Deprecated public int setUsbTethering(boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
method @Deprecated public int tether(@NonNull String);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
method @Deprecated public int untether(@NonNull String);
- field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
- field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
- field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
- field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
- field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_ETHERNET = 5; // 0x5
- field public static final int TETHERING_INVALID = -1; // 0xffffffff
- field public static final int TETHERING_NCM = 4; // 0x4
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field public static final int TETHERING_WIFI_P2P = 3; // 0x3
- field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
- field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
- field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
- field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
- field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
- field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
- field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
- field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
- field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
- field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
- field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
- field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
- field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
- field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
- field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
- field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
- field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
- field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
- field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
- }
-
- public static interface TetheringManager.OnTetheringEntitlementResultListener {
- method public void onTetheringEntitlementResult(int);
- }
-
- public static interface TetheringManager.StartTetheringCallback {
- method public default void onTetheringFailed(int);
- method public default void onTetheringStarted();
}
public static interface TetheringManager.TetheringEventCallback {
- method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
- method public default void onError(@NonNull String, int);
- method public default void onOffloadStatusChanged(int);
method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
- method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheringSupported(boolean);
- method public default void onUpstreamChanged(@Nullable android.net.Network);
}
public static class TetheringManager.TetheringInterfaceRegexps {
@@ -109,21 +37,5 @@ package android.net {
method @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
}
- public static class TetheringManager.TetheringRequest {
- method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
- method @Nullable public android.net.LinkAddress getLocalIpv4Address();
- method public boolean getShouldShowEntitlementUi();
- method public int getTetheringType();
- method public boolean isExemptFromEntitlementCheck();
- }
-
- public static class TetheringManager.TetheringRequest.Builder {
- ctor public TetheringManager.TetheringRequest.Builder(int);
- method @NonNull public android.net.TetheringManager.TetheringRequest build();
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
- }
-
}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
index 48be0d96425c..645b00001330 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
@@ -16,8 +16,6 @@
package android.net;
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -36,7 +34,6 @@ import java.util.Objects;
* @hide
*/
@SystemApi
-@SystemApi(client = MODULE_LIBRARIES)
@TestApi
public final class TetheredClient implements Parcelable {
@NonNull
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 87e5c1e52198..49c7fe20660d 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -55,7 +55,6 @@ import java.util.function.Supplier;
* @hide
*/
@SystemApi
-@SystemApi(client = MODULE_LIBRARIES)
@TestApi
public class TetheringManager {
private static final String TAG = TetheringManager.class.getSimpleName();
diff --git a/packages/Tethering/jarjar-rules.txt b/packages/Tethering/jarjar-rules.txt
index e90a2ccaa2a3..2c4059dda9b5 100644
--- a/packages/Tethering/jarjar-rules.txt
+++ b/packages/Tethering/jarjar-rules.txt
@@ -12,6 +12,9 @@ rule com.android.internal.util.State* com.android.networkstack.tethering.util.St
rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1
rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1
-rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1
+rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1
rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1
+
+# Classes from net-utils-framework-common
+rule com.android.net.module.util.** com.android.networkstack.tethering.util.@1 \ No newline at end of file
diff --git a/packages/Tethering/jni/android_net_util_TetheringUtils.cpp b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
index 549344064405..f6eb40a842d5 100644
--- a/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
+++ b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
@@ -18,6 +18,7 @@
#include <error.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIHelpCompat.h>
#include <nativehelper/ScopedUtfChars.h>
#include <net/if.h>
#include <netinet/icmp6.h>
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
index 593d04a06b93..a0198cc9c126 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
@@ -273,8 +273,9 @@ public class TetheringNotificationUpdater {
mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
0 /* requestCode */,
new Intent(Settings.ACTION_TETHER_SETTINGS)
- .setPackage(getSettingsPackageName(mContext.getPackageManager())),
- Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE,
+ .setPackage(getSettingsPackageName(mContext.getPackageManager()))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
+ PendingIntent.FLAG_IMMUTABLE,
null /* options */);
showNotification(R.drawable.stat_sys_tether_general, title, message,
@@ -317,8 +318,9 @@ public class TetheringNotificationUpdater {
mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
0 /* requestCode */,
new Intent(Settings.ACTION_TETHER_SETTINGS)
- .setPackage(getSettingsPackageName(mContext.getPackageManager())),
- Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE,
+ .setPackage(getSettingsPackageName(mContext.getPackageManager()))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
+ PendingIntent.FLAG_IMMUTABLE,
null /* options */);
showNotification(R.drawable.stat_sys_tether_general, title, message,
diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 74df11370e50..9bb01ae5df1d 100644
--- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -42,6 +42,7 @@ import android.net.dhcp.DhcpPacket;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.system.Os;
import android.util.Log;
@@ -101,17 +102,21 @@ public class EthernetTetheringTest {
private UiAutomation mUiAutomation =
InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ private boolean mRunTests;
@Before
public void setUp() throws Exception {
- mHandlerThread = new HandlerThread(getClass().getSimpleName());
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
- mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm);
// Needed to create a TestNetworkInterface, to call requestTetheredInterface, and to receive
// tethered client callbacks.
mUiAutomation.adoptShellPermissionIdentity(
MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED);
+ mRunTests = mTm.isTetheringSupported() && mEm != null;
+ assumeTrue(mRunTests);
+
+ mHandlerThread = new HandlerThread(getClass().getSimpleName());
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm);
}
private void cleanUp() throws Exception {
@@ -135,7 +140,7 @@ public class EthernetTetheringTest {
@After
public void tearDown() throws Exception {
try {
- cleanUp();
+ if (mRunTests) cleanUp();
} finally {
mUiAutomation.dropShellPermissionIdentity();
}
@@ -224,9 +229,19 @@ public class EthernetTetheringTest {
}
+ private boolean isAdbOverNetwork() {
+ // If adb TCP port opened, this test may running by adb over network.
+ return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1)
+ || (SystemProperties.getInt("service.adb.tcp.port", -1) > -1);
+ }
+
@Test
public void testPhysicalEthernet() throws Exception {
assumeTrue(mEm.isAvailable());
+ // Do not run this test if adb is over network and ethernet is connected.
+ // It is likely the adb run over ethernet, the adb would break when ethernet is switching
+ // from client mode to server mode. See b/160389275.
+ assumeFalse(isAdbOverNetwork());
// Get an interface to use.
final String iface = mTetheredInterfaceRequester.getInterface();
diff --git a/packages/Tethering/tests/privileged/Android.bp b/packages/Tethering/tests/privileged/Android.bp
new file mode 100644
index 000000000000..a0fb24603a93
--- /dev/null
+++ b/packages/Tethering/tests/privileged/Android.bp
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+android_test {
+ name: "TetheringPrivilegedTests",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ certificate: "networkstack",
+ platform_apis: true,
+ test_suites: [
+ "general-tests",
+ "mts",
+ ],
+ compile_multilib: "both",
+}
diff --git a/packages/Tethering/tests/privileged/AndroidManifest.xml b/packages/Tethering/tests/privileged/AndroidManifest.xml
new file mode 100644
index 000000000000..49eba15d13d4
--- /dev/null
+++ b/packages/Tethering/tests/privileged/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.networkstack.tethering.tests.privileged"
+ android:sharedUserId="android.uid.networkstack">
+
+ <!-- Note: do not add any privileged or signature permissions that are granted
+ to the network stack and its shared uid apps. Otherwise, the test APK will
+ install, but when the device is rebooted, it will bootloop because this
+ test APK is not in the privileged permission allow list -->
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.networkstack.tethering.tests.privileged"
+ android:label="Tethering privileged tests">
+ </instrumentation>
+</manifest>
diff --git a/packages/Tethering/tests/unit/jarjar-rules.txt b/packages/Tethering/tests/unit/jarjar-rules.txt
index 1ea56cdf1a3d..ec2d2b02004e 100644
--- a/packages/Tethering/tests/unit/jarjar-rules.txt
+++ b/packages/Tethering/tests/unit/jarjar-rules.txt
@@ -8,4 +8,4 @@ rule com.android.internal.util.State* com.android.networkstack.tethering.util.St
rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1
rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1
-rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1
+rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1
diff --git a/packages/services/PacProcessor/AndroidManifest.xml b/packages/services/PacProcessor/AndroidManifest.xml
index 6740c169ff21..ad1326194a4d 100644
--- a/packages/services/PacProcessor/AndroidManifest.xml
+++ b/packages/services/PacProcessor/AndroidManifest.xml
@@ -5,7 +5,9 @@
<uses-permission android:name="android.permission.INTERNET" />
<application
- android:label="@string/app_name">
+ android:label="@string/app_name"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
<service android:name=".PacService"
android:exported="true">
diff --git a/packages/services/PacProcessor/src/com/android/net/IProxyService.aidl b/packages/services/PacProcessor/src/com/android/net/IProxyService.aidl
index 4e54aba5c3bf..1bbc90d604f9 100644
--- a/packages/services/PacProcessor/src/com/android/net/IProxyService.aidl
+++ b/packages/services/PacProcessor/src/com/android/net/IProxyService.aidl
@@ -21,7 +21,4 @@ interface IProxyService
String resolvePacFile(String host, String url);
oneway void setPacFile(String scriptContents);
-
- oneway void startPacSystem();
- oneway void stopPacSystem();
}
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
index b006d6e1fa7b..3c25bfd380f2 100644
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
@@ -83,15 +83,5 @@ public class PacService extends Service {
}
mPacNative.setCurrentProxyScript(script);
}
-
- @Override
- public void startPacSystem() throws RemoteException {
- //TODO: remove
- }
-
- @Override
- public void stopPacSystem() throws RemoteException {
- //TODO: remove
- }
}
}
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 0854b9582187..def67ceb596f 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -19,10 +19,10 @@ LOCAL_SHARED_LIBRARIES := \
libjnigraphics
LOCAL_HEADER_LIBRARIES := \
+ jni_headers \
libbase_headers
LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE) \
frameworks/rs
LOCAL_CFLAGS += -Wno-unused-parameter
diff --git a/services/Android.bp b/services/Android.bp
index 57d9a3850e86..dc948e95076c 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -111,7 +111,6 @@ droidstubs {
" --hide InternalClasses" + // com.android.* classes are okay in this interface
// TODO: remove the --hide options below
" --hide-package com.google.android.startop.iorap" +
- " --hide ReferencesHidden" +
" --hide DeprecationMismatch" +
" --hide HiddenTypedefConstant",
visibility: ["//visibility:private"],
@@ -144,4 +143,7 @@ java_library {
srcs: [":services-stubs.sources"],
installable: false,
static_libs: ["android_module_lib_stubs_current"],
+ sdk_version: "none",
+ system_modules: "none",
+ java_version: "1.8",
}
diff --git a/services/backup/OWNERS b/services/backup/OWNERS
index 9c21e8fe5e45..7c7e74285bf5 100644
--- a/services/backup/OWNERS
+++ b/services/backup/OWNERS
@@ -1,9 +1,12 @@
+# Bug component: 656484
+
+aabhinav@google.com
alsutton@google.com
-anniemeng@google.com
-brufino@google.com
bryanmawhinney@google.com
-ctate@google.com
-jorlow@google.com
+jstemmer@google.com
nathch@google.com
+niagra@google.com
+niamhfw@google.com
+philippov@google.com
rthakohov@google.com
-
+tobiast@google.com
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 52cc8f633dc1..e1bcb0c21ce5 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4315,9 +4315,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
enforceInternetPermission();
final int uid = Binder.getCallingUid();
final int connectivityInfo = encodeBool(hasConnectivity);
- mHandler.sendMessage(
- mHandler.obtainMessage(EVENT_REVALIDATE_NETWORK, uid, connectivityInfo, network));
+ // Handle ConnectivityDiagnostics event before attempting to revalidate the network. This
+ // forces an ordering of ConnectivityDiagnostics events in the case where hasConnectivity
+ // does not match the known connectivity of the network - this causes NetworkMonitor to
+ // revalidate the network and generate a ConnectivityDiagnostics ConnectivityReport event.
final NetworkAgentInfo nai;
if (network == null) {
nai = getDefaultNetwork();
@@ -4330,6 +4332,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
ConnectivityDiagnosticsHandler.EVENT_NETWORK_CONNECTIVITY_REPORTED,
connectivityInfo, 0, nai));
}
+
+ mHandler.sendMessage(
+ mHandler.obtainMessage(EVENT_REVALIDATE_NETWORK, uid, connectivityInfo, network));
}
private void handleReportNetworkConnectivity(
@@ -5136,14 +5141,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void onPackageAdded(String packageName, int uid) {
- if (TextUtils.isEmpty(packageName) || uid < 0) {
- Slog.wtf(TAG, "Invalid package in onPackageAdded: " + packageName + " | " + uid);
- return;
- }
- mPermissionMonitor.onPackageAdded(packageName, uid);
- }
-
private void onPackageReplaced(String packageName, int uid) {
if (TextUtils.isEmpty(packageName) || uid < 0) {
Slog.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
@@ -5169,7 +5166,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
Slog.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
return;
}
- mPermissionMonitor.onPackageRemoved(uid);
final int userId = UserHandle.getUserId(uid);
synchronized (mVpns) {
@@ -5219,8 +5215,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
onUserRemoved(userId);
} else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
onUserUnlocked(userId);
- } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- onPackageAdded(packageName, uid);
} else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
onPackageReplaced(packageName, uid);
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
diff --git a/services/core/java/com/android/server/RuntimeService.java b/services/core/java/com/android/server/RuntimeService.java
index bb39ccc52af2..f4249f844873 100644
--- a/services/core/java/com/android/server/RuntimeService.java
+++ b/services/core/java/com/android/server/RuntimeService.java
@@ -23,10 +23,9 @@ import android.service.runtime.RuntimeServiceInfoProto;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import libcore.timezone.TimeZoneDataFiles;
-import libcore.util.CoreLibraryDebug;
-import libcore.util.DebugInfo;
-
+import com.android.i18n.timezone.DebugInfo;
+import com.android.i18n.timezone.I18nModuleDebug;
+import com.android.i18n.timezone.TimeZoneDataFiles;
import com.android.internal.util.DumpUtils;
import com.android.timezone.distro.DistroException;
import com.android.timezone.distro.DistroVersion;
@@ -61,14 +60,14 @@ public class RuntimeService extends Binder {
boolean protoFormat = hasOption(args, "--proto");
ProtoOutputStream proto = null;
- DebugInfo coreLibraryDebugInfo = CoreLibraryDebug.getDebugInfo();
- addTimeZoneApkDebugInfo(coreLibraryDebugInfo);
+ DebugInfo i18nLibraryDebugInfo = I18nModuleDebug.getDebugInfo();
+ addTimeZoneApkDebugInfo(i18nLibraryDebugInfo);
if (protoFormat) {
proto = new ProtoOutputStream(fd);
- reportTimeZoneInfoProto(coreLibraryDebugInfo, proto);
+ reportTimeZoneInfoProto(i18nLibraryDebugInfo, proto);
} else {
- reportTimeZoneInfo(coreLibraryDebugInfo, pw);
+ reportTimeZoneInfo(i18nLibraryDebugInfo, pw);
}
if (protoFormat) {
diff --git a/services/core/java/com/android/server/compat/TEST_MAPPING b/services/core/java/com/android/server/compat/TEST_MAPPING
index 0c30c790c5dd..dc1e2cb0c803 100644
--- a/services/core/java/com/android/server/compat/TEST_MAPPING
+++ b/services/core/java/com/android/server/compat/TEST_MAPPING
@@ -15,7 +15,7 @@
},
// CTS tests
{
- "name": "CtsAppCompatHostTestCases#"
+ "name": "CtsAppCompatHostTestCases"
}
]
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index f6ce2dc68b99..de302fc01f2d 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -196,13 +196,7 @@ public class PacManager {
mPacUrl = Uri.EMPTY;
mCurrentPac = null;
if (mProxyService != null) {
- try {
- mProxyService.stopPacSystem();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to stop PAC service", e);
- } finally {
- unbind();
- }
+ unbind();
}
}
return DO_SEND_BROADCAST;
@@ -327,11 +321,6 @@ public class PacManager {
if (mProxyService == null) {
Log.e(TAG, "No proxy service");
} else {
- try {
- mProxyService.startPacSystem();
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to reach ProxyService - PAC will not be started", e);
- }
mNetThreadHandler.post(mPacDownloader);
}
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index f0b7150dd84f..a75a80a606eb 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -72,7 +72,7 @@ import java.util.Set;
*
* @hide
*/
-public class PermissionMonitor {
+public class PermissionMonitor implements PackageManagerInternal.PackageListObserver {
private static final String TAG = "PermissionMonitor";
private static final boolean DBG = true;
protected static final Boolean SYSTEM = Boolean.TRUE;
@@ -82,6 +82,7 @@ public class PermissionMonitor {
private final PackageManager mPackageManager;
private final UserManager mUserManager;
private final INetd mNetd;
+ private final Dependencies mDeps;
// Values are User IDs.
@GuardedBy("this")
@@ -102,48 +103,30 @@ public class PermissionMonitor {
@GuardedBy("this")
private final Set<Integer> mAllApps = new HashSet<>();
- private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
-
- private int getPermissionForUid(int uid) {
- int permission = 0;
- // Check all the packages for this UID. The UID has the permission if any of the
- // packages in it has the permission.
- String[] packages = mPackageManager.getPackagesForUid(uid);
- if (packages != null && packages.length > 0) {
- for (String name : packages) {
- final PackageInfo app = getPackageInfo(name);
- if (app != null && app.requestedPermissions != null) {
- permission |= getNetdPermissionMask(app.requestedPermissions,
- app.requestedPermissionsFlags);
- }
- }
- } else {
- // The last package of this uid is removed from device. Clean the package up.
- permission = INetd.PERMISSION_UNINSTALLED;
- }
- return permission;
- }
-
- @Override
- public void onPackageAdded(String packageName, int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
- }
-
- @Override
- public void onPackageChanged(@NonNull String packageName, int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+ /**
+ * Dependencies of PermissionMonitor, for injection in tests.
+ */
+ @VisibleForTesting
+ public static class Dependencies {
+ /**
+ * Get device first sdk version.
+ */
+ public int getDeviceFirstSdkInt() {
+ return Build.VERSION.FIRST_SDK_INT;
}
+ }
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
- }
+ public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) {
+ this(context, netd, new Dependencies());
}
- public PermissionMonitor(Context context, INetd netd) {
+ @VisibleForTesting
+ PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd,
+ @NonNull final Dependencies deps) {
mPackageManager = context.getPackageManager();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mNetd = netd;
+ mDeps = deps;
}
// Intended to be called only once at startup, after the system is ready. Installs a broadcast
@@ -153,7 +136,7 @@ public class PermissionMonitor {
PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
if (pmi != null) {
- pmi.getPackageList(new PackageListObserver());
+ pmi.getPackageList(this);
} else {
loge("failed to get the PackageManagerInternal service");
}
@@ -224,11 +207,6 @@ public class PermissionMonitor {
}
@VisibleForTesting
- protected int getDeviceFirstSdkInt() {
- return Build.VERSION.FIRST_SDK_INT;
- }
-
- @VisibleForTesting
boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
return false;
@@ -250,7 +228,7 @@ public class PermissionMonitor {
if (app.applicationInfo != null) {
// Backward compatibility for b/114245686, on devices that launched before Q daemons
// and apps running as the system UID are exempted from this check.
- if (app.applicationInfo.uid == SYSTEM_UID && getDeviceFirstSdkInt() < VERSION_Q) {
+ if (app.applicationInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q) {
return true;
}
@@ -363,15 +341,38 @@ public class PermissionMonitor {
return currentPermission;
}
+ private int getPermissionForUid(final int uid) {
+ int permission = INetd.PERMISSION_NONE;
+ // Check all the packages for this UID. The UID has the permission if any of the
+ // packages in it has the permission.
+ final String[] packages = mPackageManager.getPackagesForUid(uid);
+ if (packages != null && packages.length > 0) {
+ for (String name : packages) {
+ final PackageInfo app = getPackageInfo(name);
+ if (app != null && app.requestedPermissions != null) {
+ permission |= getNetdPermissionMask(app.requestedPermissions,
+ app.requestedPermissionsFlags);
+ }
+ }
+ } else {
+ // The last package of this uid is removed from device. Clean the package up.
+ permission = INetd.PERMISSION_UNINSTALLED;
+ }
+ return permission;
+ }
+
/**
- * Called when a package is added. See {link #ACTION_PACKAGE_ADDED}.
+ * Called when a package is added.
*
* @param packageName The name of the new package.
* @param uid The uid of the new package.
*
* @hide
*/
- public synchronized void onPackageAdded(String packageName, int uid) {
+ @Override
+ public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
+ sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
@@ -398,13 +399,17 @@ public class PermissionMonitor {
}
/**
- * Called when a package is removed. See {link #ACTION_PACKAGE_REMOVED}.
+ * Called when a package is removed.
*
+ * @param packageName The name of the removed package or null.
* @param uid containing the integer uid previously assigned to the package.
*
* @hide
*/
- public synchronized void onPackageRemoved(int uid) {
+ @Override
+ public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
+ sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+
// If the newly-removed package falls within some VPN's uid range, update Netd with it.
// This needs to happen before the mApps update below, since removeBypassingUids() depends
// on mApps to check if the package can bypass VPN.
@@ -449,6 +454,19 @@ public class PermissionMonitor {
}
}
+ /**
+ * Called when a package is changed.
+ *
+ * @param packageName The name of the changed package.
+ * @param uid The uid of the changed package.
+ *
+ * @hide
+ */
+ @Override
+ public synchronized void onPackageChanged(@NonNull final String packageName, final int uid) {
+ sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+ }
+
private static int getNetdPermissionMask(String[] requestedPermissions,
int[] requestedPermissionsFlags) {
int permissions = 0;
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index e715890fb211..26cc3ee165f1 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -73,6 +73,8 @@ public class ProxyTracker {
@GuardedBy("mProxyLock")
private boolean mDefaultProxyEnabled = true;
+ private final Handler mConnectivityServiceHandler;
+
// The object responsible for Proxy Auto Configuration (PAC).
@NonNull
private final PacManager mPacManager;
@@ -80,6 +82,7 @@ public class ProxyTracker {
public ProxyTracker(@NonNull final Context context,
@NonNull final Handler connectivityServiceInternalHandler, final int pacChangedEvent) {
mContext = context;
+ mConnectivityServiceHandler = connectivityServiceInternalHandler;
mPacManager = new PacManager(context, connectivityServiceInternalHandler, pacChangedEvent);
}
@@ -149,6 +152,9 @@ public class ProxyTracker {
* Read the global proxy settings and cache them in memory.
*/
public void loadGlobalProxy() {
+ if (loadDeprecatedGlobalHttpProxy()) {
+ return;
+ }
ContentResolver res = mContext.getContentResolver();
String host = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_HOST);
int port = Settings.Global.getInt(res, GLOBAL_HTTP_PROXY_PORT, 0);
@@ -157,7 +163,7 @@ public class ProxyTracker {
if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
ProxyInfo proxyProperties;
if (!TextUtils.isEmpty(pacFileUrl)) {
- proxyProperties = new ProxyInfo(pacFileUrl);
+ proxyProperties = new ProxyInfo(Uri.parse(pacFileUrl));
} else {
proxyProperties = new ProxyInfo(host, port, exclList);
}
@@ -169,20 +175,24 @@ public class ProxyTracker {
synchronized (mProxyLock) {
mGlobalProxy = proxyProperties;
}
+
+ if (!TextUtils.isEmpty(pacFileUrl)) {
+ mConnectivityServiceHandler.post(
+ () -> mPacManager.setCurrentProxyScriptUrl(proxyProperties));
+ }
}
- loadDeprecatedGlobalHttpProxy();
- // TODO : shouldn't this function call mPacManager.setCurrentProxyScriptUrl ?
}
/**
* Read the global proxy from the deprecated Settings.Global.HTTP_PROXY setting and apply it.
+ * Returns {@code true} when global proxy was set successfully from deprecated setting.
*/
- public void loadDeprecatedGlobalHttpProxy() {
+ public boolean loadDeprecatedGlobalHttpProxy() {
final String proxy = Settings.Global.getString(mContext.getContentResolver(), HTTP_PROXY);
if (!TextUtils.isEmpty(proxy)) {
String data[] = proxy.split(":");
if (data.length == 0) {
- return;
+ return false;
}
final String proxyHost = data[0];
@@ -191,12 +201,14 @@ public class ProxyTracker {
try {
proxyPort = Integer.parseInt(data[1]);
} catch (NumberFormatException e) {
- return;
+ return false;
}
}
final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
setGlobalProxy(p);
+ return true;
}
+ return false;
}
/**
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index e3e02e32ad50..f0bf5c0975f2 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -24,6 +24,7 @@ import android.net.NetworkUtils;
import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
+import android.net.Uri;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
@@ -372,7 +373,7 @@ public class IpConfigStore {
config.httpProxy = proxyInfo;
break;
case PAC:
- ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl);
+ ProxyInfo proxyPacProperties = new ProxyInfo(Uri.parse(pacFileUrl));
config.proxySettings = proxySettings;
config.httpProxy = proxyPacProperties;
break;
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index 7711c6a21d20..5f2c4a38b42a 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -16,12 +16,14 @@
package com.android.server.net;
+import static android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA;
import static android.net.NetworkTemplate.getCollapsedRatType;
import android.annotation.NonNull;
import android.content.Context;
import android.os.Looper;
import android.telephony.Annotation;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
@@ -196,7 +198,18 @@ public class NetworkStatsSubscriptionsMonitor extends
@Override
public void onServiceStateChanged(@NonNull ServiceState ss) {
- final int networkType = ss.getDataNetworkType();
+ // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony
+ // would report RAT = 5G_NR.
+ // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and
+ // network allocates a secondary 5G cell so telephony reports RAT = LTE along with
+ // NR state as connected. In such case, attributes the data usage to NR.
+ // See b/160727498.
+ final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE
+ || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA)
+ && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED;
+
+ final int networkType =
+ (is5GNsa ? NETWORK_TYPE_5G_NSA : ss.getDataNetworkType());
final int collapsedRatType = getCollapsedRatType(networkType);
if (collapsedRatType == mLastCollapsedRatType) return;
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 6fdde7a196cc..fe6aad70c31e 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -10,8 +10,8 @@ toddke@android.com
toddke@google.com
# apex support
-per-file ApexManager.java = dariofreni@google.com
-per-file StagingManager.java = dariofreni@google.com
+per-file ApexManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
+per-file StagingManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
# dex
per-file AbstractStatsBase.java = agampe@google.com, calin@google.com, ngeoffray@google.com
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 2700f9ddc203..494dbad34a1d 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -49,11 +49,8 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
import com.android.server.SystemService;
-import com.android.server.pm.InstructionSets;
import com.android.server.pm.PackageManagerService;
-import dalvik.system.VMRuntime;
-
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -214,7 +211,7 @@ public class DeviceStorageMonitorService extends SystemService {
newLevel = State.LEVEL_FULL;
} else if (usableBytes <= lowBytes) {
newLevel = State.LEVEL_LOW;
- } else if (StorageManager.UUID_DEFAULT.equals(uuid) && !isBootImageOnDisk()
+ } else if (StorageManager.UUID_DEFAULT.equals(uuid)
&& usableBytes < BOOT_IMAGE_STORAGE_REQUIREMENT) {
newLevel = State.LEVEL_LOW;
} else {
@@ -261,15 +258,6 @@ public class DeviceStorageMonitorService extends SystemService {
};
}
- private static boolean isBootImageOnDisk() {
- for (String instructionSet : InstructionSets.getAllDexCodeInstructionSets()) {
- if (!VMRuntime.isBootClassPathOnDisk(instructionSet)) {
- return false;
- }
- }
- return true;
- }
-
@Override
public void onStart() {
final Context context = getContext();
@@ -467,15 +455,8 @@ public class DeviceStorageMonitorService extends SystemService {
final CharSequence title = context.getText(
com.android.internal.R.string.low_internal_storage_view_title);
- final CharSequence details;
- if (StorageManager.UUID_DEFAULT.equals(uuid)) {
- details = context.getText(isBootImageOnDisk()
- ? com.android.internal.R.string.low_internal_storage_view_text
- : com.android.internal.R.string.low_internal_storage_view_text_no_boot);
- } else {
- details = context.getText(
- com.android.internal.R.string.low_internal_storage_view_text);
- }
+ final CharSequence details = context.getText(
+ com.android.internal.R.string.low_internal_storage_view_text);
PendingIntent intent = PendingIntent.getActivityAsUser(context, 0, lowMemIntent, 0,
null, UserHandle.CURRENT);
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index bbd1ae60cb62..fd5c6e91a885 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -37,6 +37,10 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Slog;
+import com.android.i18n.timezone.TimeZoneDataFiles;
+import com.android.i18n.timezone.TimeZoneFinder;
+import com.android.i18n.timezone.TzDataSetVersion;
+import com.android.i18n.timezone.ZoneInfoDb;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.EventLogTags;
import com.android.server.SystemService;
@@ -46,10 +50,6 @@ import com.android.timezone.distro.StagedDistroOperation;
import com.android.timezone.distro.TimeZoneDistro;
import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
-import libcore.timezone.TimeZoneDataFiles;
-import libcore.timezone.TimeZoneFinder;
-import libcore.timezone.TzDataSetVersion;
-import libcore.timezone.ZoneInfoDb;
import java.io.File;
import java.io.FileDescriptor;
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index a99c0a3fa23e..335040a4b92f 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -1,5 +1,4 @@
-/* //device/libs/android_runtime/android_server_AlarmManagerService.cpp
-**
+/*
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +18,8 @@
#include <nativehelper/JNIHelp.h>
#include "jni.h"
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
#include <utils/Log.h>
#include <utils/misc.h>
#include <utils/String8.h>
@@ -75,8 +76,8 @@ typedef std::array<int, N_ANDROID_TIMERFDS> TimerFds;
class AlarmImpl
{
public:
- AlarmImpl(const TimerFds &fds, int epollfd, int rtc_id) :
- fds{fds}, epollfd{epollfd}, rtc_id{rtc_id} { }
+ AlarmImpl(const TimerFds &fds, int epollfd, const std::string& rtc_dev) :
+ fds{fds}, epollfd{epollfd}, rtc_dev{rtc_dev} { }
~AlarmImpl();
int set(int type, struct timespec *ts);
@@ -87,7 +88,7 @@ public:
private:
const TimerFds fds;
const int epollfd;
- const int rtc_id;
+ std::string rtc_dev;
};
AlarmImpl::~AlarmImpl()
@@ -132,38 +133,24 @@ int AlarmImpl::getTime(int type, struct itimerspec *spec)
int AlarmImpl::setTime(struct timeval *tv)
{
- struct rtc_time rtc;
- struct tm tm, *gmtime_res;
- int fd;
- int res;
-
- res = settimeofday(tv, NULL);
- if (res < 0) {
- ALOGV("settimeofday() failed: %s\n", strerror(errno));
+ if (settimeofday(tv, NULL) == -1) {
+ ALOGV("settimeofday() failed: %s", strerror(errno));
return -1;
}
- if (rtc_id < 0) {
- ALOGV("Not setting RTC because wall clock RTC was not found");
- errno = ENODEV;
+ android::base::unique_fd fd{open(rtc_dev.c_str(), O_RDWR)};
+ if (!fd.ok()) {
+ ALOGE("Unable to open %s: %s", rtc_dev.c_str(), strerror(errno));
return -1;
}
- android::String8 rtc_dev = String8::format("/dev/rtc%d", rtc_id);
- fd = open(rtc_dev.string(), O_RDWR);
- if (fd < 0) {
- ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno));
- return res;
- }
-
- gmtime_res = gmtime_r(&tv->tv_sec, &tm);
- if (!gmtime_res) {
- ALOGV("gmtime_r() failed: %s\n", strerror(errno));
- res = -1;
- goto done;
+ struct tm tm;
+ if (!gmtime_r(&tv->tv_sec, &tm)) {
+ ALOGV("gmtime_r() failed: %s", strerror(errno));
+ return -1;
}
- memset(&rtc, 0, sizeof(rtc));
+ struct rtc_time rtc = {};
rtc.tm_sec = tm.tm_sec;
rtc.tm_min = tm.tm_min;
rtc.tm_hour = tm.tm_hour;
@@ -173,12 +160,12 @@ int AlarmImpl::setTime(struct timeval *tv)
rtc.tm_wday = tm.tm_wday;
rtc.tm_yday = tm.tm_yday;
rtc.tm_isdst = tm.tm_isdst;
- res = ioctl(fd, RTC_SET_TIME, &rtc);
- if (res < 0)
- ALOGV("RTC_SET_TIME ioctl failed: %s\n", strerror(errno));
-done:
- close(fd);
- return res;
+ if (ioctl(fd, RTC_SET_TIME, &rtc) == -1) {
+ ALOGV("RTC_SET_TIME ioctl failed: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
}
int AlarmImpl::waitForAlarm()
@@ -251,65 +238,6 @@ static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobjec
return 0;
}
-static const char rtc_sysfs[] = "/sys/class/rtc";
-
-static bool rtc_is_hctosys(unsigned int rtc_id)
-{
- android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",
- rtc_sysfs, rtc_id);
- FILE *file = fopen(hctosys_path.string(), "re");
- if (!file) {
- ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));
- return false;
- }
-
- unsigned int hctosys;
- bool ret = false;
- int err = fscanf(file, "%u", &hctosys);
- if (err == EOF)
- ALOGE("failed to read from %s: %s", hctosys_path.string(),
- strerror(errno));
- else if (err == 0)
- ALOGE("%s did not have expected contents", hctosys_path.string());
- else
- ret = hctosys;
-
- fclose(file);
- return ret;
-}
-
-static int wall_clock_rtc()
-{
- std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(rtc_sysfs), closedir);
- if (!dir.get()) {
- ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno));
- return -1;
- }
-
- struct dirent *dirent;
- while (errno = 0, dirent = readdir(dir.get())) {
- unsigned int rtc_id;
- int matched = sscanf(dirent->d_name, "rtc%u", &rtc_id);
-
- if (matched < 0)
- break;
- else if (matched != 1)
- continue;
-
- if (rtc_is_hctosys(rtc_id)) {
- ALOGV("found wall clock RTC %u", rtc_id);
- return rtc_id;
- }
- }
-
- if (errno == 0)
- ALOGW("no wall clock RTC found");
- else
- ALOGE("failed to enumerate RTCs: %s", strerror(errno));
-
- return -1;
-}
-
static void log_timerfd_create_error(clockid_t id)
{
if (errno == EINVAL) {
@@ -343,8 +271,7 @@ static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
epollfd = epoll_create(fds.size());
if (epollfd < 0) {
- ALOGE("epoll_create(%zu) failed: %s", fds.size(),
- strerror(errno));
+ ALOGE("epoll_create(%zu) failed: %s", fds.size(), strerror(errno));
return 0;
}
@@ -360,7 +287,19 @@ static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
}
}
- AlarmImpl *ret = new AlarmImpl(fds, epollfd, wall_clock_rtc());
+ // Find the wall clock RTC. We expect this always to be /dev/rtc0, but
+ // check the /dev/rtc symlink first so that legacy devices that don't use
+ // rtc0 can add a symlink rather than need to carry a local patch to this
+ // code.
+ //
+ // TODO: if you're reading this in a world where all devices are using the
+ // GKI, you can remove the readlink and just assume /dev/rtc0.
+ std::string dev_rtc;
+ if (!android::base::Readlink("/dev/rtc", &dev_rtc)) {
+ dev_rtc = "/dev/rtc0";
+ }
+
+ std::unique_ptr<AlarmImpl> alarm{new AlarmImpl(fds, epollfd, dev_rtc)};
for (size_t i = 0; i < fds.size(); i++) {
epoll_event event;
@@ -370,13 +309,11 @@ static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event);
if (err < 0) {
ALOGE("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
- delete ret;
return 0;
}
}
- struct itimerspec spec;
- memset(&spec, 0, sizeof(spec));
+ struct itimerspec spec = {};
/* 0 = disarmed; the timerfd doesn't need to be armed to get
RTC change notifications, just set up as cancelable */
@@ -384,11 +321,10 @@ static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
if (err < 0) {
ALOGE("timerfd_settime() failed: %s", strerror(errno));
- delete ret;
return 0;
}
- return reinterpret_cast<jlong>(ret);
+ return reinterpret_cast<jlong>(alarm.release());
}
static jlong android_server_AlarmManagerService_getNextAlarm(JNIEnv*, jobject, jlong nativeData, jint type)
diff --git a/services/core/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp
index c9459994a658..6600c981b68d 100644
--- a/services/core/jni/com_android_server_SerialService.cpp
+++ b/services/core/jni/com_android_server_SerialService.cpp
@@ -18,7 +18,7 @@
#include "utils/Log.h"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include <sys/types.h>
diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp
index 72dce4dca0da..3ab5920d8b59 100644
--- a/services/core/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp
@@ -18,7 +18,7 @@
#include "utils/Log.h"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index a40bcd0d7c07..a629b69c1c27 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -18,7 +18,7 @@
#include "utils/Log.h"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
diff --git a/services/core/jni/com_android_server_UsbMidiDevice.cpp b/services/core/jni/com_android_server_UsbMidiDevice.cpp
index 8ac2c4f37ecd..d6b5bed173eb 100644
--- a/services/core/jni/com_android_server_UsbMidiDevice.cpp
+++ b/services/core/jni/com_android_server_UsbMidiDevice.cpp
@@ -19,7 +19,7 @@
#include "utils/Log.h"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 7aaa0745e5c6..1f445c9ca3bd 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -233,7 +233,7 @@ public:
/* --- InputReaderPolicyInterface implementation --- */
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
- virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
+ virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId);
virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices);
virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier);
virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier);
@@ -306,7 +306,7 @@ private:
sp<SpriteController> spriteController;
// Pointer controller singleton, created and destroyed as needed.
- wp<PointerController> pointerController;
+ std::weak_ptr<PointerController> pointerController;
// Input devices to be disabled
SortedVector<int32_t> disabledInputDevices;
@@ -551,15 +551,16 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
} // release lock
}
-sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t /* deviceId */) {
+std::shared_ptr<PointerControllerInterface> NativeInputManager::obtainPointerController(
+ int32_t /* deviceId */) {
ATRACE_CALL();
AutoMutex _l(mLock);
- sp<PointerController> controller = mLocked.pointerController.promote();
+ std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
if (controller == nullptr) {
ensureSpriteControllerLocked();
- controller = new PointerController(this, mLooper, mLocked.spriteController);
+ controller = PointerController::create(this, mLooper, mLocked.spriteController);
mLocked.pointerController = controller;
updateInactivityTimeoutLocked();
}
@@ -840,15 +841,14 @@ void NativeInputManager::setSystemUiVisibility(int32_t visibility) {
}
void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) {
- sp<PointerController> controller = mLocked.pointerController.promote();
+ std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
if (controller == nullptr) {
return;
}
bool lightsOut = mLocked.systemUiVisibility & ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN;
- controller->setInactivityTimeout(lightsOut
- ? PointerController::INACTIVITY_TIMEOUT_SHORT
- : PointerController::INACTIVITY_TIMEOUT_NORMAL);
+ controller->setInactivityTimeout(lightsOut ? PointerController::InactivityTimeout::SHORT
+ : PointerController::InactivityTimeout::NORMAL);
}
void NativeInputManager::setPointerSpeed(int32_t speed) {
@@ -928,7 +928,7 @@ void NativeInputManager::reloadCalibration() {
void NativeInputManager::setPointerIconType(int32_t iconId) {
AutoMutex _l(mLock);
- sp<PointerController> controller = mLocked.pointerController.promote();
+ std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
if (controller != nullptr) {
controller->updatePointerIcon(iconId);
}
@@ -936,7 +936,7 @@ void NativeInputManager::setPointerIconType(int32_t iconId) {
void NativeInputManager::reloadPointerIcons() {
AutoMutex _l(mLock);
- sp<PointerController> controller = mLocked.pointerController.promote();
+ std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
if (controller != nullptr) {
controller->reloadPointerResources();
}
@@ -944,7 +944,7 @@ void NativeInputManager::reloadPointerIcons() {
void NativeInputManager::setCustomPointerIcon(const SpriteIcon& icon) {
AutoMutex _l(mLock);
- sp<PointerController> controller = mLocked.pointerController.promote();
+ std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
if (controller != nullptr) {
controller->setCustomPointerIcon(icon);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 03e71f976c5b..a363f9ba5264 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5672,7 +5672,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid));
try {
IKeyChainService keyChain = keyChainConnection.getService();
- if (!keyChain.installKeyPair(privKey, cert, chain, alias)) {
+ if (!keyChain.installKeyPair(privKey, cert, chain, alias, KeyStore.UID_SELF)) {
return false;
}
if (requestAccess) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 23b1512081da..1131d37b381e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -74,6 +74,7 @@ import android.view.WindowManager;
import android.view.contentcapture.ContentCaptureManager;
import android.view.inputmethod.InputMethodSystemProperty;
+import com.android.i18n.timezone.ZoneInfoDb;
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.notification.SystemNotificationChannels;
@@ -165,8 +166,6 @@ import com.android.server.wm.ActivityTaskManagerService;
import com.android.server.wm.WindowManagerGlobalLock;
import com.android.server.wm.WindowManagerService;
-import libcore.timezone.ZoneInfoDb;
-
import dalvik.system.VMRuntime;
import java.io.File;
@@ -556,12 +555,6 @@ public final class SystemServer {
}
}
- // Diagnostic to ensure that the system is in a base healthy state. Done here as a common
- // non-zygote process.
- if (!VMRuntime.hasBootImageSpaces()) {
- Slog.wtf(TAG, "Runtime is not running with a boot image!");
- }
-
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
index 5c6fe0fc4cad..2c4c4d0ee91f 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
@@ -43,13 +43,13 @@ import android.app.timezone.RulesManager;
import android.app.timezone.RulesState;
import android.os.ParcelFileDescriptor;
+import com.android.i18n.timezone.TzDataSetVersion;
import com.android.timezone.distro.DistroVersion;
import com.android.timezone.distro.StagedDistroOperation;
import com.android.timezone.distro.TimeZoneDistro;
import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
import libcore.io.IoUtils;
-import libcore.timezone.TzDataSetVersion;
import org.junit.Before;
import org.junit.Test;
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 9a47ae15e64a..0965249cdad3 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -273,6 +273,11 @@ interface ITelecomService {
boolean setDefaultDialer(in String packageName);
/**
+ * Stop suppressing blocked numbers after a call to emergency services. Shell only.
+ */
+ void stopBlockSuppression();
+
+ /**
* @see TelecomServiceImpl#createManageBlockedNumbersIntent
**/
Intent createManageBlockedNumbersIntent();
diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
index 3c1e707ab1dd..4af19b5489ca 100644
--- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
@@ -127,6 +127,14 @@ public final class CarrierAppUtils {
return userContext.getContentResolver();
}
+ private static boolean isUpdatedSystemApp(ApplicationInfo ai) {
+ if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+ return true;
+ }
+
+ return false;
+ }
+
/**
* Disable carrier apps until they are privileged
* Must be public b/c framework unit tests can't access package-private methods.
@@ -138,7 +146,7 @@ public final class CarrierAppUtils {
ContentResolver contentResolver, int userId,
ArraySet<String> systemCarrierAppsDisabledUntilUsed,
ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
- List<ApplicationInfo> candidates = getDefaultNotUpdatedCarrierAppCandidatesHelper(
+ List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(
packageManager, userId, systemCarrierAppsDisabledUntilUsed);
if (candidates == null || candidates.isEmpty()) {
return;
@@ -180,7 +188,7 @@ public final class CarrierAppUtils {
if (hasPrivileges) {
// Only update enabled state for the app on /system. Once it has been
// updated we shouldn't touch it.
- if (enabledSetting
+ if (!isUpdatedSystemApp(ai) && enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
@@ -232,7 +240,7 @@ public final class CarrierAppUtils {
} else { // No carrier privileges
// Only update enabled state for the app on /system. Once it has been
// updated we shouldn't touch it.
- if (enabledSetting
+ if (!isUpdatedSystemApp(ai) && enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
&& (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
Log.i(TAG, "Update state(" + packageName
@@ -363,31 +371,6 @@ public final class CarrierAppUtils {
return apps;
}
- private static List<ApplicationInfo> getDefaultNotUpdatedCarrierAppCandidatesHelper(
- IPackageManager packageManager,
- int userId,
- ArraySet<String> systemCarrierAppsDisabledUntilUsed) {
- if (systemCarrierAppsDisabledUntilUsed == null) {
- return null;
- }
-
- int size = systemCarrierAppsDisabledUntilUsed.size();
- if (size == 0) {
- return null;
- }
-
- List<ApplicationInfo> apps = new ArrayList<>(size);
- for (int i = 0; i < size; i++) {
- String packageName = systemCarrierAppsDisabledUntilUsed.valueAt(i);
- ApplicationInfo ai =
- getApplicationInfoIfNotUpdatedSystemApp(packageManager, userId, packageName);
- if (ai != null) {
- apps.add(ai);
- }
- }
- return apps;
- }
-
private static Map<String, List<ApplicationInfo>> getDefaultCarrierAssociatedAppsHelper(
IPackageManager packageManager,
int userId,
@@ -400,11 +383,11 @@ public final class CarrierAppUtils {
systemCarrierAssociatedAppsDisabledUntilUsed.valueAt(i);
for (int j = 0; j < associatedAppPackages.size(); j++) {
ApplicationInfo ai =
- getApplicationInfoIfNotUpdatedSystemApp(
+ getApplicationInfoIfSystemApp(
packageManager, userId, associatedAppPackages.get(j));
// Only update enabled state for the app on /system. Once it has been updated we
// shouldn't touch it.
- if (ai != null) {
+ if (ai != null && !isUpdatedSystemApp(ai)) {
List<ApplicationInfo> appList = associatedApps.get(carrierAppPackage);
if (appList == null) {
appList = new ArrayList<>();
@@ -418,26 +401,6 @@ public final class CarrierAppUtils {
}
@Nullable
- private static ApplicationInfo getApplicationInfoIfNotUpdatedSystemApp(
- IPackageManager packageManager,
- int userId,
- String packageName) {
- try {
- ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
- | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
- | PackageManager.MATCH_SYSTEM_ONLY
- | PackageManager.MATCH_FACTORY_ONLY, userId);
- if (ai != null) {
- return ai;
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Could not reach PackageManager", e);
- }
- return null;
- }
-
- @Nullable
private static ApplicationInfo getApplicationInfoIfSystemApp(
IPackageManager packageManager,
int userId,
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index 1a049e6c517e..d69282579b77 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -542,13 +542,16 @@ public final class SmsApplication {
// Assign permission to special system apps
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
- PHONE_PACKAGE_NAME);
+ PHONE_PACKAGE_NAME, true);
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
- BLUETOOTH_PACKAGE_NAME);
+ BLUETOOTH_PACKAGE_NAME, true);
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
- MMS_SERVICE_PACKAGE_NAME);
+ MMS_SERVICE_PACKAGE_NAME, true);
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
- TELEPHONY_PROVIDER_PACKAGE_NAME);
+ TELEPHONY_PROVIDER_PACKAGE_NAME, true);
+ // CellbroadcastReceiver is a mainline module thus skip signature match.
+ assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
+ CellBroadcastUtils.getDefaultCellBroadcastReceiverPackageName(context), false);
// Give AppOps permission to UID 1001 which contains multiple
// apps, all of them should be able to write to telephony provider.
@@ -738,17 +741,23 @@ public final class SmsApplication {
* @param packageManager The package manager instance
* @param appOps The AppOps manager instance
* @param packageName The package name of the system app
+ * @param sigatureMatch whether to check signature match
*/
private static void assignExclusiveSmsPermissionsToSystemApp(Context context,
- PackageManager packageManager, AppOpsManager appOps, String packageName) {
+ PackageManager packageManager, AppOpsManager appOps, String packageName,
+ boolean sigatureMatch) {
// First check package signature matches the caller's package signature.
// Since this class is only used internally by the system, this check makes sure
// the package signature matches system signature.
- final int result = packageManager.checkSignatures(context.getPackageName(), packageName);
- if (result != PackageManager.SIGNATURE_MATCH) {
- Log.e(LOG_TAG, packageName + " does not have system signature");
- return;
+ if (sigatureMatch) {
+ final int result = packageManager.checkSignatures(context.getPackageName(),
+ packageName);
+ if (result != PackageManager.SIGNATURE_MATCH) {
+ Log.e(LOG_TAG, packageName + " does not have system signature");
+ return;
+ }
}
+
try {
PackageInfo info = packageManager.getPackageInfo(packageName, 0);
int mode = appOps.unsafeCheckOp(AppOpsManager.OPSTR_WRITE_SMS, info.applicationInfo.uid,
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/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d319e37c4ba6..b75f9a15f66f 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2495,15 +2495,15 @@ public class CarrierConfigManager {
/**
* List of 4 customized 5G SS reference signal received quality (SSRSRQ) thresholds.
* <p>
- * Reference: 3GPP TS 38.215
+ * Reference: 3GPP TS 38.215; 3GPP TS 38.133 section 10
* <p>
- * 4 threshold integers must be within the boundaries [-20 dB, -3 dB], and the levels are:
+ * 4 threshold integers must be within the boundaries [-43 dB, 20 dB], and the levels are:
* <UL>
- * <LI>"NONE: [-20, threshold1]"</LI>
+ * <LI>"NONE: [-43, threshold1]"</LI>
* <LI>"POOR: (threshold1, threshold2]"</LI>
* <LI>"MODERATE: (threshold2, threshold3]"</LI>
* <LI>"GOOD: (threshold3, threshold4]"</LI>
- * <LI>"EXCELLENT: (threshold4, -3]"</LI>
+ * <LI>"EXCELLENT: (threshold4, 20]"</LI>
* </UL>
* <p>
* This key is considered invalid if the format is violated. If the key is invalid or
@@ -4188,12 +4188,12 @@ public class CarrierConfigManager {
-65, /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putIntArray(KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY,
- // Boundaries: [-20 dB, -3 dB]
+ // Boundaries: [-43 dB, 20 dB]
new int[] {
- -16, /* SIGNAL_STRENGTH_POOR */
- -12, /* SIGNAL_STRENGTH_MODERATE */
- -9, /* SIGNAL_STRENGTH_GOOD */
- -6 /* SIGNAL_STRENGTH_GREAT */
+ -31, /* SIGNAL_STRENGTH_POOR */
+ -19, /* SIGNAL_STRENGTH_MODERATE */
+ -7, /* SIGNAL_STRENGTH_GOOD */
+ 6 /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
// Boundaries: [-23 dB, 40 dB]
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index 64776e377fa4..61f68ce32287 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.os.ServiceManager;
@@ -32,15 +34,36 @@ 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(ServiceManager.getService("phone"));
if (phone != null) {
- phone.updateServiceLocation();
+ phone.updateServiceLocationWithPackageName(appContext.getOpPackageName());
}
} catch (RemoteException ex) {
// ignore it
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 95fe90a47654..8e50bba38e84 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -54,12 +54,12 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
};
// Lifted from Default carrier configs and max range of SSRSRQ
- // Boundaries: [-20 dB, -3 dB]
+ // Boundaries: [-43 dB, 20 dB]
private int[] mSsRsrqThresholds = new int[] {
- -16, /* SIGNAL_STRENGTH_POOR */
- -12, /* SIGNAL_STRENGTH_MODERATE */
- -9, /* SIGNAL_STRENGTH_GOOD */
- -6 /* SIGNAL_STRENGTH_GREAT */
+ -31, /* SIGNAL_STRENGTH_POOR */
+ -19, /* SIGNAL_STRENGTH_MODERATE */
+ -7, /* SIGNAL_STRENGTH_GOOD */
+ 6 /* SIGNAL_STRENGTH_GREAT */
};
// Lifted from Default carrier configs and max range of SSSINR
@@ -183,8 +183,8 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
}
/**
- * Reference: 3GPP TS 38.215.
- * Range: -20 dB to -3 dB.
+ * Reference: 3GPP TS 38.215; 3GPP TS 38.133 section 10
+ * Range: -43 dB to 20 dB.
* @return SS reference signal received quality, {@link CellInfo#UNAVAILABLE} means unreported
* value.
*/
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/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 31a83c9334d5..68753e11d395 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);
@@ -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
@@ -616,6 +638,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();
}
@@ -623,7 +646,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
@@ -643,6 +667,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)
@@ -669,6 +694,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/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index a9abe89abab0..dd37ec3b6e54 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -266,7 +266,6 @@ public final class PreciseDataConnectionState implements Parcelable {
*
* @return the ApnSetting that was used to configure this data connection.
*/
- // FIXME: This shouldn't be nullable; update once the ApnSetting is supplied correctly
public @Nullable ApnSetting getApnSetting() {
return mApnSetting;
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 5c84297d3b86..243b24b667c7 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1392,29 +1392,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 7456aabc8e19..abcc82bcdfe7 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -615,10 +615,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;
}
@@ -1174,10 +1176,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 7266fc05cffa..392670ba992c 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: [&lt;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.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6b498b5f8697..4c7253ce76c6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -110,8 +110,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;
@@ -124,8 +122,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
@@ -2189,58 +2185,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.
@@ -2440,7 +2384,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;
@@ -2451,35 +2396,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
*/
@@ -2488,56 +2404,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
@@ -8109,6 +7975,140 @@ public class TelephonyManager {
return false;
}
+ /** @hide */
+ @IntDef({
+ ALLOWED_NETWORK_TYPES_REASON_POWER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AllowedNetworkTypesReason{}
+
+ /**
+ * To indicate allowed network type change is requested by power manager.
+ * Power Manger configuration won't affect the settings configured through
+ * {@link setAllowedNetworkTypes} and will result in allowing network types that are in both
+ * configurations (i.e intersection of both sets).
+ * @hide
+ */
+ public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 0;
+
+ /**
+ * Set the allowed network types of the device and
+ * provide the reason triggering the allowed network change.
+ * This can be called for following reasons
+ * <ol>
+ * <li>Allowed network types control by power manager
+ * {@link #ALLOWED_NETWORK_TYPES_REASON_POWER}
+ * </ol>
+ * This API will result in allowing an intersection of allowed network types for all reasons,
+ * including the configuration done through {@link setAllowedNetworkTypes}.
+ * While this API and {@link setAllowedNetworkTypes} is controlling allowed network types
+ * on device, user preference will still be set through {@link #setPreferredNetworkTypeBitmask}.
+ * Thus resultant network type configured on modem will be an intersection of the network types
+ * from setAllowedNetworkTypesForReason, {@link setAllowedNetworkTypes}
+ * and {@link #setPreferredNetworkTypeBitmask}.
+ *
+ * @param reason the reason the allowed network type change is taking place
+ * @param allowedNetworkTypes The bitmask of allowed network types.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setAllowedNetworkTypesForReason(@AllowedNetworkTypesReason int reason,
+ @NetworkTypeBitMask long allowedNetworkTypes) {
+ if (reason != ALLOWED_NETWORK_TYPES_REASON_POWER) {
+ throw new IllegalArgumentException("invalid AllowedNetworkTypesReason.");
+ }
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setAllowedNetworkTypesForReason(getSubId(), reason,
+ allowedNetworkTypes);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setAllowedNetworkTypesForReason RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the allowed network types for certain reason.
+ *
+ * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a
+ * specific reason. For effective allowed network types configured on device,
+ * query {@link getEffectiveAllowedNetworkTypes}
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *s
+ * @param reason the reason the allowed network type change is taking place
+ * @return the allowed network type bitmask
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public @NetworkTypeBitMask long getAllowedNetworkTypesForReason(
+ @AllowedNetworkTypesReason int reason) {
+ if (reason != ALLOWED_NETWORK_TYPES_REASON_POWER) {
+ throw new IllegalArgumentException("invalid AllowedNetworkTypesReason.");
+ }
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getAllowedNetworkTypesForReason(getSubId(), reason);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getAllowedNetworkTypesForReason RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ return -1;
+ }
+
+ /**
+ * Get bit mask of all network types.
+ *
+ * @return bit mask of all network types
+ * @hide
+ */
+ public static @NetworkTypeBitMask long getAllNetworkTypesBitmask() {
+ return NETWORK_STANDARDS_FAMILY_BITMASK_3GPP | NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2;
+ }
+
+ /**
+ * Get the allowed network types configured on the device.
+ * This API will return an intersection of allowed network types for all reasons,
+ * including the configuration done through setAllowedNetworkTypes
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @return the allowed network type bitmask
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public @NetworkTypeBitMask long getEffectiveAllowedNetworkTypes() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getEffectiveAllowedNetworkTypes(getSubId());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getEffectiveAllowedNetworkTypes RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ return -1;
+ }
+
/**
* Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
*
@@ -8969,17 +8969,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 */
@@ -12608,7 +12605,6 @@ public class TelephonyManager {
@Nullable String mvnoMatchData) {
try {
if (!mccmnc.equals(getSimOperator())) {
- Log.d(TAG, "The mccmnc does not match");
return false;
}
ITelephony service = getITelephony();
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 359d08d294c3..3f8fd9d68a4f 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -31,6 +31,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.telephony.ITelephony;
import com.android.telephony.Rlog;
@@ -56,6 +57,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;
@@ -104,17 +107,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);
@@ -159,6 +189,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);
}
@@ -169,7 +202,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);
}
@@ -179,7 +214,14 @@ public final class TelephonyScanManager {
break;
}
}
- });
+ };
+ mMessenger = new Messenger(mHandler);
+ mDeathRecipient = new Binder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ mHandler.obtainMessage(CALLBACK_TELEPHONY_DIED).sendToTarget();
+ }
+ };
}
/**
@@ -190,7 +232,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
*
@@ -203,19 +245,26 @@ public final class TelephonyScanManager {
NetworkScanRequest request, Executor executor, NetworkScanCallback callback,
String callingPackage, 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);
@@ -225,6 +274,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/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 6840e8eed318..5ee6ec957b50 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -346,7 +346,6 @@ public class MmTelFeature extends ImsFeature {
* @hide
*/
@Override
- @SystemApi @TestApi
public void onIncomingCall(IImsCallSession c, Bundle extras) {
}
@@ -358,7 +357,6 @@ public class MmTelFeature extends ImsFeature {
* @hide
*/
@Override
- @SystemApi @TestApi
public void onRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) {
}
@@ -369,7 +367,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/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 5a6b997f0723..bf81ddcb0c15 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
@@ -956,6 +943,35 @@ interface ITelephony {
boolean setAllowedNetworkTypes(int subId, long allowedNetworkTypes);
/**
+ * Get the allowed network types for certain reason.
+ *
+ * @param subId the id of the subscription.
+ * @param reason the reason the allowed network type change is taking place
+ * @return allowedNetworkTypes the allowed network types.
+ */
+ long getAllowedNetworkTypesForReason(int subId, int reason);
+
+ /**
+ * Get the effective allowed network types on the device. This API will
+ * return an intersection of allowed network types for all reasons,
+ * including the configuration done through setAllowedNetworkTypes
+ *
+ * @param subId the id of the subscription.
+ * @return allowedNetworkTypes the allowed network types.
+ */
+ long getEffectiveAllowedNetworkTypes(int subId);
+
+ /**
+ * Set the allowed network types and provide the reason triggering the allowed network change.
+ *
+ * @param subId the id of the subscription.
+ * @param reason the reason the allowed network type change is taking place
+ * @param allowedNetworkTypes the allowed network types.
+ * @return true on success; false on any failure.
+ */
+ boolean setAllowedNetworkTypesForReason(int subId, int reason, long allowedNetworkTypes);
+
+ /**
* Set the preferred network type.
* Used for device configuration by some CDMA operators.
*
diff --git a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
index 3bd8cdd23df3..f8ab87d042eb 100644
--- a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
+++ b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
@@ -65,13 +65,7 @@ public class Sms7BitEncodingTranslator {
return "";
}
- if (!mIs7BitTranslationTableLoaded) {
- mTranslationTableCommon = new SparseIntArray();
- mTranslationTableGSM = new SparseIntArray();
- mTranslationTableCDMA = new SparseIntArray();
- load7BitTranslationTableFromXml();
- mIs7BitTranslationTableLoaded = true;
- }
+ ensure7BitTranslationTableLoaded();
if ((mTranslationTableCommon != null && mTranslationTableCommon.size() > 0) ||
(mTranslationTableGSM != null && mTranslationTableGSM.size() > 0) ||
@@ -115,6 +109,8 @@ public class Sms7BitEncodingTranslator {
*/
int translation = -1;
+ ensure7BitTranslationTableLoaded();
+
if (mTranslationTableCommon != null) {
translation = mTranslationTableCommon.get(c, -1);
}
@@ -155,6 +151,18 @@ public class Sms7BitEncodingTranslator {
}
}
+ private static void ensure7BitTranslationTableLoaded() {
+ synchronized (Sms7BitEncodingTranslator.class) {
+ if (!mIs7BitTranslationTableLoaded) {
+ mTranslationTableCommon = new SparseIntArray();
+ mTranslationTableGSM = new SparseIntArray();
+ mTranslationTableCDMA = new SparseIntArray();
+ load7BitTranslationTableFromXml();
+ mIs7BitTranslationTableLoaded = true;
+ }
+ }
+ }
+
/**
* Load the whole translation table file from the framework resource
* encoded in XML.
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 3f85de358ea2..109dd3b30827 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -35,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;
@@ -315,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;
}
@@ -1093,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 + ")");
@@ -1462,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 + ")");
@@ -1481,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 + ")");
@@ -1500,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 + ")");
@@ -1587,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 + ")");
@@ -1607,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 + ")");
@@ -1626,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 + ")");
@@ -1646,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 + ")");
@@ -1665,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 + ")");
@@ -1685,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 + ")");
@@ -1706,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 + ")");
@@ -1726,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 + ")");
@@ -1747,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 + ")");
@@ -1768,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 + ")");
@@ -1789,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 + ")");
@@ -1809,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 + ")");
@@ -1871,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 122f0851cf37..7d5710e32194 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -43,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;
@@ -91,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;
@@ -140,38 +142,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: [&lt;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.
@@ -225,20 +195,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
@@ -246,19 +216,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;
}
@@ -368,17 +335,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);
- // 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;
+ byte mtiByte = 0x01; // SMS-SUBMIT
+
+ 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,
@@ -450,8 +419,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);
}
@@ -888,10 +857,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++]);
@@ -917,16 +885,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;
}
/**
@@ -1277,6 +1251,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();
@@ -1335,6 +1310,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);
@@ -1377,23 +1353,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();
}
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 69c296e7ee9c..c7c9fc739189 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -38,6 +38,7 @@ java_sdk_library {
],
compile_dex: true,
+ default_to_stubs: true,
}
// Build the android.test.base_static library
diff --git a/test-base/src/android/test/InstrumentationTestCase.java b/test-base/src/android/test/InstrumentationTestCase.java
index 6b79314a4385..9f7a2fa44dc2 100644
--- a/test-base/src/android/test/InstrumentationTestCase.java
+++ b/test-base/src/android/test/InstrumentationTestCase.java
@@ -34,9 +34,9 @@ import junit.framework.TestCase;
* A test case that has access to {@link Instrumentation}.
*
* @deprecated Use
- * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * <a href="{@docRoot}reference/androidx/test/platform/app/InstrumentationRegistry.html">
* InstrumentationRegistry</a> instead. New tests should be written using the
- * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ * <a href="{@docRoot}training/testing/index.html">AndroidX Test Library</a>.
*/
@Deprecated
public class InstrumentationTestCase extends TestCase {
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 248c117d2e03..7d0f92fac4c7 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -37,6 +37,7 @@ java_sdk_library {
"android.test.mock",
],
compile_dex: true,
+ default_to_stubs: true,
}
// Make the current.txt available for use by the cts/tests/signature tests.
diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
index e9a5ff70a7cc..3206adc31b98 100644
--- a/test-mock/src/android/test/mock/MockContentProvider.java
+++ b/test-mock/src/android/test/mock/MockContentProvider.java
@@ -29,6 +29,7 @@ import android.content.pm.ProviderInfo;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ICancellationSignal;
@@ -282,7 +283,7 @@ public class MockContentProvider extends ContentProvider {
* @hide
*/
public IBinder getIContentProviderBinder() {
- throw new UnsupportedOperationException("unimplemented mock method");
+ return new Binder();
}
/**
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index 75f5b5a96eb1..1f6db8403eee 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -41,6 +41,7 @@ java_sdk_library {
],
compile_dex: true,
+ default_to_stubs: true,
}
// Build the android.test.runner-minus-junit library
diff --git a/test-runner/api/current.txt b/test-runner/api/current.txt
index 2c19a2e85410..5407b685bb34 100644
--- a/test-runner/api/current.txt
+++ b/test-runner/api/current.txt
@@ -78,6 +78,7 @@ package android.test {
@Deprecated public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
ctor @Deprecated public InstrumentationTestRunner();
+ method @Deprecated protected void addTestListener(junit.framework.TestListener);
method @Deprecated public junit.framework.TestSuite getAllTests();
method @Deprecated protected android.test.AndroidTestRunner getAndroidTestRunner();
method @Deprecated public android.os.Bundle getArguments();
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index b2582c19b548..07e3f8736cc8 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -410,7 +410,6 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
/**
* Add a {@link TestListener}
- * @hide
*/
protected void addTestListener(TestListener listener){
if(mTestRunner!=null && listener!=null){
diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
index 62c1ba89653c..2d58ce8baddc 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk
+++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
@@ -36,8 +36,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := DynamicCodeLoggerNativeTestLibrary
LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_HEADER_LIBRARIES := jni_headers
LOCAL_SDK_VERSION := 28
LOCAL_NDK_STL_VARIANT := c++_static
diff --git a/tests/net/java/android/net/DnsPacketTest.java b/tests/net/java/android/net/DnsPacketTest.java
deleted file mode 100644
index 975abf416944..000000000000
--- a/tests/net/java/android/net/DnsPacketTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2019 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.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DnsPacketTest {
- private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag,
- int qCount, int aCount, int nsCount, int arCount) {
- assertEquals(header.id, id);
- assertEquals(header.flags, flag);
- assertEquals(header.getRecordCount(DnsPacket.QDSECTION), qCount);
- assertEquals(header.getRecordCount(DnsPacket.ANSECTION), aCount);
- assertEquals(header.getRecordCount(DnsPacket.NSSECTION), nsCount);
- assertEquals(header.getRecordCount(DnsPacket.ARSECTION), arCount);
- }
-
- private void assertRecordParses(DnsPacket.DnsRecord record, String dname,
- int dtype, int dclass, int ttl, byte[] rr) {
- assertEquals(record.dName, dname);
- assertEquals(record.nsType, dtype);
- assertEquals(record.nsClass, dclass);
- assertEquals(record.ttl, ttl);
- assertTrue(Arrays.equals(record.getRR(), rr));
- }
-
- class TestDnsPacket extends DnsPacket {
- TestDnsPacket(byte[] data) throws ParseException {
- super(data);
- }
-
- public DnsHeader getHeader() {
- return mHeader;
- }
- public List<DnsRecord> getRecordList(int secType) {
- return mRecords[secType];
- }
- }
-
- @Test
- public void testNullDisallowed() {
- try {
- new TestDnsPacket(null);
- fail("Exception not thrown for null byte array");
- } catch (ParseException e) {
- }
- }
-
- @Test
- public void testV4Answer() throws Exception {
- final byte[] v4blob = new byte[] {
- /* Header */
- 0x55, 0x66, /* Transaction ID */
- (byte) 0x81, (byte) 0x80, /* Flags */
- 0x00, 0x01, /* Questions */
- 0x00, 0x01, /* Answer RRs */
- 0x00, 0x00, /* Authority RRs */
- 0x00, 0x00, /* Additional RRs */
- /* Queries */
- 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
- 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
- 0x00, 0x01, /* Type */
- 0x00, 0x01, /* Class */
- /* Answers */
- (byte) 0xc0, 0x0c, /* Name */
- 0x00, 0x01, /* Type */
- 0x00, 0x01, /* Class */
- 0x00, 0x00, 0x01, 0x2b, /* TTL */
- 0x00, 0x04, /* Data length */
- (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */
- };
- TestDnsPacket packet = new TestDnsPacket(v4blob);
-
- // Header part
- assertHeaderParses(packet.getHeader(), 0x5566, 0x8180, 1, 1, 0, 0);
-
- // Record part
- List<DnsPacket.DnsRecord> qdRecordList =
- packet.getRecordList(DnsPacket.QDSECTION);
- assertEquals(qdRecordList.size(), 1);
- assertRecordParses(qdRecordList.get(0), "www.google.com", 1, 1, 0, null);
-
- List<DnsPacket.DnsRecord> anRecordList =
- packet.getRecordList(DnsPacket.ANSECTION);
- assertEquals(anRecordList.size(), 1);
- assertRecordParses(anRecordList.get(0), "www.google.com", 1, 1, 0x12b,
- new byte[]{ (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 });
- }
-
- @Test
- public void testV6Answer() throws Exception {
- final byte[] v6blob = new byte[] {
- /* Header */
- 0x77, 0x22, /* Transaction ID */
- (byte) 0x81, (byte) 0x80, /* Flags */
- 0x00, 0x01, /* Questions */
- 0x00, 0x01, /* Answer RRs */
- 0x00, 0x00, /* Authority RRs */
- 0x00, 0x00, /* Additional RRs */
- /* Queries */
- 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
- 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
- 0x00, 0x1c, /* Type */
- 0x00, 0x01, /* Class */
- /* Answers */
- (byte) 0xc0, 0x0c, /* Name */
- 0x00, 0x1c, /* Type */
- 0x00, 0x01, /* Class */
- 0x00, 0x00, 0x00, 0x37, /* TTL */
- 0x00, 0x10, /* Data length */
- 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 /* Address */
- };
- TestDnsPacket packet = new TestDnsPacket(v6blob);
-
- // Header part
- assertHeaderParses(packet.getHeader(), 0x7722, 0x8180, 1, 1, 0, 0);
-
- // Record part
- List<DnsPacket.DnsRecord> qdRecordList =
- packet.getRecordList(DnsPacket.QDSECTION);
- assertEquals(qdRecordList.size(), 1);
- assertRecordParses(qdRecordList.get(0), "www.google.com", 28, 1, 0, null);
-
- List<DnsPacket.DnsRecord> anRecordList =
- packet.getRecordList(DnsPacket.ANSECTION);
- assertEquals(anRecordList.size(), 1);
- assertRecordParses(anRecordList.get(0), "www.google.com", 28, 1, 0x37,
- new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 });
- }
-}
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 5dd0fda4da28..9ba56e44fe88 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -26,6 +26,7 @@ import android.net.NetworkStats.METERED_ALL
import android.net.NetworkStats.ROAMING_ALL
import android.net.NetworkTemplate.MATCH_MOBILE
import android.net.NetworkTemplate.MATCH_WIFI
+import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
import android.net.NetworkTemplate.buildTemplateMobileWithRatType
import android.telephony.TelephonyManager
@@ -145,11 +146,13 @@ class NetworkTemplateTest {
assertParcelSane(templateWifi, 8)
}
- // Verify NETWORK_TYPE_ALL does not conflict with TelephonyManager#NETWORK_TYPE_* constants.
+ // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
+ // TelephonyManager#NETWORK_TYPE_* constants.
@Test
- fun testNetworkTypeAll() {
+ fun testNetworkTypeConstants() {
for (ratType in TelephonyManager.getAllNetworkTypes()) {
assertNotEquals(NETWORK_TYPE_ALL, ratType)
+ assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
}
}
}
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
index 7748288aeb05..3158cc8637e4 100644
--- a/tests/net/java/android/net/NetworkUtilsTest.java
+++ b/tests/net/java/android/net/NetworkUtilsTest.java
@@ -16,10 +16,24 @@
package android.net;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.EPERM;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+
import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.system.ErrnoException;
+import android.system.Os;
+
import androidx.test.runner.AndroidJUnit4;
+import libcore.io.IoUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -125,4 +139,50 @@ public class NetworkUtilsTest {
assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
NetworkUtils.routedIPv6AddressCount(set));
}
+
+ private static void expectSocketSuccess(String msg, int domain, int type) {
+ try {
+ IoUtils.closeQuietly(Os.socket(domain, type, 0));
+ } catch (ErrnoException e) {
+ fail(msg + e.getMessage());
+ }
+ }
+
+ private static void expectSocketPemissionError(String msg, int domain, int type) {
+ try {
+ IoUtils.closeQuietly(Os.socket(domain, type, 0));
+ fail(msg);
+ } catch (ErrnoException e) {
+ assertEquals(msg, e.errno, EPERM);
+ }
+ }
+
+ private static void expectHasNetworking() {
+ expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
+ AF_UNIX, SOCK_STREAM);
+ expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
+ AF_INET, SOCK_DGRAM);
+ expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
+ AF_INET6, SOCK_DGRAM);
+ }
+
+ private static void expectNoNetworking() {
+ expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
+ AF_UNIX, SOCK_STREAM);
+ expectSocketPemissionError(
+ "Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
+ AF_INET, SOCK_DGRAM);
+ expectSocketPemissionError(
+ "Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
+ AF_INET6, SOCK_DGRAM);
+ }
+
+ @Test
+ public void testSetAllowNetworkingForProcess() {
+ expectHasNetworking();
+ NetworkUtils.setAllowNetworkingForProcess(false);
+ expectNoNetworking();
+ NetworkUtils.setAllowNetworkingForProcess(true);
+ expectHasNetworking();
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 76e3e2fced6f..fdc6084884f6 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -76,7 +76,6 @@ import com.android.server.LocalServices;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
@@ -88,7 +87,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PermissionMonitorTest {
@@ -116,8 +114,8 @@ public class PermissionMonitorTest {
@Mock private INetd mNetdService;
@Mock private PackageManagerInternal mMockPmi;
@Mock private UserManager mUserManager;
+ @Mock private PermissionMonitor.Dependencies mDeps;
- private PackageManagerInternal.PackageListObserver mObserver;
private PermissionMonitor mPermissionMonitor;
@Before
@@ -131,7 +129,7 @@ public class PermissionMonitorTest {
new UserInfo(MOCK_USER2, "", 0),
}));
- mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService));
+ mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mMockPmi);
@@ -139,11 +137,7 @@ public class PermissionMonitorTest {
/* observer */ null));
when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
mPermissionMonitor.startMonitoring();
-
- final ArgumentCaptor<PackageManagerInternal.PackageListObserver> observerCaptor =
- ArgumentCaptor.forClass(PackageManagerInternal.PackageListObserver.class);
- verify(mMockPmi).getPackageList(observerCaptor.capture());
- mObserver = observerCaptor.getValue();
+ verify(mMockPmi).getPackageList(mPermissionMonitor);
}
private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
@@ -290,14 +284,14 @@ public class PermissionMonitorTest {
@Test
public void testHasRestrictedNetworkPermissionSystemUid() {
- doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt();
+ doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
assertTrue(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
assertTrue(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt();
+ doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
assertFalse(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
@@ -450,13 +444,13 @@ public class PermissionMonitorTest {
new int[]{MOCK_UID1});
// Remove MOCK_UID1, expect no permission left for all user.
- mPermissionMonitor.onPackageRemoved(MOCK_UID1);
- removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
+ mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1});
// Remove SYSTEM_PACKAGE1, expect permission downgrade.
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
- removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID);
+ removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_PACKAGE1, SYSTEM_UID);
mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID});
@@ -465,7 +459,7 @@ public class PermissionMonitorTest {
// Remove all packages, expect no permission left.
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
- removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID);
+ removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID, MOCK_UID1});
@@ -501,7 +495,8 @@ public class PermissionMonitorTest {
reset(mNetdService);
// When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated
- mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+ mPermissionMonitor.onPackageRemoved(
+ MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
@@ -545,7 +540,8 @@ public class PermissionMonitorTest {
aryEq(new int[] {MOCK_UID1}));
// Removed package should have its uid rules removed
- mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+ mPermissionMonitor.onPackageRemoved(
+ MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
}
@@ -559,9 +555,9 @@ public class PermissionMonitorTest {
}
}
- private void removePackageForUsers(int[] users, int uid) {
+ private void removePackageForUsers(int[] users, String packageName, int uid) {
for (final int user : users) {
- mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid));
+ mPermissionMonitor.onPackageRemoved(packageName, UserHandle.getUid(user, uid));
}
}
@@ -647,7 +643,7 @@ public class PermissionMonitorTest {
private PackageInfo addPackage(String packageName, int uid, String[] permissions)
throws Exception {
PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions);
- mObserver.onPackageAdded(packageName, uid);
+ mPermissionMonitor.onPackageAdded(packageName, uid);
return packageInfo;
}
@@ -678,7 +674,7 @@ public class PermissionMonitorTest {
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1))
.thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
- mObserver.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
+ mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
}
@@ -692,7 +688,7 @@ public class PermissionMonitorTest {
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
- mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
}
@@ -705,7 +701,7 @@ public class PermissionMonitorTest {
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
- mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
@@ -719,10 +715,7 @@ public class PermissionMonitorTest {
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1});
- // When updating a package, the broadcast receiver gets two broadcasts (a remove and then an
- // add), but the observer sees only one callback (an update).
- setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mObserver.onPackageChanged(MOCK_PACKAGE1, MOCK_UID1);
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@@ -740,7 +733,7 @@ public class PermissionMonitorTest {
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
MOCK_PACKAGE2});
- mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
index c813269744ef..9531b0a5bb66 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
@@ -17,6 +17,7 @@
package com.android.server.net;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
@@ -30,7 +31,9 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.NetworkTemplate;
import android.os.test.TestLooper;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
@@ -61,7 +64,6 @@ public final class NetworkStatsSubscriptionsMonitorTest {
private static final String TEST_IMSI3 = "466929999999999";
@Mock private Context mContext;
- @Mock private PhoneStateListener mPhoneStateListener;
@Mock private SubscriptionManager mSubscriptionManager;
@Mock private TelephonyManager mTelephonyManager;
@Mock private NetworkStatsSubscriptionsMonitor.Delegate mDelegate;
@@ -215,4 +217,55 @@ public final class NetworkStatsSubscriptionsMonitorTest {
verify(mTelephonyManager, times(2)).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
}
+
+
+ @Test
+ public void test5g() {
+ mMonitor.start();
+ // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
+ // before changing RAT type. Also capture listener for later use.
+ addTestSub(TEST_SUBID1, TEST_IMSI1);
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ final RatTypeListener listener = CollectionUtils
+ .find(ratTypeListenerCaptor.getAllValues(), it -> it.getSubId() == TEST_SUBID1);
+ assertNotNull(listener);
+
+ // Set RAT type to 5G NSA (non-standalone) mode, verify the monitor outputs
+ // NETWORK_TYPE_5G_NSA.
+ final ServiceState serviceState = mock(ServiceState.class);
+ when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeChangedForSub(TEST_IMSI1, NetworkTemplate.NETWORK_TYPE_5G_NSA);
+ reset(mDelegate);
+
+ // Set RAT type to LTE without NR connected, the RAT type should be downgraded to LTE.
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
+ reset(mDelegate);
+
+ // Verify NR connected with other RAT type does not take effect.
+ when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_UMTS);
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
+
+ // Set RAT type to 5G standalone mode, the RAT type should be NR.
+ setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_NR);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
+ reset(mDelegate);
+
+ // Set NR state to none in standalone mode does not change anything.
+ when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_NR);
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
+ }
}