summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp23
-rw-r--r--apex/appsearch/framework/Android.bp7
-rw-r--r--apex/blobstore/OWNERS4
-rw-r--r--apex/blobstore/TEST_MAPPING7
-rw-r--r--apex/jobscheduler/framework/Android.bp1
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobInfo.java2
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobParameters.java3
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java2
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java15
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java58
-rw-r--r--apex/media/framework/Android.bp7
-rw-r--r--apex/media/framework/java/android/media/MediaController2.java3
-rw-r--r--apex/sdkext/TEST_MAPPING7
-rw-r--r--apex/sdkextensions/Android.bp (renamed from apex/sdkext/Android.bp)19
-rw-r--r--apex/sdkextensions/OWNERS (renamed from apex/sdkext/OWNERS)0
-rw-r--r--apex/sdkextensions/TEST_MAPPING10
-rw-r--r--apex/sdkextensions/com.android.sdkext.avbpubkey (renamed from apex/sdkext/com.android.sdkext.avbpubkey)bin1032 -> 1032 bytes
-rw-r--r--apex/sdkextensions/com.android.sdkext.pem (renamed from apex/sdkext/com.android.sdkext.pem)0
-rw-r--r--apex/sdkextensions/com.android.sdkext.pk8 (renamed from apex/sdkext/com.android.sdkext.pk8)bin2375 -> 2375 bytes
-rw-r--r--apex/sdkextensions/com.android.sdkext.x509.pem (renamed from apex/sdkext/com.android.sdkext.x509.pem)0
-rw-r--r--apex/sdkextensions/derive_sdk/Android.bp (renamed from apex/sdkext/derive_sdk/Android.bp)22
-rw-r--r--apex/sdkextensions/derive_sdk/derive_sdk.cpp (renamed from apex/sdkext/derive_sdk/derive_sdk.cpp)2
-rw-r--r--apex/sdkextensions/derive_sdk/derive_sdk.rc (renamed from apex/sdkext/derive_sdk/derive_sdk.rc)0
-rw-r--r--apex/sdkextensions/derive_sdk/sdk.proto (renamed from apex/sdkext/derive_sdk/sdk.proto)0
-rw-r--r--apex/sdkextensions/framework/Android.bp (renamed from apex/sdkext/framework/Android.bp)38
-rw-r--r--apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java (renamed from apex/sdkext/framework/java/android/os/ext/SdkExtensions.java)0
-rw-r--r--apex/sdkextensions/framework/java/android/os/ext/package.html (renamed from apex/sdkext/framework/java/android/os/ext/package.html)0
-rw-r--r--apex/sdkextensions/gen_sdkinfo.py (renamed from apex/sdkext/gen_sdkinfo.py)0
-rw-r--r--apex/sdkextensions/ld.config.txt (renamed from apex/sdkext/ld.config.txt)6
-rw-r--r--apex/sdkextensions/manifest.json (renamed from apex/sdkext/manifest.json)0
-rw-r--r--apex/sdkextensions/sdk.proto (renamed from apex/sdkext/sdk.proto)0
-rw-r--r--apex/sdkextensions/testing/Android.bp46
-rw-r--r--apex/sdkextensions/testing/test_manifest.json4
-rw-r--r--apex/statsd/aidl/android/os/IStatsManagerService.aidl40
-rw-r--r--apex/statsd/aidl/android/os/IStatsd.aidl12
-rw-r--r--apex/statsd/framework/Android.bp11
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsManagerService.java110
-rw-r--r--api/current.txt112
-rwxr-xr-xapi/system-current.txt248
-rw-r--r--api/test-current.txt3
-rw-r--r--cmds/statsd/Android.bp26
-rw-r--r--cmds/statsd/src/StatsService.cpp43
-rw-r--r--cmds/statsd/src/StatsService.h9
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp22
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp5
-rw-r--r--cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp99
-rw-r--r--cmds/statsd/src/external/SurfaceflingerStatsPuller.h48
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp102
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h3
-rw-r--r--cmds/statsd/src/metrics/duration_helper/DurationTracker.h2
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp18
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h2
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp7
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h2
-rw-r--r--cmds/statsd/src/subscriber/SubscriberReporter.cpp6
-rw-r--r--cmds/statsd/src/subscriber/SubscriberReporter.h3
-rw-r--r--cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp6
-rw-r--r--cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp96
-rw-r--r--core/java/android/app/ActivityThread.java66
-rw-r--r--core/java/android/app/ClientTransactionHandler.java8
-rw-r--r--core/java/android/app/DownloadManager.java35
-rw-r--r--core/java/android/app/LocalActivityManager.java2
-rw-r--r--core/java/android/app/StatsManager.java28
-rw-r--r--core/java/android/app/StatusBarManager.java29
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java33
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java22
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--core/java/android/app/servertransaction/StartActivityItem.java (renamed from core/java/android/app/servertransaction/WindowVisibilityItem.java)61
-rw-r--r--core/java/android/app/servertransaction/StopActivityItem.java20
-rw-r--r--core/java/android/app/servertransaction/TransactionExecutor.java6
-rw-r--r--core/java/android/app/servertransaction/TransactionExecutorHelper.java3
-rw-r--r--core/java/android/app/timedetector/ManualTimeSuggestion.java2
-rw-r--r--core/java/android/app/timedetector/NetworkTimeSuggestion.java2
-rw-r--r--core/java/android/app/timedetector/PhoneTimeSuggestion.java2
-rw-r--r--core/java/android/app/timedetector/TimeDetector.java2
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java7
-rw-r--r--core/java/android/content/ContentProvider.java78
-rw-r--r--core/java/android/content/ContentProviderOperation.java2
-rw-r--r--core/java/android/content/ContentProviderResult.java8
-rw-r--r--core/java/android/content/ContentResolver.java68
-rw-r--r--core/java/android/content/Context.java13
-rw-r--r--core/java/android/content/pm/CrossProfileApps.java57
-rw-r--r--core/java/android/content/pm/ICrossProfileApps.aidl2
-rw-r--r--core/java/android/content/pm/PackageManager.java7
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java2
-rw-r--r--core/java/android/content/pm/parsing/ComponentParseUtils.java2
-rw-r--r--core/java/android/database/sqlite/SQLiteQueryBuilder.java44
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl7
-rw-r--r--core/java/android/hardware/input/InputManager.java36
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.java68
-rw-r--r--core/java/android/hardware/usb/UsbManager.java12
-rw-r--r--core/java/android/net/ConnectivityDiagnosticsManager.java242
-rw-r--r--core/java/android/net/ConnectivityManager.java87
-rw-r--r--core/java/android/net/DhcpInfo.java8
-rw-r--r--core/java/android/net/IConnectivityManager.aidl8
-rw-r--r--core/java/android/net/IpSecManager.java9
-rw-r--r--core/java/android/net/NetworkCapabilities.java24
-rw-r--r--core/java/android/net/NetworkProvider.java166
-rw-r--r--core/java/android/net/NetworkRequest.java3
-rw-r--r--core/java/android/net/NetworkSpecifier.java9
-rw-r--r--core/java/android/net/NetworkStats.java219
-rw-r--r--core/java/android/net/TrafficStats.java2
-rw-r--r--core/java/android/net/annotations/PolicyDirection.java35
-rw-r--r--core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java70
-rw-r--r--core/java/android/net/netstats/provider/INetworkStatsProvider.aidl28
-rw-r--r--core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl31
-rw-r--r--core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java98
-rw-r--r--core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java48
-rw-r--r--core/java/android/os/Parcel.java106
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java25
-rw-r--r--core/java/android/os/PersistableBundle.java47
-rw-r--r--core/java/android/os/Process.java18
-rw-r--r--core/java/android/os/TelephonyServiceManager.java145
-rw-r--r--core/java/android/os/TimestampedValue.java (renamed from core/java/android/util/TimestampedValue.java)5
-rw-r--r--core/java/android/os/UpdateEngine.java180
-rw-r--r--core/java/android/os/UpdateEngineCallback.java3
-rw-r--r--core/java/android/os/ZygoteProcess.java2
-rw-r--r--core/java/android/os/storage/StorageManager.java206
-rw-r--r--core/java/android/os/storage/StorageVolume.java11
-rw-r--r--core/java/android/provider/DocumentsContract.java4
-rw-r--r--core/java/android/provider/Settings.java75
-rw-r--r--core/java/android/provider/Telephony.java399
-rw-r--r--core/java/android/service/autofill/FillResponse.java10
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java181
-rw-r--r--core/java/android/telephony/WapPushManagerConnector.java178
-rw-r--r--core/java/android/text/SpannableStringInternal.java13
-rw-r--r--core/java/android/util/Log.java20
-rw-r--r--core/java/android/util/NtpTrustedTime.java1
-rw-r--r--core/java/android/view/IDisplayWindowInsetsController.aidl48
-rw-r--r--core/java/android/view/IWindowManager.aidl14
-rw-r--r--core/java/android/view/InsetsAnimationControlCallbacks.java19
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java17
-rw-r--r--core/java/android/view/InsetsController.java121
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java28
-rw-r--r--core/java/android/view/InsetsState.java17
-rw-r--r--core/java/android/view/SurfaceControl.java28
-rw-r--r--core/java/android/view/SurfaceView.java10
-rw-r--r--core/java/android/view/View.java26
-rw-r--r--core/java/android/view/ViewGroup.java22
-rw-r--r--core/java/android/view/ViewRootImpl.java10
-rw-r--r--core/java/android/view/WindowInsets.java43
-rw-r--r--core/java/android/view/WindowInsetsAnimationCallback.java55
-rw-r--r--core/java/android/view/WindowInsetsAnimationControlListener.java7
-rw-r--r--core/java/android/view/WindowInsetsController.java6
-rw-r--r--core/java/android/view/WindowManagerGlobal.java6
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java56
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl4
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java25
-rw-r--r--core/java/android/widget/Editor.java27
-rw-r--r--core/java/android/widget/EditorTouchState.java14
-rw-r--r--core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java315
-rw-r--r--core/java/com/android/internal/app/ISoundTriggerService.aidl4
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl44
-rw-r--r--core/java/com/android/internal/compat/AndroidBuildClassifier.java34
-rw-r--r--core/java/com/android/internal/compat/IOverrideValidator.aidl38
-rw-r--r--core/java/com/android/internal/compat/IPlatformCompat.aidl6
-rw-r--r--core/java/com/android/internal/compat/OverrideAllowedState.aidl19
-rw-r--r--core/java/com/android/internal/compat/OverrideAllowedState.java153
-rw-r--r--core/java/com/android/internal/infra/AndroidFuture.java90
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java31
-rw-r--r--core/java/com/android/internal/os/Zygote.java5
-rw-r--r--core/java/com/android/internal/os/ZygoteArguments.java2
-rw-r--r--core/java/com/android/internal/telephony/IWapPushManager.aidl (renamed from telephony/java/com/android/internal/telephony/IWapPushManager.aidl)13
-rw-r--r--core/java/com/android/internal/telephony/WapPushManagerParams.java72
-rw-r--r--core/java/com/android/internal/util/GrowingArrayUtils.java2
-rw-r--r--core/java/com/android/internal/util/HexDump.java2
-rw-r--r--core/java/com/android/internal/util/IState.java2
-rw-r--r--core/java/com/android/internal/util/IndentingPrintWriter.java3
-rw-r--r--core/java/com/android/internal/util/JournaledFile.java2
-rw-r--r--core/java/com/android/internal/util/MemInfoReader.java2
-rw-r--r--core/java/com/android/internal/util/Preconditions.java2
-rw-r--r--core/java/com/android/internal/util/State.java2
-rw-r--r--core/java/com/android/internal/util/StateMachine.java2
-rw-r--r--core/java/com/android/internal/util/XmlUtils.java4
-rw-r--r--core/java/com/android/internal/view/ActionBarPolicy.java6
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java3
-rw-r--r--core/java/com/android/internal/view/IInputConnectionWrapper.java2
-rw-r--r--core/java/com/android/internal/view/InputBindResult.java2
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java2
-rw-r--r--core/java/com/android/internal/view/WindowManagerPolicyThread.java2
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenu.java8
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuItem.java2
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuItemView.java2
-rw-r--r--core/java/com/android/internal/view/menu/ContextMenuBuilder.java2
-rw-r--r--core/java/com/android/internal/view/menu/IconMenuItemView.java8
-rw-r--r--core/java/com/android/internal/view/menu/IconMenuView.java8
-rw-r--r--core/java/com/android/internal/view/menu/MenuBuilder.java2
-rw-r--r--core/java/com/android/internal/view/menu/MenuDialogHelper.java2
-rw-r--r--core/java/com/android/internal/view/menu/MenuItemImpl.java6
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java2
-rw-r--r--core/java/com/android/internal/view/menu/MenuPresenter.java2
-rw-r--r--core/java/com/android/internal/view/menu/MenuView.java5
-rw-r--r--core/java/com/android/internal/view/menu/SubMenuBuilder.java2
-rw-r--r--core/java/com/android/internal/widget/AbsActionBarView.java17
-rw-r--r--core/java/com/android/internal/widget/ActionBarContextView.java13
-rw-r--r--core/java/com/android/internal/widget/ActionBarOverlayLayout.java3
-rw-r--r--core/java/com/android/internal/widget/AlertDialogLayout.java2
-rw-r--r--core/java/com/android/internal/widget/ButtonBarLayout.java2
-rw-r--r--core/java/com/android/internal/widget/CachingIconView.java2
-rw-r--r--core/java/com/android/internal/widget/DialogTitle.java2
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java2
-rw-r--r--core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java4
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java6
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java2
-rw-r--r--core/java/com/android/internal/widget/NumericTextView.java2
-rw-r--r--core/java/com/android/internal/widget/PointerLocationView.java2
-rw-r--r--core/java/com/android/internal/widget/PreferenceImageView.java2
-rw-r--r--core/java/com/android/internal/widget/RecyclerView.java2
-rw-r--r--core/java/com/android/internal/widget/ScrollBarUtils.java2
-rw-r--r--core/java/com/android/internal/widget/ScrollingTabContainerView.java6
-rw-r--r--core/java/com/android/internal/widget/SlidingTab.java6
-rw-r--r--core/java/com/android/internal/widget/TextViewInputDisabler.java2
-rw-r--r--core/java/com/android/internal/widget/ViewPager.java2
-rw-r--r--core/java/com/android/server/ResettableTimeout.java5
-rw-r--r--core/java/com/android/server/SystemConfig.java15
-rw-r--r--core/java/com/android/server/net/BaseNetworkObserver.java2
-rw-r--r--core/java/com/android/server/net/NetlinkTracker.java2
-rw-r--r--core/java/com/google/android/collect/Lists.java3
-rw-r--r--core/java/com/google/android/collect/Maps.java2
-rw-r--r--core/java/com/google/android/collect/Sets.java2
-rw-r--r--core/java/com/google/android/util/AbstractMessageParser.java2
-rw-r--r--core/java/org/apache/http/conn/ssl/AbstractVerifier.java6
-rw-r--r--core/java/org/apache/http/conn/ssl/SSLSocketFactory.java20
-rw-r--r--core/jni/android/graphics/apex/android_bitmap.cpp93
-rw-r--r--core/jni/android/graphics/apex/include/android/graphics/bitmap.h5
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp12
-rw-r--r--core/jni/fd_utils.cpp42
-rw-r--r--core/proto/android/app/settings_enums.proto11
-rw-r--r--core/proto/android/server/animationadapter.proto10
-rw-r--r--core/res/AndroidManifest.xml11
-rw-r--r--core/res/res/anim/screen_rotate_0_enter.xml40
-rw-r--r--core/res/res/anim/screen_rotate_0_exit.xml37
-rw-r--r--core/res/res/anim/screen_rotate_0_frame.xml25
-rw-r--r--core/res/res/anim/screen_rotate_180_enter.xml12
-rw-r--r--core/res/res/anim/screen_rotate_180_exit.xml12
-rw-r--r--core/res/res/anim/screen_rotate_alpha.xml4
-rw-r--r--core/res/res/anim/screen_rotate_minus_90_enter.xml26
-rw-r--r--core/res/res/anim/screen_rotate_minus_90_exit.xml32
-rw-r--r--core/res/res/anim/screen_rotate_plus_90_enter.xml25
-rw-r--r--core/res/res/anim/screen_rotate_plus_90_exit.xml32
-rw-r--r--core/res/res/interpolator/screen_rotation_alpha_in.xml22
-rw-r--r--core/res/res/interpolator/screen_rotation_alpha_out.xml22
-rw-r--r--core/res/res/layout/accessibility_button_chooser_item.xml2
-rw-r--r--core/res/res/values/config.xml18
-rw-r--r--core/res/res/values/strings.xml5
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java21
-rw-r--r--core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java2
-rw-r--r--core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java4
-rw-r--r--core/tests/coretests/src/android/app/DownloadManagerBaseTest.java9
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java3
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java21
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java52
-rw-r--r--core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java2
-rw-r--r--core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java2
-rw-r--r--core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java2
-rw-r--r--core/tests/coretests/src/android/os/TimestampedValueTest.java (renamed from core/tests/coretests/src/android/util/TimestampedValueTest.java)4
-rw-r--r--core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java4
-rw-r--r--core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java8
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java125
-rw-r--r--core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java4
-rw-r--r--core/tests/coretests/src/android/view/InsetsStateTest.java21
-rw-r--r--core/tests/coretests/src/android/view/WindowInsetsTest.java3
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java (renamed from services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java)44
-rw-r--r--core/tests/coretests/src/android/widget/EditorCursorDragTest.java86
-rw-r--r--core/tests/coretests/src/android/widget/EditorTouchStateTest.java54
-rw-r--r--core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java7
-rw-r--r--core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java140
-rw-r--r--core/xsd/permission.xsd4
-rw-r--r--core/xsd/schema/current.txt7
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--graphics/java/android/graphics/BaseCanvas.java2
-rw-r--r--graphics/java/android/graphics/Bitmap.java2
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java2
-rw-r--r--graphics/java/android/graphics/BitmapRegionDecoder.java2
-rw-r--r--graphics/java/android/graphics/BitmapShader.java2
-rw-r--r--graphics/java/android/graphics/Camera.java2
-rw-r--r--graphics/java/android/graphics/Canvas.java2
-rw-r--r--graphics/java/android/graphics/CanvasProperty.java3
-rw-r--r--graphics/java/android/graphics/ColorMatrixColorFilter.java2
-rw-r--r--graphics/java/android/graphics/FontFamily.java2
-rw-r--r--graphics/java/android/graphics/FontListParser.java2
-rw-r--r--graphics/java/android/graphics/GraphicBuffer.java2
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java2
-rw-r--r--graphics/java/android/graphics/LightingColorFilter.java2
-rw-r--r--graphics/java/android/graphics/LinearGradient.java2
-rw-r--r--graphics/java/android/graphics/Matrix.java2
-rw-r--r--graphics/java/android/graphics/Movie.java2
-rw-r--r--graphics/java/android/graphics/NinePatch.java2
-rw-r--r--graphics/java/android/graphics/Outline.java2
-rw-r--r--graphics/java/android/graphics/Paint.java2
-rw-r--r--graphics/java/android/graphics/Path.java2
-rw-r--r--graphics/java/android/graphics/Picture.java2
-rw-r--r--graphics/java/android/graphics/PorterDuff.java2
-rw-r--r--graphics/java/android/graphics/PorterDuffColorFilter.java2
-rw-r--r--graphics/java/android/graphics/RadialGradient.java2
-rw-r--r--graphics/java/android/graphics/Rect.java2
-rw-r--r--graphics/java/android/graphics/Region.java2
-rw-r--r--graphics/java/android/graphics/Shader.java2
-rw-r--r--graphics/java/android/graphics/SurfaceTexture.java2
-rw-r--r--graphics/java/android/graphics/SweepGradient.java2
-rw-r--r--graphics/java/android/graphics/TableMaskFilter.java2
-rw-r--r--graphics/java/android/graphics/TemporaryBuffer.java3
-rw-r--r--graphics/java/android/graphics/Typeface.java2
-rw-r--r--graphics/java/android/graphics/Xfermode.java2
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedImageDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java14
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/AnimationDrawable.java18
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/ClipDrawable.java20
-rw-r--r--libs/hwui/DeviceInfo.cpp7
-rw-r--r--libs/hwui/DeviceInfo.h7
-rw-r--r--libs/hwui/JankTracker.cpp2
-rw-r--r--libs/hwui/hwui/Bitmap.cpp4
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp5
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp125
-rw-r--r--libs/hwui/renderthread/RenderThread.h17
-rw-r--r--location/java/android/location/Criteria.java321
-rw-r--r--location/java/com/android/internal/location/ProviderProperties.java162
-rw-r--r--location/java/com/android/internal/location/ProviderRequest.java128
-rw-r--r--media/java/android/media/IMediaRoute2Provider.aidl11
-rw-r--r--media/java/android/media/IMediaRouter2Manager.aidl2
-rw-r--r--media/java/android/media/IMediaRouterService.aidl5
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java8
-rw-r--r--media/java/android/media/MediaRoute2Info.java138
-rw-r--r--media/java/android/media/MediaRoute2ProviderInfo.java14
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java87
-rw-r--r--media/java/android/media/MediaRouter2.java253
-rw-r--r--media/java/android/media/MediaRouter2Manager.java39
-rw-r--r--media/java/android/media/MediaRouter2Utils.java100
-rw-r--r--media/java/android/media/MediaScannerConnection.java2
-rw-r--r--media/java/android/media/RouteDiscoveryRequest.aidl19
-rw-r--r--media/java/android/media/RouteDiscoveryRequest.java200
-rw-r--r--media/java/android/media/RouteSessionInfo.java217
-rw-r--r--media/java/android/media/session/MediaSessionManager.java7
-rw-r--r--media/java/android/media/soundtrigger/SoundTriggerDetector.java2
-rw-r--r--media/java/android/media/soundtrigger/SoundTriggerManager.java15
-rw-r--r--media/java/android/media/tv/TvInputInfo.java2
-rwxr-xr-xmedia/java/android/media/tv/TvInputService.java2
-rw-r--r--media/java/android/media/tv/TvTrackInfo.java102
-rw-r--r--media/java/android/media/tv/tuner/Descrambler.java103
-rw-r--r--media/java/android/media/tv/tuner/Dvr.java152
-rw-r--r--media/java/android/media/tv/tuner/Filter.java142
-rw-r--r--media/java/android/media/tv/tuner/FilterConfiguration.java329
-rw-r--r--media/java/android/media/tv/tuner/FrontendCapabilities.java291
-rw-r--r--media/java/android/media/tv/tuner/TimeFilter.java127
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java340
-rw-r--r--media/java/android/media/tv/tuner/TunerConstants.java50
-rw-r--r--media/java/android/media/tv/tuner/TunerUtils.java13
-rw-r--r--media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java35
-rw-r--r--media/java/android/media/tv/tuner/filter/AvSettings.java36
-rw-r--r--media/java/android/media/tv/tuner/filter/DownloadSettings.java32
-rw-r--r--media/java/android/media/tv/tuner/filter/FilterConfiguration.java78
-rw-r--r--media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java38
-rw-r--r--media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java34
-rw-r--r--media/java/android/media/tv/tuner/filter/PesSettings.java92
-rw-r--r--media/java/android/media/tv/tuner/filter/RecordSettings.java33
-rw-r--r--media/java/android/media/tv/tuner/filter/SectionSettings.java31
-rw-r--r--media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java33
-rw-r--r--media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java30
-rw-r--r--media/java/android/media/tv/tuner/filter/Settings.java39
-rw-r--r--media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java36
-rw-r--r--media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java84
-rw-r--r--media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java41
-rw-r--r--media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java65
-rw-r--r--media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java33
-rw-r--r--media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java46
-rw-r--r--media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java46
-rw-r--r--media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java78
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendCallback.java2
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java24
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendInfo.java1
-rw-r--r--media/java/android/media/tv/tuner/frontend/IsdbcFrontendCapabilities.java59
-rw-r--r--media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java40
-rw-r--r--media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java40
-rw-r--r--media/java/android/media/tv/tuner/frontend/ScanMessage.java (renamed from media/java/android/media/tv/tuner/ScanMessage.java)69
-rw-r--r--media/java/android/mtp/MtpPropertyList.java3
-rw-r--r--media/java/android/mtp/MtpStorage.java3
-rw-r--r--media/java/android/service/media/MediaBrowserService.java2
-rw-r--r--media/jni/Android.bp4
-rw-r--r--media/jni/android_media_tv_Tuner.cpp45
-rw-r--r--media/mca/effect/java/android/media/effect/SingleFilterEffect.java3
-rw-r--r--media/mca/filterfw/java/android/filterfw/GraphEnvironment.java4
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/Filter.java10
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/FilterContext.java6
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/FilterGraph.java13
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/Frame.java4
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/FrameFormat.java4
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/FrameManager.java5
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java5
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/GLFrame.java9
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/GraphRunner.java2
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java4
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/Program.java3
-rw-r--r--media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java7
-rw-r--r--media/mca/filterfw/java/android/filterfw/format/ImageFormat.java2
-rw-r--r--media/mca/filterfw/java/android/filterfw/geometry/Point.java3
-rw-r--r--media/mca/filterfw/java/android/filterfw/geometry/Quad.java4
-rw-r--r--media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java52
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java176
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java91
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java87
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/RouteSessionTest.java9
-rw-r--r--mms/OWNERS2
-rw-r--r--mms/java/android/telephony/MmsManager.java29
-rw-r--r--native/graphics/jni/bitmap.cpp10
-rw-r--r--native/graphics/jni/libjnigraphics.map.txt1
-rw-r--r--opengl/java/android/opengl/EGL14.java4
-rw-r--r--opengl/java/android/opengl/GLES20.java2
-rw-r--r--opengl/java/android/opengl/GLSurfaceView.java2
-rw-r--r--opengl/java/javax/microedition/khronos/egl/EGL10.java3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java6
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java28
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java28
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java25
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java17
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java21
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java24
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java6
-rw-r--r--packages/SettingsProvider/Android.bp2
-rw-r--r--packages/SettingsProvider/res/values/overlayable.xml25
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java2
-rw-r--r--packages/SystemUI/docs/broadcasts.md35
-rw-r--r--packages/SystemUI/res/layout/media_carousel.xml35
-rw-r--r--packages/SystemUI/res/layout/people_strip.xml222
-rw-r--r--packages/SystemUI/res/values/strings.xml3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/DumpController.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java158
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java131
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DerivedMember.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java109
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProvider.java148
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt163
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt64
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java333
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt45
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java148
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java225
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java184
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java2
-rw-r--r--packages/Tethering/Android.bp3
-rw-r--r--packages/Tethering/AndroidManifest.xml1
-rw-r--r--packages/Tethering/common/TetheringLib/Android.bp10
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java101
-rw-r--r--packages/Tethering/jarjar-rules.txt1
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java218
-rw-r--r--packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java2
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java52
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java2
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java125
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java38
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java19
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java14
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java96
-rw-r--r--packages/Tethering/tests/unit/jarjar-rules.txt1
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java204
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java12
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java230
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java7
-rw-r--r--rs/java/android/renderscript/BaseObj.java4
-rw-r--r--rs/java/android/renderscript/Element.java2
-rw-r--r--rs/java/android/renderscript/FileA3D.java8
-rw-r--r--rs/java/android/renderscript/Font.java11
-rw-r--r--rs/java/android/renderscript/Matrix4f.java3
-rw-r--r--rs/java/android/renderscript/Mesh.java3
-rw-r--r--rs/java/android/renderscript/Program.java8
-rw-r--r--rs/java/android/renderscript/ProgramFragment.java2
-rw-r--r--rs/java/android/renderscript/ProgramFragmentFixedFunction.java2
-rw-r--r--rs/java/android/renderscript/ProgramRaster.java2
-rw-r--r--rs/java/android/renderscript/ProgramStore.java2
-rw-r--r--rs/java/android/renderscript/ProgramVertex.java2
-rw-r--r--rs/java/android/renderscript/ProgramVertexFixedFunction.java2
-rw-r--r--rs/java/android/renderscript/RSSurfaceView.java2
-rw-r--r--rs/java/android/renderscript/RenderScript.java35
-rw-r--r--rs/java/android/renderscript/RenderScriptCacheDir.java3
-rw-r--r--rs/java/android/renderscript/RenderScriptGL.java2
-rw-r--r--rs/java/android/renderscript/Script.java2
-rw-r--r--rs/jni/Android.mk1
-rw-r--r--rs/jni/android_renderscript_RenderScript.cpp58
-rw-r--r--services/Android.bp2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java63
-rw-r--r--services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java14
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java145
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java27
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java33
-rw-r--r--services/core/Android.bp6
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java159
-rw-r--r--services/core/java/com/android/server/GnssManagerService.java9
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java854
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java88
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java2
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java3
-rw-r--r--services/core/java/com/android/server/RescueParty.java172
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java26
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java4
-rw-r--r--services/core/java/com/android/server/Watchdog.java11
-rw-r--r--services/core/java/com/android/server/adb/AdbDebuggingManager.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java58
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java25
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java31
-rw-r--r--services/core/java/com/android/server/compat/CompatConfig.java96
-rw-r--r--services/core/java/com/android/server/compat/OverrideValidatorImpl.java94
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java67
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java20
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java27
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java31
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java77
-rw-r--r--services/core/java/com/android/server/integrity/IntegrityFileManager.java17
-rw-r--r--services/core/java/com/android/server/integrity/model/BitTrackedInputStream.java69
-rw-r--r--services/core/java/com/android/server/integrity/model/ByteTrackedOutputStream.java (renamed from services/core/java/com/android/server/integrity/serializer/ByteTrackedOutputStream.java)2
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java103
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleIndexRange.java50
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleIndexingController.java62
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleParser.java3
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleXmlParser.java3
-rw-r--r--services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java4
-rw-r--r--services/core/java/com/android/server/location/AbstractLocationProvider.java331
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java39
-rw-r--r--services/core/java/com/android/server/location/LocationProviderProxy.java129
-rw-r--r--services/core/java/com/android/server/location/LocationRequestStatistics.java125
-rw-r--r--services/core/java/com/android/server/location/LocationSettingsStore.java29
-rw-r--r--services/core/java/com/android/server/location/MockProvider.java35
-rw-r--r--services/core/java/com/android/server/location/MockableLocationProvider.java289
-rw-r--r--services/core/java/com/android/server/location/PassiveProvider.java26
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2Provider.java17
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java48
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java123
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java9
-rw-r--r--services/core/java/com/android/server/media/MediaSession2Record.java179
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java50
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecordImpl.java143
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java280
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java161
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider.java30
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsFactory.java6
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java10
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java2
-rw-r--r--services/core/java/com/android/server/notification/OWNERS4
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java87
-rw-r--r--services/core/java/com/android/server/pm/InstallSource.java102
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java55
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java50
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java104
-rw-r--r--services/core/java/com/android/server/pm/Settings.java55
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java27
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java69
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java2
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java73
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java70
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java7
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java109
-rw-r--r--services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java8
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java2
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java48
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java12
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java353
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimationRunner.java4
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java47
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java11
-rw-r--r--services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java97
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp8
-rw-r--r--services/devicepolicy/Android.bp5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java29
-rw-r--r--services/java/com/android/server/SystemServer.java1
-rw-r--r--services/net/java/android/net/ip/IpClientCallbacks.java13
-rw-r--r--services/net/java/android/net/ip/IpClientUtil.java1
-rw-r--r--services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java41
-rw-r--r--services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java74
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java129
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java128
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java58
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java99
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java291
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java52
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java383
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java180
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/model/BitTrackedInputStreamTest.java142
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/model/ByteTrackedOutputStreamTest.java (renamed from services/tests/servicestests/src/com/android/server/integrity/serializer/ByteTrackedOutputStreamTest.java)4
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java102
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java168
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/power/NotifierTest.java287
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java48
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DimmerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java39
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java153
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java68
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java110
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java62
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java27
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java51
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java34
-rw-r--r--telecomm/java/android/telecom/AudioState.java2
-rw-r--r--telecomm/java/android/telecom/Call.java3
-rw-r--r--telecomm/java/android/telecom/CallerInfo.java4
-rw-r--r--telecomm/java/android/telecom/Connection.java2
-rw-r--r--telecomm/java/android/telecom/Log.java2
-rw-r--r--telecomm/java/android/telecom/ParcelableCall.java7
-rw-r--r--telecomm/java/android/telecom/Phone.java2
-rw-r--r--telecomm/java/android/telecom/PhoneAccountHandle.java2
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java38
-rw-r--r--telecomm/java/android/telecom/VideoCallImpl.java2
-rw-r--r--telecomm/java/android/telecom/VideoProfile.java1
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl28
-rw-r--r--telephony/common/android/telephony/LocationAccessPolicy.java2
-rw-r--r--telephony/common/com/android/internal/telephony/CarrierAppUtils.java2
-rw-r--r--telephony/common/com/android/internal/telephony/GsmAlphabet.java4
-rw-r--r--telephony/common/com/android/internal/telephony/HbpcdUtils.java2
-rw-r--r--telephony/common/com/android/internal/telephony/SmsApplication.java2
-rw-r--r--telephony/common/com/android/internal/telephony/SmsConstants.java2
-rw-r--r--telephony/common/com/android/internal/telephony/SmsNumberUtils.java2
-rw-r--r--telephony/common/com/android/internal/telephony/TelephonyPermissions.java2
-rw-r--r--telephony/common/com/android/internal/telephony/util/TelephonyUtils.java (renamed from telephony/java/com/android/internal/telephony/util/TelephonyUtils.java)0
-rw-r--r--telephony/java/android/service/carrier/CarrierIdentifier.java2
-rw-r--r--telephony/java/android/service/euicc/EuiccProfileInfo.java2
-rw-r--r--telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java2
-rw-r--r--telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java2
-rw-r--r--telephony/java/android/telephony/AnomalyReporter.java2
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java20
-rw-r--r--telephony/java/android/telephony/CbGeoUtils.java2
-rw-r--r--telephony/java/android/telephony/CellIdentity.java3
-rw-r--r--telephony/java/android/telephony/CellIdentityGsm.java2
-rw-r--r--telephony/java/android/telephony/CellIdentityLte.java2
-rw-r--r--telephony/java/android/telephony/CellInfoCdma.java2
-rw-r--r--telephony/java/android/telephony/CellInfoGsm.java2
-rw-r--r--telephony/java/android/telephony/CellInfoLte.java2
-rw-r--r--telephony/java/android/telephony/CellInfoTdscdma.java2
-rw-r--r--telephony/java/android/telephony/CellInfoWcdma.java2
-rw-r--r--telephony/java/android/telephony/CellLocation.java7
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthCdma.java2
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthGsm.java2
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthLte.java2
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthNr.java14
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthTdscdma.java2
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthWcdma.java2
-rw-r--r--telephony/java/android/telephony/NetworkScan.java9
-rw-r--r--telephony/java/android/telephony/NetworkService.java2
-rw-r--r--telephony/java/android/telephony/NetworkServiceCallback.java2
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java2
-rw-r--r--telephony/java/android/telephony/ServiceState.java29
-rw-r--r--telephony/java/android/telephony/SignalStrength.java2
-rw-r--r--telephony/java/android/telephony/SmsManager.java46
-rw-r--r--telephony/java/android/telephony/SmsMessage.java2
-rw-r--r--telephony/java/android/telephony/SubscriptionInfo.java2
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java513
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java89
-rw-r--r--telephony/java/android/telephony/TelephonyScanManager.java9
-rw-r--r--telephony/java/android/telephony/UiccAccessRule.java2
-rw-r--r--telephony/java/android/telephony/VoLteServiceState.java2
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java2
-rw-r--r--telephony/java/android/telephony/data/DataService.java2
-rw-r--r--telephony/java/android/telephony/data/DataServiceCallback.java2
-rw-r--r--telephony/java/android/telephony/data/QualifiedNetworksService.java2
-rw-r--r--telephony/java/android/telephony/emergency/EmergencyNumber.java2
-rw-r--r--telephony/java/android/telephony/euicc/EuiccCardManager.java7
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java8
-rw-r--r--telephony/java/android/telephony/ims/ImsConferenceState.java2
-rw-r--r--telephony/java/android/telephony/ims/ImsExternalCallState.java2
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java8
-rw-r--r--telephony/java/android/telephony/ims/ImsRcsManager.java78
-rw-r--r--telephony/java/android/telephony/ims/ImsSsData.java2
-rw-r--r--telephony/java/android/telephony/ims/ProvisioningManager.java14
-rw-r--r--telephony/java/android/telephony/ims/RcsControllerCall.java9
-rw-r--r--telephony/java/android/telephony/ims/RcsUceAdapter.java8
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl10
-rw-r--r--telephony/java/com/android/ims/ImsConfig.java2
-rw-r--r--telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java2
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/SmsMessage.java2
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java2
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java2
-rw-r--r--telephony/java/com/android/internal/telephony/uicc/IccUtils.java2
-rw-r--r--telephony/java/com/android/telephony/Rlog.java154
-rw-r--r--tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java5
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java96
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java28
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java35
-rw-r--r--tests/net/java/android/net/NetworkStatsTest.java334
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsObserversTest.java16
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java110
-rw-r--r--tests/utils/testutils/Android.bp1
-rw-r--r--tests/utils/testutils/java/com/android/server/accessibility/test/MessageCapturingHandler.java (renamed from services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java)4
-rw-r--r--tools/stats_log_api_gen/java_writer.cpp5
-rw-r--r--wifi/Android.bp9
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl4
-rw-r--r--wifi/java/android/net/wifi/SoftApCapability.java9
-rw-r--r--wifi/java/android/net/wifi/SoftApConfiguration.java165
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java10
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java66
-rw-r--r--wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java43
-rw-r--r--wifi/java/com/android/server/wifi/BaseWifiService.java11
-rw-r--r--wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java136
-rw-r--r--wifi/tests/src/android/net/wifi/WifiConfigurationTest.java57
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java28
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java1
825 files changed, 19942 insertions, 9031 deletions
diff --git a/Android.bp b/Android.bp
index bba6185739fd..554ceae3adad 100644
--- a/Android.bp
+++ b/Android.bp
@@ -262,12 +262,13 @@ filegroup {
name: "framework-updatable-sources",
srcs: [
":framework-appsearch-sources",
- ":framework-sdkext-sources",
+ ":framework-sdkextensions-sources",
":framework-statsd-sources",
":framework-tethering-srcs",
":updatable-media-srcs",
":framework-mediaprovider-sources",
":framework-wifi-updatable-sources",
+ ":ike-srcs",
]
}
@@ -432,6 +433,7 @@ java_library {
// TODO(b/146167933): Use framework-statsd-stubs
"framework-statsd",
"framework-wifi-stubs",
+ "ike-stubs",
],
installable: true,
javac_shard_size: 150,
@@ -440,8 +442,6 @@ java_library {
"libcore-platform-compat-config",
"services-platform-compat-config",
"media-provider-platform-compat-config",
- "services-devicepolicy-platform-compat-config",
- "services-core-platform-compat-config",
],
static_libs: [
// If MimeMap ever becomes its own APEX, then this dependency would need to be removed
@@ -481,12 +481,14 @@ java_library {
"updatable_media_stubs",
"framework_mediaprovider_stubs",
"framework-appsearch", // TODO(b/146218515): should be framework-appsearch-stubs
- "framework-sdkext-stubs-systemapi",
+ "framework-sdkextensions-stubs-systemapi",
// TODO(b/146167933): Use framework-statsd-stubs instead.
"framework-statsd",
// TODO(b/140299412): should be framework-wifi-stubs
"framework-wifi",
- // TODO(jiyong): add more stubs for APEXes here
+ "ike-stubs",
+ // TODO(b/147200698): should be the stub of framework-tethering
+ "framework-tethering",
],
sdk_version: "core_platform",
apex_available: ["//apex_available:platform"],
@@ -616,6 +618,15 @@ java_library {
}
filegroup {
+ name: "framework-ike-shared-srcs",
+ visibility: ["//frameworks/opt/net/ike"],
+ srcs: [
+ "core/java/android/net/annotations/PolicyDirection.java",
+ "telephony/java/android/telephony/Annotation.java",
+ ],
+}
+
+filegroup {
name: "framework-networkstack-shared-srcs",
srcs: [
// TODO: remove these annotations as soon as we can use andoid.support.annotations.*
@@ -648,6 +659,7 @@ filegroup {
"core/java/com/android/internal/util/Preconditions.java",
"core/java/com/android/internal/util/State.java",
"core/java/com/android/internal/util/StateMachine.java",
+ "core/java/com/android/internal/util/TrafficStatsConstants.java",
"core/java/android/net/shared/Inet4AddressUtils.java",
],
}
@@ -1134,6 +1146,7 @@ filegroup {
srcs: [
":framework-annotations",
"core/java/android/net/InterfaceConfiguration.java",
+ "core/java/android/os/BasicShellCommandHandler.java",
"core/java/android/os/HandlerExecutor.java",
"core/java/android/util/BackupUtils.java",
"core/java/android/util/LocalLog.java",
diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp
index 3dc5a2c10b6b..1f30dda21ef7 100644
--- a/apex/appsearch/framework/Android.bp
+++ b/apex/appsearch/framework/Android.bp
@@ -26,9 +26,16 @@ java_library {
installable: true,
sdk_version: "core_platform", // TODO(b/146218515) should be core_current
srcs: [":framework-appsearch-sources"],
+ hostdex: true, // for hiddenapi check
libs: [
"framework-minus-apex", // TODO(b/146218515) should be framework-system-stubs
],
+ visibility: [
+ "//frameworks/base/apex/appsearch:__subpackages__",
+ // TODO(b/146218515) remove this when framework is built with the stub of appsearch
+ "//frameworks/base",
+ ],
+ apex_available: ["com.android.appsearch"],
}
metalava_appsearch_docs_args =
diff --git a/apex/blobstore/OWNERS b/apex/blobstore/OWNERS
new file mode 100644
index 000000000000..8e04399196e2
--- /dev/null
+++ b/apex/blobstore/OWNERS
@@ -0,0 +1,4 @@
+set noparent
+
+sudheersai@google.com
+yamasani@google.com
diff --git a/apex/blobstore/TEST_MAPPING b/apex/blobstore/TEST_MAPPING
new file mode 100644
index 000000000000..4dc0c49380c8
--- /dev/null
+++ b/apex/blobstore/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsBlobStoreTestCases"
+ }
+ ]
+} \ No newline at end of file
diff --git a/apex/jobscheduler/framework/Android.bp b/apex/jobscheduler/framework/Android.bp
index 98bbe8243183..ec074262fb13 100644
--- a/apex/jobscheduler/framework/Android.bp
+++ b/apex/jobscheduler/framework/Android.bp
@@ -25,5 +25,6 @@ java_library {
},
libs: [
"framework-minus-apex",
+ "unsupportedappusage",
],
}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 8b3b3a28f2bc..0bb07caf0b00 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -29,7 +29,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.content.ComponentName;
import android.net.NetworkRequest;
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index 42cf17b1264e..ef1351e6d597 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -18,8 +18,7 @@ package android.app.job;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.app.job.IJobCallback;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.net.Network;
import android.net.Uri;
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java b/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java
index c6631fa76494..0c45cbf6dc11 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java
@@ -19,7 +19,7 @@ package android.app.job;
import static android.app.job.JobInfo.NETWORK_BYTES_UNKNOWN;
import android.annotation.BytesLong;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.os.Build;
import android.os.Parcel;
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index 041825c235d0..6109b713de24 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -1,5 +1,6 @@
package com.android.server.usage;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.usage.AppStandbyInfo;
import android.app.usage.UsageEvents;
@@ -99,8 +100,18 @@ public interface AppStandbyInternal {
List<AppStandbyInfo> getAppStandbyBuckets(int userId);
- void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
- int reason, long elapsedRealtime, boolean resetTimeout);
+ /**
+ * Changes an app's standby bucket to the provided value. The caller can only set the standby
+ * bucket for a different app than itself.
+ */
+ void setAppStandbyBucket(@NonNull String packageName, int bucket, int userId, int callingUid,
+ int callingPid);
+
+ /**
+ * Changes the app standby bucket for multiple apps at once.
+ */
+ void setAppStandbyBuckets(@NonNull List<AppStandbyInfo> appBuckets, int userId, int callingUid,
+ int callingPid);
void addActiveDeviceAdmin(String adminPkg, int userId);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 2f8b5130edb0..58eb58961ac4 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -47,6 +47,7 @@ import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppGlobals;
@@ -101,7 +102,6 @@ import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.usage.AppIdleHistory.AppUsageHistory;
-import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
import java.io.File;
import java.io.PrintWriter;
@@ -109,6 +109,7 @@ import java.time.Duration;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -1014,14 +1015,57 @@ public class AppStandbyController implements AppStandbyInternal {
}
}
+ @Override
+ public void setAppStandbyBucket(@NonNull String packageName, int bucket, int userId,
+ int callingUid, int callingPid) {
+ setAppStandbyBuckets(
+ Collections.singletonList(new AppStandbyInfo(packageName, bucket)),
+ userId, callingUid, callingPid);
+ }
+
+ @Override
+ public void setAppStandbyBuckets(@NonNull List<AppStandbyInfo> appBuckets, int userId,
+ int callingUid, int callingPid) {
+ userId = ActivityManager.handleIncomingUser(
+ callingPid, callingUid, userId, false, true, "setAppStandbyBucket", null);
+ final boolean shellCaller = callingUid == Process.ROOT_UID
+ || callingUid == Process.SHELL_UID;
+ final boolean systemCaller = UserHandle.isCore(callingUid);
+ final int reason = systemCaller ? REASON_MAIN_FORCED : REASON_MAIN_PREDICTED;
+ final int packageFlags = PackageManager.MATCH_ANY_USER
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE;
+ final int numApps = appBuckets.size();
+ final long elapsedRealtime = mInjector.elapsedRealtime();
+ for (int i = 0; i < numApps; ++i) {
+ final AppStandbyInfo bucketInfo = appBuckets.get(i);
+ final String packageName = bucketInfo.mPackageName;
+ final int bucket = bucketInfo.mStandbyBucket;
+ if (bucket < STANDBY_BUCKET_ACTIVE || bucket > STANDBY_BUCKET_NEVER) {
+ throw new IllegalArgumentException("Cannot set the standby bucket to " + bucket);
+ }
+ final int packageUid = mInjector.getPackageManagerInternal()
+ .getPackageUid(packageName, packageFlags, userId);
+ // Caller cannot set their own standby state
+ if (packageUid == callingUid) {
+ throw new IllegalArgumentException("Cannot set your own standby bucket");
+ }
+ if (packageUid < 0) {
+ throw new IllegalArgumentException(
+ "Cannot set standby bucket for non existent package (" + packageName + ")");
+ }
+ setAppStandbyBucket(packageName, userId, bucket, reason, elapsedRealtime, shellCaller);
+ }
+ }
+
@VisibleForTesting
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
- int reason, long elapsedRealtime) {
- setAppStandbyBucket(packageName, userId, newBucket, reason, elapsedRealtime, false);
+ int reason) {
+ setAppStandbyBucket(
+ packageName, userId, newBucket, reason, mInjector.elapsedRealtime(), false);
}
- @Override
- public void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
+ private void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
int reason, long elapsedRealtime, boolean resetTimeout) {
synchronized (mAppIdleLock) {
// If the package is not installed, don't allow the bucket to be set.
@@ -1444,6 +1488,10 @@ public class AppStandbyController implements AppStandbyInternal {
mBatteryStats.noteEvent(event, packageName, uid);
}
+ PackageManagerInternal getPackageManagerInternal() {
+ return mPackageManagerInternal;
+ }
+
boolean isPackageEphemeral(int userId, String packageName) {
return mPackageManagerInternal.isPackageEphemeral(userId, packageName);
}
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 6bd0086681a7..18382a488428 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -55,6 +55,13 @@ java_library {
jarjar_rules: "jarjar_rules.txt",
plugins: ["java_api_finder"],
+
+ hostdex: true, // for hiddenapi check
+ visibility: ["//frameworks/av/apex:__subpackages__"],
+ apex_available: [
+ "com.android.media",
+ "test_com.android.media",
+ ],
}
filegroup {
diff --git a/apex/media/framework/java/android/media/MediaController2.java b/apex/media/framework/java/android/media/MediaController2.java
index c3dd3fe4451c..d059c670ccb6 100644
--- a/apex/media/framework/java/android/media/MediaController2.java
+++ b/apex/media/framework/java/android/media/MediaController2.java
@@ -141,6 +141,9 @@ public class MediaController2 implements AutoCloseable {
// Note: unbindService() throws IllegalArgumentException when it's called twice.
return;
}
+ if (DEBUG) {
+ Log.d(TAG, "closing " + this);
+ }
mClosed = true;
if (mServiceConnection != null) {
// Note: This should be called even when the bindService() has returned false.
diff --git a/apex/sdkext/TEST_MAPPING b/apex/sdkext/TEST_MAPPING
deleted file mode 100644
index 91947f39980a..000000000000
--- a/apex/sdkext/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit": [
- {
- "name": "CtsSdkExtTestCases"
- }
- ]
-}
diff --git a/apex/sdkext/Android.bp b/apex/sdkextensions/Android.bp
index f62f167cdcfa..4c5c2b2cfd4f 100644
--- a/apex/sdkext/Android.bp
+++ b/apex/sdkextensions/Android.bp
@@ -18,21 +18,26 @@ package {
apex {
name: "com.android.sdkext",
- manifest: "manifest.json",
+ defaults: [ "com.android.sdkext-defaults" ],
binaries: [ "derive_sdk" ],
- java_libs: [ "framework-sdkext" ],
+ prebuilts: [ "cur_sdkinfo" ],
+ manifest: "manifest.json",
+}
+
+apex_defaults {
+ name: "com.android.sdkext-defaults",
+ java_libs: [ "framework-sdkextensions" ],
prebuilts: [
- "com.android.sdkext.ldconfig",
- "cur_sdkinfo",
- "derive_sdk.rc",
+ "com.android.sdkext.ldconfig",
+ "derive_sdk.rc",
],
key: "com.android.sdkext.key",
certificate: ":com.android.sdkext.certificate",
}
sdk {
- name: "sdkext-sdk",
- java_header_libs: [ "framework-sdkext-stubs-systemapi" ],
+ name: "sdkextensions-sdk",
+ java_header_libs: [ "framework-sdkextensions-stubs-systemapi" ],
}
apex_key {
diff --git a/apex/sdkext/OWNERS b/apex/sdkextensions/OWNERS
index feb274262bef..feb274262bef 100644
--- a/apex/sdkext/OWNERS
+++ b/apex/sdkextensions/OWNERS
diff --git a/apex/sdkextensions/TEST_MAPPING b/apex/sdkextensions/TEST_MAPPING
new file mode 100644
index 000000000000..4e1883382e2c
--- /dev/null
+++ b/apex/sdkextensions/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsSdkExtensionsTestCases"
+ },
+ {
+ "name": "apiextensions_e2e_tests"
+ }
+ ]
+}
diff --git a/apex/sdkext/com.android.sdkext.avbpubkey b/apex/sdkextensions/com.android.sdkext.avbpubkey
index 8f47741ed3b8..8f47741ed3b8 100644
--- a/apex/sdkext/com.android.sdkext.avbpubkey
+++ b/apex/sdkextensions/com.android.sdkext.avbpubkey
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.pem b/apex/sdkextensions/com.android.sdkext.pem
index 816460183aa3..816460183aa3 100644
--- a/apex/sdkext/com.android.sdkext.pem
+++ b/apex/sdkextensions/com.android.sdkext.pem
diff --git a/apex/sdkext/com.android.sdkext.pk8 b/apex/sdkextensions/com.android.sdkext.pk8
index ccc0bf438cd1..ccc0bf438cd1 100644
--- a/apex/sdkext/com.android.sdkext.pk8
+++ b/apex/sdkextensions/com.android.sdkext.pk8
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.x509.pem b/apex/sdkextensions/com.android.sdkext.x509.pem
index 45d2ade354d4..45d2ade354d4 100644
--- a/apex/sdkext/com.android.sdkext.x509.pem
+++ b/apex/sdkextensions/com.android.sdkext.x509.pem
diff --git a/apex/sdkext/derive_sdk/Android.bp b/apex/sdkextensions/derive_sdk/Android.bp
index c4e3c296f210..cf49902d9978 100644
--- a/apex/sdkext/derive_sdk/Android.bp
+++ b/apex/sdkextensions/derive_sdk/Android.bp
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-cc_binary {
- name: "derive_sdk",
+cc_defaults {
+ name: "derive_sdk-defaults",
srcs: [
"derive_sdk.cpp",
"sdk.proto",
@@ -30,6 +30,24 @@ cc_binary {
],
}
+cc_binary {
+ name: "derive_sdk",
+ defaults: [ "derive_sdk-defaults" ],
+ apex_available: [ "com.android.sdkext" ],
+ visibility: [ "//frameworks/base/apex/sdkextensions" ]
+}
+
+// Work around testing using a 64-bit test suite on 32-bit test device by
+// using a prefer32 version of derive_sdk in testing.
+cc_binary {
+ name: "derive_sdk_prefer32",
+ defaults: [ "derive_sdk-defaults" ],
+ compile_multilib: "prefer32",
+ stem: "derive_sdk",
+ apex_available: [ "test_com.android.sdkext" ],
+ visibility: [ "//frameworks/base/apex/sdkextensions/testing" ]
+}
+
prebuilt_etc {
name: "derive_sdk.rc",
src: "derive_sdk.rc",
diff --git a/apex/sdkext/derive_sdk/derive_sdk.cpp b/apex/sdkextensions/derive_sdk/derive_sdk.cpp
index 0a9711677015..6fb7ef43416e 100644
--- a/apex/sdkext/derive_sdk/derive_sdk.cpp
+++ b/apex/sdkextensions/derive_sdk/derive_sdk.cpp
@@ -26,7 +26,7 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include "frameworks/base/apex/sdkext/derive_sdk/sdk.pb.h"
+#include "frameworks/base/apex/sdkextensions/derive_sdk/sdk.pb.h"
using com::android::sdkext::proto::SdkVersion;
diff --git a/apex/sdkext/derive_sdk/derive_sdk.rc b/apex/sdkextensions/derive_sdk/derive_sdk.rc
index 1b667949eeaa..1b667949eeaa 100644
--- a/apex/sdkext/derive_sdk/derive_sdk.rc
+++ b/apex/sdkextensions/derive_sdk/derive_sdk.rc
diff --git a/apex/sdkext/derive_sdk/sdk.proto b/apex/sdkextensions/derive_sdk/sdk.proto
index d15b93552ff4..d15b93552ff4 100644
--- a/apex/sdkext/derive_sdk/sdk.proto
+++ b/apex/sdkextensions/derive_sdk/sdk.proto
diff --git a/apex/sdkext/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index a50dc3d4f349..dd174734df6d 100644
--- a/apex/sdkext/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -17,55 +17,63 @@ package {
}
filegroup {
- name: "framework-sdkext-sources",
+ name: "framework-sdkextensions-sources",
srcs: [
"java/**/*.java",
],
path: "java",
- visibility: [ "//frameworks/base:__pkg__" ] // For the "global" stubs.
+ visibility: [ "//frameworks/base" ] // For the "global" stubs.
}
java_library {
- name: "framework-sdkext",
- srcs: [ ":framework-sdkext-sources" ],
+ name: "framework-sdkextensions",
+ srcs: [ ":framework-sdkextensions-sources" ],
sdk_version: "system_current",
libs: [ "framework-annotations-lib" ],
permitted_packages: [ "android.os.ext" ],
installable: true,
- visibility: [ "//frameworks/base/apex/sdkext:__pkg__" ],
+ visibility: [
+ "//frameworks/base/apex/sdkextensions",
+ "//frameworks/base/apex/sdkextensions/testing",
+ ],
+ hostdex: true, // for hiddenapi check
+ apex_available: [
+ "com.android.sdkext",
+ "test_com.android.sdkext",
+ ],
}
droidstubs {
- name: "framework-sdkext-droidstubs-publicapi",
+ name: "framework-sdkextensions-droidstubs-publicapi",
defaults: [
- "framework-sdkext-stubs-defaults",
+ "framework-sdkextensions-stubs-defaults",
"framework-module-stubs-defaults-publicapi",
]
}
droidstubs {
- name: "framework-sdkext-droidstubs-systemapi",
+ name: "framework-sdkextensions-droidstubs-systemapi",
defaults: [
- "framework-sdkext-stubs-defaults",
+ "framework-sdkextensions-stubs-defaults",
"framework-module-stubs-defaults-systemapi",
]
}
stubs_defaults {
- name: "framework-sdkext-stubs-defaults",
+ name: "framework-sdkextensions-stubs-defaults",
srcs: [
- ":framework-sdkext-sources",
+ ":framework-sdkextensions-sources",
":framework-annotations",
],
sdk_version: "system_current",
}
java_library {
- name: "framework-sdkext-stubs-systemapi",
- srcs: [":framework-sdkext-droidstubs-systemapi"],
+ name: "framework-sdkextensions-stubs-systemapi",
+ srcs: [":framework-sdkextensions-droidstubs-systemapi"],
sdk_version: "system_current",
visibility: [
- "//frameworks/base:__pkg__", // Framework
- "//frameworks/base/apex/sdkext:__pkg__", // sdkext SDK
+ "//frameworks/base", // Framework
+ "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
]
}
diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java
index a8a7effa9b6c..a8a7effa9b6c 100644
--- a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
+++ b/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java
diff --git a/apex/sdkext/framework/java/android/os/ext/package.html b/apex/sdkextensions/framework/java/android/os/ext/package.html
index 34c1697c01fd..34c1697c01fd 100644
--- a/apex/sdkext/framework/java/android/os/ext/package.html
+++ b/apex/sdkextensions/framework/java/android/os/ext/package.html
diff --git a/apex/sdkext/gen_sdkinfo.py b/apex/sdkextensions/gen_sdkinfo.py
index 5af478ba7fe6..5af478ba7fe6 100644
--- a/apex/sdkext/gen_sdkinfo.py
+++ b/apex/sdkextensions/gen_sdkinfo.py
diff --git a/apex/sdkext/ld.config.txt b/apex/sdkextensions/ld.config.txt
index b4470685f4fc..dcc69b892760 100644
--- a/apex/sdkext/ld.config.txt
+++ b/apex/sdkextensions/ld.config.txt
@@ -1,10 +1,10 @@
# Copyright (C) 2019 The Android Open Source Project
#
-# Bionic loader config file for the sdkext apex.
+# Bionic loader config file for the sdkextensions apex.
-dir.sdkext = /apex/com.android.sdkext/bin/
+dir.sdkextensions = /apex/com.android.sdkext/bin/
-[sdkext]
+[sdkextensions]
additional.namespaces = platform
namespace.default.isolated = true
diff --git a/apex/sdkext/manifest.json b/apex/sdkextensions/manifest.json
index 048f5c4f177b..048f5c4f177b 100644
--- a/apex/sdkext/manifest.json
+++ b/apex/sdkextensions/manifest.json
diff --git a/apex/sdkext/sdk.proto b/apex/sdkextensions/sdk.proto
index d15b93552ff4..d15b93552ff4 100644
--- a/apex/sdkext/sdk.proto
+++ b/apex/sdkextensions/sdk.proto
diff --git a/apex/sdkextensions/testing/Android.bp b/apex/sdkextensions/testing/Android.bp
new file mode 100644
index 000000000000..e6451cc29bc2
--- /dev/null
+++ b/apex/sdkextensions/testing/Android.bp
@@ -0,0 +1,46 @@
+// 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.
+
+apex {
+ name: "test_com.android.sdkext",
+ visibility: [ "//system/apex/tests" ],
+ defaults: ["com.android.sdkext-defaults"],
+ manifest: "test_manifest.json",
+ prebuilts: [ "sdkinfo_45" ],
+ file_contexts: ":com.android.sdkext-file_contexts",
+ installable: false, // Should never be installed on the systemimage
+ multilib: {
+ prefer32: {
+ binaries: ["derive_sdk_prefer32"],
+ },
+ },
+ // The automated test infra ends up building this apex for 64+32-bit and
+ // then installs it on a 32-bit-only device. Work around this weirdness
+ // by preferring 32-bit.
+ compile_multilib: "prefer32",
+}
+
+genrule {
+ name: "sdkinfo_45_src",
+ out: [ "sdkinfo.binarypb" ],
+ tools: [ "gen_sdkinfo" ],
+ cmd: "$(location) -v 45 -o $(out)",
+}
+
+prebuilt_etc {
+ name: "sdkinfo_45",
+ src: ":sdkinfo_45_src",
+ filename: "sdkinfo.binarypb",
+ installable: false,
+}
diff --git a/apex/sdkextensions/testing/test_manifest.json b/apex/sdkextensions/testing/test_manifest.json
new file mode 100644
index 000000000000..1b4a2b0c6e60
--- /dev/null
+++ b/apex/sdkextensions/testing/test_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.sdkext",
+ "version": 2147483647
+}
diff --git a/apex/statsd/aidl/android/os/IStatsManagerService.aidl b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
index 055836777678..dec56345ec2f 100644
--- a/apex/statsd/aidl/android/os/IStatsManagerService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
@@ -85,4 +85,44 @@ interface IStatsManagerService {
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
*/
void unsetBroadcastSubscriber(long configKey, long subscriberId, in String packageName);
+
+ /**
+ * Returns the most recently registered experiment IDs.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ long[] getRegisteredExperimentIds();
+
+ /**
+ * Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ byte[] getMetadata(in String packageName);
+
+ /**
+ * Fetches data for the specified configuration key. Returns a byte array representing proto
+ * wire-encoded of ConfigMetricsReportList.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ byte[] getData(in long key, in String packageName);
+
+ /**
+ * Sets a configuration with the specified config id and subscribes to updates for this
+ * configuration id. Broadcasts will be sent if this configuration needs to be collected.
+ * The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
+ * registered in a separate function.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ void addConfiguration(in long configId, in byte[] config, in String packageName);
+
+ /**
+ * Removes the configuration with the matching config id. No-op if this config id does not
+ * exist.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ void removeConfiguration(in long configId, in String packageName);
} \ No newline at end of file
diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
index 935843921feb..c409f516de1b 100644
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -89,24 +89,24 @@ interface IStatsd {
*
* Requires Manifest.permission.DUMP.
*/
- byte[] getData(in long key, in String packageName);
+ byte[] getData(in long key, int callingUid);
/**
* Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
*
* Requires Manifest.permission.DUMP.
*/
- byte[] getMetadata(in String packageName);
+ byte[] getMetadata();
/**
- * Sets a configuration with the specified config key and subscribes to updates for this
+ * Sets a configuration with the specified config id and subscribes to updates for this
* configuration key. Broadcasts will be sent if this configuration needs to be collected.
* The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
* registered in a separate function.
*
* Requires Manifest.permission.DUMP.
*/
- void addConfiguration(in long configKey, in byte[] config, in String packageName);
+ void addConfiguration(in long configId, in byte[] config, in int callingUid);
/**
* Registers the given pending intent for this config key. This intent is invoked when the
@@ -143,12 +143,12 @@ interface IStatsd {
void removeActiveConfigsChangedOperation(int callingUid);
/**
- * Removes the configuration with the matching config key. No-op if this config key does not
+ * Removes the configuration with the matching config id. No-op if this config id does not
* exist.
*
* Requires Manifest.permission.DUMP.
*/
- void removeConfiguration(in long configKey, in String packageName);
+ void removeConfiguration(in long configId, in int callingUid);
/**
* Set the PendingIntentRef to be used when broadcasting subscriber
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index a2b0577fe001..0b46645ad06f 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -37,7 +37,16 @@ java_library {
// TODO(b/146230220): Use framework-system-stubs instead.
"android_system_stubs_current",
],
- // TODO:(b/146210774): Add apex_available field.
+ hostdex: true, // for hiddenapi check
+ visibility: [
+ "//frameworks/base/apex/statsd:__subpackages__",
+ //TODO(b/146167933) remove this when framework is built with framework-statsd-stubs
+ "//frameworks/base",
+ ],
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ ],
}
droidstubs {
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
index 1d03e3b702c4..b27d0f7699fc 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.stats;
import static com.android.server.stats.StatsCompanion.PendingIntentRef;
import android.Manifest;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.Context;
@@ -245,20 +246,127 @@ public class StatsManagerService extends IStatsManagerService.Stub {
}
}
+ @Override
+ public long[] getRegisteredExperimentIds() throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(null);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ return statsd.getRegisteredExperimentIds();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to getRegisteredExperimentIds with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to registerExperimentIds");
+ }
+
+ @Override
+ public byte[] getMetadata(String packageName) throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ return statsd.getMetadata();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to getMetadata with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to getMetadata");
+ }
+
+ @Override
+ public byte[] getData(long key, String packageName) throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ return statsd.getData(key, callingUid);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to getData with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to getData");
+ }
+
+ @Override
+ public void addConfiguration(long configId, byte[] config, String packageName)
+ throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ statsd.addConfiguration(configId, config, callingUid);
+ return;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to addConfiguration with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to addConfig");
+ }
+
+ @Override
+ public void removeConfiguration(long configId, String packageName)
+ throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ statsd.removeConfiguration(configId, callingUid);
+ return;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to removeConfiguration with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to removeConfig");
+ }
+
void setStatsCompanionService(StatsCompanionService statsCompanionService) {
mStatsCompanionService = statsCompanionService;
}
- private void enforceDumpAndUsageStatsPermission(String packageName) {
+ /**
+ * Checks that the caller has both DUMP and PACKAGE_USAGE_STATS permissions. Also checks that
+ * the caller has USAGE_STATS_PERMISSION_OPS for the specified packageName if it is not null.
+ *
+ * @param packageName The packageName to check USAGE_STATS_PERMISSION_OPS.
+ */
+ private void enforceDumpAndUsageStatsPermission(@Nullable String packageName) {
int callingUid = Binder.getCallingUid();
int callingPid = Binder.getCallingPid();
if (callingPid == Process.myPid()) {
return;
}
+
mContext.enforceCallingPermission(Manifest.permission.DUMP, null);
mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS, null);
+ if (packageName == null) {
+ return;
+ }
AppOpsManager appOpsManager = (AppOpsManager) mContext
.getSystemService(Context.APP_OPS_SERVICE);
switch (appOpsManager.noteOp(USAGE_STATS_PERMISSION_OPS,
diff --git a/api/current.txt b/api/current.txt
index 36567ecc1a72..b5448f906e17 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9504,6 +9504,7 @@ package android.content {
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
method @Nullable public final String getCallingFeatureId();
method @Nullable public final String getCallingPackage();
+ method @Nullable public final String getCallingPackageUnchecked();
method @Nullable public final android.content.Context getContext();
method @Nullable public final android.content.pm.PathPermission[] getPathPermissions();
method @Nullable public final String getReadPermission();
@@ -9513,6 +9514,7 @@ package android.content {
method @Nullable public abstract android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues);
method @Nullable public android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable android.os.Bundle);
method protected boolean isTemporary();
+ method public void onCallingPackageChanged();
method public void onConfigurationChanged(android.content.res.Configuration);
method public abstract boolean onCreate();
method public void onLowMemory();
@@ -9627,13 +9629,13 @@ package android.content {
ctor public ContentProviderResult(@NonNull android.net.Uri);
ctor public ContentProviderResult(int);
ctor public ContentProviderResult(@NonNull android.os.Bundle);
- ctor public ContentProviderResult(@NonNull Exception);
+ ctor public ContentProviderResult(@NonNull Throwable);
ctor public ContentProviderResult(android.os.Parcel);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.ContentProviderResult> CREATOR;
field @Nullable public final Integer count;
- field @Nullable public final Exception exception;
+ field @Nullable public final Throwable exception;
field @Nullable public final android.os.Bundle extras;
field @Nullable public final android.net.Uri uri;
}
@@ -9998,6 +10000,7 @@ package android.content {
field public static final String MEDIA_ROUTER_SERVICE = "media_router";
field public static final String MEDIA_SESSION_SERVICE = "media_session";
field public static final String MIDI_SERVICE = "midi";
+ field public static final String MMS_SERVICE = "mms";
field public static final int MODE_APPEND = 32768; // 0x8000
field public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 8; // 0x8
field @Deprecated public static final int MODE_MULTI_PROCESS = 4; // 0x4
@@ -11353,6 +11356,8 @@ package android.content.pm {
}
public class CrossProfileApps {
+ method public boolean canInteractAcrossProfiles();
+ method public boolean canRequestInteractAcrossProfiles();
method @NonNull public android.graphics.drawable.Drawable getProfileSwitchingIconDrawable(@NonNull android.os.UserHandle);
method @NonNull public CharSequence getProfileSwitchingLabel(@NonNull android.os.UserHandle);
method @NonNull public java.util.List<android.os.UserHandle> getTargetUserProfiles();
@@ -11925,6 +11930,7 @@ package android.content.pm {
field public static final String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
field public static final String FEATURE_TELEPHONY = "android.hardware.telephony";
field public static final String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
+ field public static final String FEATURE_TELEPHONY_DATA = "android.hardware.telephony.data";
field public static final String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc";
field public static final String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
field public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
@@ -13323,6 +13329,7 @@ package android.database.sqlite {
method @Deprecated public String buildUnionSubQuery(String, String[], java.util.Set<java.lang.String>, int, String, String, String[], String, String);
method public int delete(@NonNull android.database.sqlite.SQLiteDatabase, @Nullable String, @Nullable String[]);
method @Nullable public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
+ method @Nullable public java.util.Collection<java.util.regex.Pattern> getProjectionGreylist();
method @Nullable public java.util.Map<java.lang.String,java.lang.String> getProjectionMap();
method @Nullable public String getTables();
method public long insert(@NonNull android.database.sqlite.SQLiteDatabase, @NonNull android.content.ContentValues);
@@ -13335,6 +13342,7 @@ package android.database.sqlite {
method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String, String, android.os.CancellationSignal);
method public void setCursorFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
method public void setDistinct(boolean);
+ method public void setProjectionGreylist(@Nullable java.util.Collection<java.util.regex.Pattern>);
method public void setProjectionMap(@Nullable java.util.Map<java.lang.String,java.lang.String>);
method public void setStrict(boolean);
method public void setStrictColumns(boolean);
@@ -25781,8 +25789,8 @@ package android.media {
method @Nullable public android.graphics.Bitmap getImageAtIndex(int);
method @Nullable public android.graphics.Bitmap getPrimaryImage(@NonNull android.media.MediaMetadataRetriever.BitmapParams);
method @Nullable public android.graphics.Bitmap getPrimaryImage();
- method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
- method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
+ method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, @IntRange(from=1) int, @IntRange(from=1) int);
+ method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, @IntRange(from=1) int, @IntRange(from=1) int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public void release();
method public void setDataSource(String) throws java.lang.IllegalArgumentException;
method public void setDataSource(String, java.util.Map<java.lang.String,java.lang.String>) throws java.lang.IllegalArgumentException;
@@ -28683,6 +28691,8 @@ package android.media.tv {
method public int getVideoWidth();
method public boolean isAudioDescription();
method public boolean isEncrypted();
+ method public boolean isHardOfHearing();
+ method public boolean isSpokenSubtitle();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TvTrackInfo> CREATOR;
field public static final int TYPE_AUDIO = 0; // 0x0
@@ -28699,7 +28709,9 @@ package android.media.tv {
method public android.media.tv.TvTrackInfo.Builder setDescription(CharSequence);
method @NonNull public android.media.tv.TvTrackInfo.Builder setEncrypted(boolean);
method public android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
+ method @NonNull public android.media.tv.TvTrackInfo.Builder setHardOfHearing(boolean);
method public android.media.tv.TvTrackInfo.Builder setLanguage(String);
+ method @NonNull public android.media.tv.TvTrackInfo.Builder setSpokenSubtitle(boolean);
method public android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
method public android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
method public android.media.tv.TvTrackInfo.Builder setVideoHeight(int);
@@ -29011,6 +29023,37 @@ package android.net {
field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR;
}
+ public class ConnectivityDiagnosticsManager {
+ method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+ method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+ field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
+ field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
+ }
+
+ public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
+ ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback();
+ method public void onConnectivityReport(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport);
+ method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport);
+ method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
+ }
+
+ public static class ConnectivityDiagnosticsManager.ConnectivityReport {
+ ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
+ field @NonNull public final android.os.PersistableBundle additionalInfo;
+ field @NonNull public final android.net.LinkProperties linkProperties;
+ field @NonNull public final android.net.Network network;
+ field @NonNull public final android.net.NetworkCapabilities networkCapabilities;
+ field public final long reportTimestamp;
+ }
+
+ public static class ConnectivityDiagnosticsManager.DataStallReport {
+ ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.os.PersistableBundle);
+ field public final int detectionMethod;
+ field @NonNull public final android.net.Network network;
+ field public final long reportTimestamp;
+ field @NonNull public final android.os.PersistableBundle stallDetails;
+ }
+
public class ConnectivityManager {
method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
method public boolean bindProcessToNetwork(@Nullable android.net.Network);
@@ -29115,6 +29158,7 @@ package android.net {
ctor public DhcpInfo();
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpInfo> CREATOR;
field public int dns1;
field public int dns2;
field public int gateway;
@@ -29481,6 +29525,7 @@ package android.net {
method public android.net.NetworkRequest.Builder addCapability(int);
method public android.net.NetworkRequest.Builder addTransportType(int);
method public android.net.NetworkRequest build();
+ method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
method public android.net.NetworkRequest.Builder removeCapability(int);
method public android.net.NetworkRequest.Builder removeTransportType(int);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
@@ -30279,6 +30324,7 @@ package android.net.wifi {
@Deprecated public static class WifiConfiguration.AuthAlgorithm {
field @Deprecated public static final int LEAP = 2; // 0x2
field @Deprecated public static final int OPEN = 0; // 0x0
+ field @Deprecated public static final int SAE = 3; // 0x3
field @Deprecated public static final int SHARED = 1; // 0x1
field @Deprecated public static final String[] strings;
field @Deprecated public static final String varName = "auth_alg";
@@ -35681,7 +35727,9 @@ package android.os {
method public int describeContents();
method @Nullable public android.os.PersistableBundle getPersistableBundle(@Nullable String);
method public void putPersistableBundle(@Nullable String, @Nullable android.os.PersistableBundle);
+ method @NonNull public static android.os.PersistableBundle readFromStream(@NonNull java.io.InputStream) throws java.io.IOException;
method public void writeToParcel(android.os.Parcel, int);
+ method public void writeToStream(@NonNull java.io.OutputStream) throws java.io.IOException;
field @NonNull public static final android.os.Parcelable.Creator<android.os.PersistableBundle> CREATOR;
field public static final android.os.PersistableBundle EMPTY;
}
@@ -35783,6 +35831,7 @@ package android.os {
field public static final int THREAD_PRIORITY_URGENT_AUDIO = -19; // 0xffffffed
field public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8; // 0xfffffff8
field public static final int THREAD_PRIORITY_VIDEO = -10; // 0xfffffff6
+ field public static final int WIFI_UID = 1010; // 0x3f2
}
public abstract class ProxyFileDescriptorCallback {
@@ -36349,15 +36398,22 @@ package android.os.storage {
method public boolean isObbMounted(String);
method public boolean mountObb(String, String, android.os.storage.OnObbStateChangeListener);
method @NonNull public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException;
+ method public void registerStorageVolumeCallback(@NonNull java.util.concurrent.Executor, @NonNull android.os.storage.StorageManager.StorageVolumeCallback);
method public void setCacheBehaviorGroup(java.io.File, boolean) throws java.io.IOException;
method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
method public boolean unmountObb(String, boolean, android.os.storage.OnObbStateChangeListener);
+ method public void unregisterStorageVolumeCallback(@NonNull android.os.storage.StorageManager.StorageVolumeCallback);
field public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
field public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
field public static final String EXTRA_UUID = "android.os.storage.extra.UUID";
field public static final java.util.UUID UUID_DEFAULT;
}
+ public static class StorageManager.StorageVolumeCallback {
+ ctor public StorageManager.StorageVolumeCallback();
+ method public void onStateChanged(@NonNull android.os.storage.StorageVolume);
+ }
+
public final class StorageVolume implements android.os.Parcelable {
method @Deprecated @Nullable public android.content.Intent createAccessIntent(String);
method @NonNull public android.content.Intent createOpenDocumentTreeIntent();
@@ -39473,7 +39529,9 @@ package android.provider {
field public static final String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
field public static final String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
+ field public static final String ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION";
field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
+ field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
field public static final String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
field public static final String ACTION_MANAGE_UNKNOWN_APP_SOURCES = "android.settings.MANAGE_UNKNOWN_APP_SOURCES";
@@ -42617,9 +42675,13 @@ package android.service.voice {
method public android.content.Intent createEnrollIntent();
method public android.content.Intent createReEnrollIntent();
method public android.content.Intent createUnEnrollIntent();
+ method public int getParameter(int);
method public int getSupportedRecognitionModes();
+ method @Nullable public android.service.voice.AlwaysOnHotwordDetector.ModelParamRange queryParameter(int);
+ method public int setParameter(int, int);
method public boolean startRecognition(int);
method public boolean stopRecognition();
+ field public static final int MODEL_PARAM_THRESHOLD_FACTOR = 0; // 0x0
field public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 2; // 0x2
field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1
field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2
@@ -42644,6 +42706,11 @@ package android.service.voice {
method @Nullable public byte[] getTriggerAudio();
}
+ public static final class AlwaysOnHotwordDetector.ModelParamRange {
+ method public int end();
+ method public int start();
+ }
+
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
@@ -44959,6 +45026,7 @@ package android.telephony {
field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
field public static final int DATA_CYCLE_USE_PLATFORM_DEFAULT = -1; // 0xffffffff
+ field public static final String ENABLE_EAP_METHOD_PREFIX_BOOL = "enable_eap_method_prefix_bool";
field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
field public static final String KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrp_thresholds_int_array";
@@ -45156,6 +45224,7 @@ package android.telephony {
public static final class CarrierConfigManager.Ims {
field public static final String KEY_PREFIX = "ims.";
+ field public static final String KEY_WIFI_OFF_DEFERRING_TIME_INT = "ims.wifi_off_deferring_time_int";
}
public abstract class CellIdentity implements android.os.Parcelable {
@@ -45464,6 +45533,11 @@ package android.telephony {
method @Nullable public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, @NonNull java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback);
}
+ public final class MmsManager {
+ method public void downloadMultimediaMessage(int, @NonNull String, @NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent);
+ method public void sendMultimediaMessage(int, @NonNull android.net.Uri, @Nullable String, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent);
+ }
+
@Deprecated public class NeighboringCellInfo implements android.os.Parcelable {
ctor @Deprecated public NeighboringCellInfo();
ctor @Deprecated public NeighboringCellInfo(int, int);
@@ -45660,6 +45734,7 @@ package android.telephony {
method public String getOperatorNumeric();
method public boolean getRoaming();
method public int getState();
+ method public boolean isSearching();
method public void setIsManualSelection(boolean);
method public void setOperatorName(String, String, String);
method public void setRoaming(boolean);
@@ -45700,8 +45775,8 @@ package android.telephony {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
- method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
- method @Nullable public android.os.Bundle getCarrierConfigValues();
+ method @Deprecated public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
+ method @NonNull public android.os.Bundle getCarrierConfigValues();
method public static android.telephony.SmsManager getDefault();
method public static int getDefaultSmsSubscriptionId();
method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
@@ -45710,7 +45785,7 @@ package android.telephony {
method public int getSubscriptionId();
method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
- method public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
+ method @Deprecated public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
method public void sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.SEND_SMS}) public void sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
@@ -45918,6 +45993,7 @@ package android.telephony {
public class SubscriptionManager {
method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
method public void addOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
+ method public void addOnSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void addSubscriptionsIntoGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
method public boolean canManageSubscription(android.telephony.SubscriptionInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>);
@@ -46076,12 +46152,12 @@ package android.telephony {
method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
method public boolean hasCarrierPrivileges();
method public boolean hasIccCard();
- method public boolean iccCloseLogicalChannel(int);
- method public byte[] iccExchangeSimIO(int, int, int, int, int, String);
+ method @Deprecated public boolean iccCloseLogicalChannel(int);
+ method @Deprecated public byte[] iccExchangeSimIO(int, int, int, int, int, String);
method @Deprecated public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String);
- method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String, int);
- method public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
- method public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
+ method @Deprecated public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String, int);
+ method @Deprecated public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
+ method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
@@ -46099,7 +46175,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
method public void sendDialerSpecialCode(String);
- method public String sendEnvelopeWithStatus(String);
+ method @Deprecated public String sendEnvelopeWithStatus(String);
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
@@ -51541,9 +51617,10 @@ package android.view {
method public boolean dispatchUnhandledMove(android.view.View, int);
method protected void dispatchVisibilityChanged(@NonNull android.view.View, int);
method public void dispatchWindowFocusChanged(boolean);
- method public void dispatchWindowInsetsAnimationFinished(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
+ method public void dispatchWindowInsetsAnimationFinish(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
+ method public void dispatchWindowInsetsAnimationPrepare(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
method @NonNull public android.view.WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull android.view.WindowInsets);
- method @NonNull public android.view.WindowInsetsAnimationCallback.AnimationBounds dispatchWindowInsetsAnimationStarted(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds);
+ method @NonNull public android.view.WindowInsetsAnimationCallback.AnimationBounds dispatchWindowInsetsAnimationStart(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds);
method public void dispatchWindowSystemUiVisiblityChanged(int);
method public void dispatchWindowVisibilityChanged(int);
method @CallSuper public void draw(android.graphics.Canvas);
@@ -53223,9 +53300,10 @@ package android.view {
}
public interface WindowInsetsAnimationCallback {
- method public default void onFinished(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
+ method public default void onFinish(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
+ method public default void onPrepare(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
method @NonNull public android.view.WindowInsets onProgress(@NonNull android.view.WindowInsets);
- method @NonNull public default android.view.WindowInsetsAnimationCallback.AnimationBounds onStarted(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds);
+ method @NonNull public default android.view.WindowInsetsAnimationCallback.AnimationBounds onStart(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds);
}
public static final class WindowInsetsAnimationCallback.AnimationBounds {
diff --git a/api/system-current.txt b/api/system-current.txt
index 746bf58fd220..b7ea0e617cef 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -152,6 +152,7 @@ package android {
field public static final String PROVIDE_RESOLVER_RANKER_SERVICE = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE";
field public static final String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
field public static final String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
+ field public static final String RADIO_SCAN_WITHOUT_LOCATION = "android.permission.RADIO_SCAN_WITHOUT_LOCATION";
field public static final String READ_ACTIVE_EMERGENCY_SESSION = "android.permission.READ_ACTIVE_EMERGENCY_SESSION";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
@@ -567,6 +568,7 @@ package android.app {
}
public class DownloadManager {
+ method @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public void onMediaStoreDownloadsDeleted(@NonNull android.util.LongSparseArray<java.lang.String>);
field public static final String ACTION_DOWNLOAD_COMPLETED = "android.intent.action.DOWNLOAD_COMPLETED";
}
@@ -677,6 +679,7 @@ package android.app {
public class StatusBarManager {
method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean);
}
public static final class StatusBarManager.DisableInfo {
@@ -799,6 +802,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedKiosk();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isOrganizationOwnedDeviceWithManagedProfile();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUnattendedManagedKiosk();
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
@@ -1652,11 +1656,17 @@ package android.content {
method @NonNull public final android.os.UserHandle getSendingUser();
}
+ public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
+ method public int checkUriPermission(@NonNull android.net.Uri, int, int);
+ }
+
public class ContentProviderClient implements java.lang.AutoCloseable {
method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
}
public abstract class ContentResolver {
+ method @NonNull public static android.net.Uri decodeFromFile(@NonNull java.io.File);
+ method @NonNull public static java.io.File encodeToFile(@NonNull android.net.Uri);
method @Nullable @RequiresPermission("android.permission.CACHE_CONTENT") public android.os.Bundle getCache(@NonNull android.net.Uri);
method @RequiresPermission("android.permission.CACHE_CONTENT") public void putCache(@NonNull android.net.Uri, @Nullable android.os.Bundle);
}
@@ -1697,6 +1707,7 @@ package android.content {
field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
field public static final String TETHERING_SERVICE = "tethering";
field public static final String VR_SERVICE = "vrmanager";
+ field public static final String WIFI_COND_SERVICE = "wificond";
field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
}
@@ -3535,7 +3546,6 @@ package android.hardware.soundtrigger {
}
public static final class SoundTrigger.ModelParamRange implements android.os.Parcelable {
- method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.ModelParamRange> CREATOR;
field public final int end;
@@ -3579,9 +3589,17 @@ package android.hardware.usb {
}
public class UsbManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public long getCurrentFunctions();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USB) public java.util.List<android.hardware.usb.UsbPort> getPorts();
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void grantPermission(android.hardware.usb.UsbDevice, String);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long);
field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
+ field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE";
+ field public static final long FUNCTION_NONE = 0L; // 0x0L
+ field public static final long FUNCTION_RNDIS = 32L; // 0x20L
+ field public static final String USB_CONFIGURED = "configured";
+ field public static final String USB_CONNECTED = "connected";
+ field public static final String USB_FUNCTION_RNDIS = "rndis";
}
public final class UsbPort {
@@ -4294,7 +4312,7 @@ package android.media.session {
}
public static interface MediaSessionManager.OnMediaKeyEventDispatchedListener {
- method public default void onMediaKeyEventDispatched(@NonNull android.view.KeyEvent, @NonNull String, @NonNull android.media.session.MediaSession.Token);
+ method public default void onMediaKeyEventDispatched(@NonNull android.view.KeyEvent, @NonNull String, @Nullable android.media.session.MediaSession.Token);
}
public static interface MediaSessionManager.OnMediaKeyEventSessionChangedListener {
@@ -4350,9 +4368,9 @@ package android.media.soundtrigger {
method public int getDetectionServiceOperationsTimeout();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModuleProperties getModuleProperties();
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int getParameter(@NonNull java.util.UUID, int) throws java.lang.IllegalArgumentException, java.lang.UnsupportedOperationException;
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int getParameter(@NonNull java.util.UUID, int);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModelParamRange queryParameter(@Nullable java.util.UUID, int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int setParameter(@Nullable java.util.UUID, int, int) throws java.lang.IllegalArgumentException, java.lang.UnsupportedOperationException;
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int setParameter(@Nullable java.util.UUID, int, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
}
@@ -4678,6 +4696,7 @@ package android.net {
method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
@@ -4685,6 +4704,7 @@ package android.net {
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
@@ -4824,6 +4844,7 @@ package android.net {
public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
ctor public MatchAllNetworkSpecifier();
method public int describeContents();
+ method public boolean satisfiedBy(android.net.NetworkSpecifier);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.MatchAllNetworkSpecifier> CREATOR;
}
@@ -4835,6 +4856,7 @@ package android.net {
}
public final class NetworkCapabilities implements android.os.Parcelable {
+ method public boolean deduceRestrictedCapability();
method @NonNull public int[] getTransportTypes();
method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
method @NonNull public android.net.NetworkCapabilities setSSID(@Nullable String);
@@ -4854,6 +4876,17 @@ package android.net {
field public final android.net.WifiKey wifiKey;
}
+ public class NetworkProvider {
+ ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
+ method @Nullable public android.os.Messenger getMessenger();
+ method @NonNull public String getName();
+ method public int getProviderId();
+ method public void onNetworkRequested(@NonNull android.net.NetworkRequest, int, int);
+ method public void onRequestWithdrawn(@NonNull android.net.NetworkRequest);
+ field public static final int ID_NONE = -1; // 0xffffffff
+ }
+
public abstract class NetworkRecommendationProvider {
ctor public NetworkRecommendationProvider(android.content.Context, java.util.concurrent.Executor);
method public final android.os.IBinder getBinder();
@@ -4887,10 +4920,43 @@ package android.net {
method public void updateScores(@NonNull java.util.List<android.net.ScoredNetwork>);
}
+ public abstract class NetworkSpecifier {
+ method public void assertValidFromUid(int);
+ method @Nullable public android.net.NetworkSpecifier redact();
+ method public abstract boolean satisfiedBy(@Nullable android.net.NetworkSpecifier);
+ }
+
public class NetworkStack {
field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK";
}
+ public final class NetworkStats implements android.os.Parcelable {
+ ctor public NetworkStats(long, int);
+ method @NonNull public android.net.NetworkStats add(@NonNull android.net.NetworkStats);
+ method @NonNull public android.net.NetworkStats addValues(@NonNull android.net.NetworkStats.Entry);
+ method public int describeContents();
+ method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR;
+ field public static final int DEFAULT_NETWORK_NO = 0; // 0x0
+ field public static final int DEFAULT_NETWORK_YES = 1; // 0x1
+ field @Nullable public static final String IFACE_ALL;
+ field public static final String IFACE_VT = "vt_data0";
+ field public static final int METERED_NO = 0; // 0x0
+ field public static final int METERED_YES = 1; // 0x1
+ field public static final int ROAMING_NO = 0; // 0x0
+ field public static final int ROAMING_YES = 1; // 0x1
+ field public static final int SET_DEFAULT = 0; // 0x0
+ field public static final int SET_FOREGROUND = 1; // 0x1
+ field public static final int TAG_NONE = 0; // 0x0
+ field public static final int UID_ALL = -1; // 0xffffffff
+ field public static final int UID_TETHERING = -5; // 0xfffffffb
+ }
+
+ public static class NetworkStats.Entry {
+ ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
+ }
+
public final class RouteInfo implements android.os.Parcelable {
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
method public int getType();
@@ -4957,6 +5023,7 @@ package android.net {
public final class StringNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
ctor public StringNetworkSpecifier(@NonNull String);
method public int describeContents();
+ method public boolean satisfiedBy(android.net.NetworkSpecifier);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.StringNetworkSpecifier> CREATOR;
field @NonNull public final String specifier;
@@ -5481,6 +5548,25 @@ package android.net.metrics {
}
+package android.net.netstats.provider {
+
+ public abstract class AbstractNetworkStatsProvider {
+ ctor public AbstractNetworkStatsProvider();
+ method public abstract void requestStatsUpdate(int);
+ method public abstract void setAlert(long);
+ method public abstract void setLimit(@NonNull String, long);
+ field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff
+ }
+
+ public class NetworkStatsProviderCallback {
+ method public void onAlertReached();
+ method public void onLimitReached();
+ method public void onStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats);
+ method public void unregister();
+ }
+
+}
+
package android.net.util {
public final class SocketUtils {
@@ -5740,6 +5826,7 @@ package android.net.wifi {
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApCapability> CREATOR;
field public static final int SOFTAP_FEATURE_ACS_OFFLOAD = 1; // 0x1
field public static final int SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 2; // 0x2
+ field public static final int SOFTAP_FEATURE_WPA3_SAE = 4; // 0x4
}
public final class SoftApConfiguration implements android.os.Parcelable {
@@ -5748,9 +5835,10 @@ package android.net.wifi {
method @Nullable public android.net.MacAddress getBssid();
method public int getChannel();
method public int getMaxNumberOfClients();
+ method @Nullable public String getPassphrase();
method public int getSecurityType();
+ method public int getShutdownTimeoutMillis();
method @Nullable public String getSsid();
- method @Nullable public String getWpa2Passphrase();
method public boolean isHiddenSsid();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int BAND_2GHZ = 1; // 0x1
@@ -5760,6 +5848,8 @@ package android.net.wifi {
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApConfiguration> CREATOR;
field public static final int SECURITY_TYPE_OPEN = 0; // 0x0
field public static final int SECURITY_TYPE_WPA2_PSK = 1; // 0x1
+ field public static final int SECURITY_TYPE_WPA3_SAE = 3; // 0x3
+ field public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2; // 0x2
}
public static final class SoftApConfiguration.Builder {
@@ -5771,8 +5861,9 @@ package android.net.wifi {
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setWpa2Passphrase(@Nullable String);
}
public final class SoftApInfo implements android.os.Parcelable {
@@ -5915,6 +6006,7 @@ package android.net.wifi {
public class WifiManager {
method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoinPasspoint(@NonNull String, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
@@ -5934,6 +6026,7 @@ package android.net.wifi {
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(@NonNull java.util.List<android.net.wifi.ScanResult>);
method public boolean isApMacRandomizationSupported();
method public boolean isConnectedMacRandomizationSupported();
method @Deprecated public boolean isDeviceToDeviceRttSupported();
@@ -5991,6 +6084,7 @@ package android.net.wifi {
field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
field public static final String EXTRA_URL = "android.net.wifi.extra.URL";
+ field public static final String EXTRA_WIFI_AP_FAILURE_REASON = "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
field public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
field public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
@@ -6069,6 +6163,10 @@ package android.net.wifi {
field public int numUsage;
}
+ public final class WifiNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+ method public boolean satisfiedBy(android.net.NetworkSpecifier);
+ }
+
public static final class WifiNetworkSuggestion.Builder {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int);
}
@@ -6255,6 +6353,10 @@ package android.net.wifi.aware {
method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPmk(@NonNull android.net.wifi.aware.PeerHandle, @NonNull byte[]);
}
+ public final class WifiAwareNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+ method public boolean satisfiedBy(android.net.NetworkSpecifier);
+ }
+
public class WifiAwareSession implements java.lang.AutoCloseable {
method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, @NonNull byte[], @NonNull byte[]);
}
@@ -6271,6 +6373,10 @@ package android.net.wifi.hotspot2 {
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.OsuProvider> CREATOR;
}
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ method public boolean isAutoJoinEnabled();
+ }
+
public abstract class ProvisioningCallback {
ctor public ProvisioningCallback();
method public abstract void onProvisioningComplete();
@@ -6937,6 +7043,10 @@ package android.os {
method public boolean hasSingleFileDescriptor();
}
+ public class ParcelFileDescriptor implements java.io.Closeable android.os.Parcelable {
+ method @NonNull public static android.os.ParcelFileDescriptor wrap(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.Handler, @NonNull android.os.ParcelFileDescriptor.OnCloseListener) throws java.io.IOException;
+ }
+
public final class PowerManager {
method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long);
method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend();
@@ -7045,7 +7155,22 @@ package android.os {
}
public class TelephonyServiceManager {
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getCarrierConfigServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getEuiccCardControllerServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getEuiccControllerService();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getIccPhoneBookServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getNetworkPolicyServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getOpportunisticNetworkServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPackageManagerServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPermissionManagerServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPhoneSubServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getSmsServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getSubscriptionServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyImsServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyRcsMessageServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyRegistryServiceRegisterer();
method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getWindowServiceRegisterer();
}
public static class TelephonyServiceManager.ServiceNotFoundException extends java.lang.Exception {
@@ -7061,11 +7186,13 @@ package android.os {
public class UpdateEngine {
ctor public UpdateEngine();
+ method @NonNull public android.os.UpdateEngine.AllocateSpaceResult allocateSpace(@NonNull String, @NonNull String[]);
method public void applyPayload(String, long, long, String[]);
- method public void applyPayload(@NonNull android.os.ParcelFileDescriptor, long, long, @NonNull String[]);
+ method public void applyPayload(@NonNull android.content.res.AssetFileDescriptor, @NonNull String[]);
method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler);
method public boolean bind(android.os.UpdateEngineCallback);
method public void cancel();
+ method public int cleanupAppliedPayload();
method public void resetStatus();
method public void resume();
method public void suspend();
@@ -7073,14 +7200,21 @@ package android.os {
method public boolean verifyPayloadMetadata(String);
}
+ public static final class UpdateEngine.AllocateSpaceResult {
+ method public int errorCode();
+ method public long freeSpaceRequired();
+ }
+
public static final class UpdateEngine.ErrorCodeConstants {
ctor public UpdateEngine.ErrorCodeConstants();
+ field public static final int DEVICE_CORRUPTED = 61; // 0x3d
field public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12; // 0xc
field public static final int DOWNLOAD_TRANSFER_ERROR = 9; // 0x9
field public static final int ERROR = 1; // 0x1
field public static final int FILESYSTEM_COPIER_ERROR = 4; // 0x4
field public static final int INSTALL_DEVICE_OPEN_ERROR = 7; // 0x7
field public static final int KERNEL_DEVICE_OPEN_ERROR = 8; // 0x8
+ field public static final int NOT_ENOUGH_SPACE = 60; // 0x3c
field public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; // 0xa
field public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; // 0x6
field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb
@@ -7316,6 +7450,10 @@ package android.os.storage {
field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
}
+ public final class StorageVolume implements android.os.Parcelable {
+ method @NonNull public String getId();
+ }
+
}
package android.permission {
@@ -7725,6 +7863,7 @@ package android.provider {
}
public final class Settings {
+ method public static boolean checkAndNoteWriteSettingsOperation(@NonNull android.content.Context, int, @NonNull String, boolean);
field public static final String ACTION_ACCESSIBILITY_DETAILS_SETTINGS = "android.settings.ACCESSIBILITY_DETAILS_SETTINGS";
field public static final String ACTION_BUGREPORT_HANDLER_SETTINGS = "android.settings.BUGREPORT_HANDLER_SETTINGS";
field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
@@ -7735,6 +7874,7 @@ package android.provider {
field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS";
field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
+ field public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI";
}
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
@@ -7754,6 +7894,7 @@ package android.provider {
field public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis";
field public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
field public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
+ field public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled";
field public static final String TETHER_SUPPORTED = "tether_supported";
field public static final String THEATER_MODE_ON = "theater_mode_on";
field public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
@@ -7893,7 +8034,71 @@ package android.provider {
}
public static final class Telephony.SimInfo {
+ field public static final String ACCESS_RULES = "access_rules";
+ field public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS = "access_rules_from_carrier_configs";
+ field public static final String CARD_ID = "card_id";
+ field public static final String CARRIER_ID = "carrier_id";
+ field public static final String CARRIER_NAME = "carrier_name";
+ field public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+ field public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+ field public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+ field public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+ field public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+ field public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+ field public static final String CB_CMAS_TEST_ALERT = "enable_cmas_test_alerts";
+ field public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+ field public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+ field public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+ field public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+ field public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+ field public static final String COLOR = "color";
field @NonNull public static final android.net.Uri CONTENT_URI;
+ field public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+ field public static final String DATA_ROAMING = "data_roaming";
+ field public static final int DATA_ROAMING_DEFAULT = 0; // 0x0
+ field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
+ field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+ field public static final String DISPLAY_NAME = "display_name";
+ field public static final String EHPLMNS = "ehplmns";
+ field public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+ field public static final String GROUP_OWNER = "group_owner";
+ field public static final String GROUP_UUID = "group_uuid";
+ field public static final String HPLMNS = "hplmns";
+ field public static final String ICC_ID = "icc_id";
+ field public static final String IMSI = "imsi";
+ field public static final String ISO_COUNTRY_CODE = "iso_country_code";
+ field public static final String IS_EMBEDDED = "is_embedded";
+ field public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+ field public static final String IS_REMOVABLE = "is_removable";
+ field public static final String MCC = "mcc";
+ field public static final String MCC_STRING = "mcc_string";
+ field public static final String MNC = "mnc";
+ field public static final String MNC_STRING = "mnc_string";
+ field public static final String NAME_SOURCE = "name_source";
+ field public static final int NAME_SOURCE_CARRIER = 3; // 0x3
+ field public static final int NAME_SOURCE_DEFAULT = 0; // 0x0
+ field public static final int NAME_SOURCE_SIM_PNN = 4; // 0x4
+ field public static final int NAME_SOURCE_SIM_SPN = 1; // 0x1
+ field public static final int NAME_SOURCE_USER_INPUT = 2; // 0x2
+ field public static final String NUMBER = "number";
+ field public static final String PROFILE_CLASS = "profile_class";
+ field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
+ field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
+ field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1
+ field public static final int PROFILE_CLASS_TESTING = 0; // 0x0
+ field public static final int PROFILE_CLASS_UNSET = -1; // 0xffffffff
+ field public static final int SIM_NOT_INSERTED = -1; // 0xffffffff
+ field public static final String SIM_SLOT_INDEX = "sim_id";
+ field public static final String SUBSCRIPTION_TYPE = "subscription_type";
+ field public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0; // 0x0
+ field public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1; // 0x1
+ field public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+ field public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+ field public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+ field public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+ field public static final String WFC_IMS_MODE = "wfc_ims_mode";
+ field public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+ field public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
}
public static final class Telephony.Sms.Intents {
@@ -9160,30 +9365,37 @@ package android.telephony {
public abstract class CellIdentity implements android.os.Parcelable {
method @NonNull public abstract android.telephony.CellLocation asCellLocation();
+ method @NonNull public abstract android.telephony.CellIdentity sanitizeLocationInfo();
}
public final class CellIdentityCdma extends android.telephony.CellIdentity {
method @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo();
}
public final class CellIdentityGsm extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityGsm sanitizeLocationInfo();
}
public final class CellIdentityLte extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityLte sanitizeLocationInfo();
}
public final class CellIdentityNr extends android.telephony.CellIdentity {
method @NonNull public android.telephony.CellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityNr sanitizeLocationInfo();
}
public final class CellIdentityTdscdma extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityTdscdma sanitizeLocationInfo();
}
public final class CellIdentityWcdma extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityWcdma sanitizeLocationInfo();
}
public final class DataFailCause {
@@ -10191,10 +10403,10 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int);
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
@@ -10361,6 +10573,20 @@ package android.telephony {
method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
}
+ public final class WapPushManagerConnector {
+ ctor public WapPushManagerConnector(@NonNull android.content.Context);
+ method public boolean bindToWapPushManagerService();
+ method @Nullable public String getConnectedWapPushManagerServicePackage();
+ method public int processMessage(@NonNull String, @NonNull String, @NonNull android.content.Intent);
+ method public void unbindWapPushManagerService();
+ field public static final int RESULT_APP_QUERY_FAILED = 2; // 0x2
+ field public static final int RESULT_EXCEPTION_CAUGHT = 16; // 0x10
+ field public static final int RESULT_FURTHER_PROCESSING = 32768; // 0x8000
+ field public static final int RESULT_INVALID_RECEIVER_NAME = 8; // 0x8
+ field public static final int RESULT_MESSAGE_HANDLED = 1; // 0x1
+ field public static final int RESULT_SIGNATURE_NO_MATCH = 4; // 0x4
+ }
+
}
package android.telephony.cdma {
@@ -11611,6 +11837,8 @@ package android.view.accessibility {
public final class AccessibilityManager {
method public int getAccessibilityWindowId(@Nullable android.os.IBinder);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void registerSystemAction(@NonNull android.app.RemoteAction, int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void unregisterSystemAction(int);
}
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 99679428cefb..d017dd63bdd3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -437,6 +437,7 @@ package android.app {
public class StatusBarManager {
method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean);
}
public static final class StatusBarManager.DisableInfo {
@@ -2551,6 +2552,7 @@ package android.provider {
field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
field public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION = "android.settings.MANAGE_APP_OVERLAY_PERMISSION";
field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
+ field public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI";
field public static final int RESET_MODE_PACKAGE_DEFAULTS = 1; // 0x1
}
@@ -2569,6 +2571,7 @@ package android.provider {
field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
field public static final String NOTIFICATION_BUBBLES = "notification_bubbles";
field public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices";
+ field public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled";
field public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 7b96ce92e307..1c6867c39790 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -78,7 +78,6 @@ cc_defaults {
"src/external/StatsPuller.cpp",
"src/external/StatsPullerManager.cpp",
"src/external/SubsystemSleepStatePuller.cpp",
- "src/external/SurfaceflingerStatsPuller.cpp",
"src/external/TrainInfoPuller.cpp",
"src/FieldValue.cpp",
"src/guardrail/StatsdStats.cpp",
@@ -126,30 +125,28 @@ cc_defaults {
],
static_libs: [
- "libhealthhalutils",
- "libplatformprotos",
- ],
-
- shared_libs: [
"android.frameworks.stats@1.0",
- "android.hardware.health@2.0",
"android.hardware.power.stats@1.0",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
"libbase",
- "libbinder",
"libcutils",
- "libgraphicsenv",
- "libhidlbase",
- "libincident",
+ "libhealthhalutils",
"liblog",
+ "libplatformprotos",
"libprotoutil",
- "libservices",
"libstatslog",
- "libstatsmetadata",
"libstatssocket",
"libsysutils",
- "libtimestats_proto",
+ ],
+ shared_libs: [
+ "android.hardware.health@2.0",
+ "libbinder",
+ "libgraphicsenv",
+ "libhidlbase",
+ "libincident",
+ "libservices",
+ "libstatsmetadata",
"libutils",
],
}
@@ -298,7 +295,6 @@ cc_test {
"tests/external/puller_util_test.cpp",
"tests/external/StatsCallbackPuller_test.cpp",
"tests/external/StatsPuller_test.cpp",
- "tests/external/SurfaceflingerStatsPuller_test.cpp",
"tests/FieldValue_test.cpp",
"tests/guardrail/StatsdStats_test.cpp",
"tests/indexed_priority_queue_test.cpp",
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 5ff0f97865b8..1ca19c3417c2 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1135,12 +1135,11 @@ void StatsService::OnLogEvent(LogEvent* event) {
}
}
-Status StatsService::getData(int64_t key, const String16& packageName, vector<uint8_t>* output) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+Status StatsService::getData(int64_t key, const int32_t callingUid, vector<uint8_t>* output) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
- ConfigKey configKey(ipc->getCallingUid(), key);
+ VLOG("StatsService::getData with Uid %i", callingUid);
+ ConfigKey configKey(callingUid, key);
// The dump latency does not matter here since we do not include the current bucket, we do not
// need to pull any new data anyhow.
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
@@ -1148,22 +1147,18 @@ Status StatsService::getData(int64_t key, const String16& packageName, vector<ui
return Status::ok();
}
-Status StatsService::getMetadata(const String16& packageName, vector<uint8_t>* output) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+Status StatsService::getMetadata(vector<uint8_t>* output) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- VLOG("StatsService::getMetadata with Pid %i, Uid %i", ipc->getCallingPid(),
- ipc->getCallingUid());
StatsdStats::getInstance().dumpStats(output, false); // Don't reset the counters.
return Status::ok();
}
Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config,
- const String16& packageName) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+ const int32_t callingUid) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- if (addConfigurationChecked(ipc->getCallingUid(), key, config)) {
+ if (addConfigurationChecked(callingUid, key, config)) {
return Status::ok();
} else {
ALOGE("Could not parse malformatted StatsdConfig");
@@ -1228,13 +1223,11 @@ Status StatsService::removeActiveConfigsChangedOperation(const int32_t callingUi
return Status::ok();
}
-Status StatsService::removeConfiguration(int64_t key, const String16& packageName) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+Status StatsService::removeConfiguration(int64_t key, const int32_t callingUid) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- ConfigKey configKey(ipc->getCallingUid(), key);
+ ConfigKey configKey(callingUid, key);
mConfigManager->RemoveConfig(configKey);
- SubscriberReporter::getInstance().removeConfig(configKey);
return Status::ok();
}
@@ -1477,17 +1470,7 @@ Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackType
Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) {
- uid_t uid = IPCThreadState::self()->getCallingUid();
-
- // Caller must be granted these permissions
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d lacks permission %s", uid, kPermissionDump));
- }
- if (!checkCallingPermission(String16(kPermissionUsage))) {
- return exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage));
- }
+ ENFORCE_UID(AID_SYSTEM);
// TODO: add verifier permission
// Read the latest train info
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 0565f3ce2484..c9a9072ecb92 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -99,15 +99,14 @@ public:
* Binder call for clients to request data for this configuration key.
*/
virtual Status getData(int64_t key,
- const String16& packageName,
+ const int32_t callingUid,
vector<uint8_t>* output) override;
/**
* Binder call for clients to get metadata across all configs in statsd.
*/
- virtual Status getMetadata(const String16& packageName,
- vector<uint8_t>* output) override;
+ virtual Status getMetadata(vector<uint8_t>* output) override;
/**
@@ -116,7 +115,7 @@ public:
*/
virtual Status addConfiguration(int64_t key,
const vector<uint8_t>& config,
- const String16& packageName) override;
+ const int32_t callingUid) override;
/**
* Binder call to let clients register the data fetch operation for a configuration.
@@ -146,7 +145,7 @@ public:
* Binder call to allow clients to remove the specified configuration.
*/
virtual Status removeConfiguration(int64_t key,
- const String16& packageName) override;
+ const int32_t callingUid) override;
/**
* Binder call to associate the given config's subscriberId with the given pendingIntentRef.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 55d73c1ae342..972adf7d4d05 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -189,25 +189,11 @@ void ConfigManager::RemoveConfig(const ConfigKey& key) {
// Remove from map
uidIt->second.erase(key);
- // No more configs for this uid, lets remove the active configs callback.
- if (uidIt->second.empty()) {
- auto itActiveConfigsChangedReceiver = mActiveConfigsChangedReceivers.find(uid);
- if (itActiveConfigsChangedReceiver != mActiveConfigsChangedReceivers.end()) {
- mActiveConfigsChangedReceivers.erase(itActiveConfigsChangedReceiver);
- }
- }
-
for (const sp<ConfigListener>& listener : mListeners) {
broadcastList.push_back(listener);
}
}
- auto itReceiver = mConfigReceivers.find(key);
- if (itReceiver != mConfigReceivers.end()) {
- // Remove from map
- mConfigReceivers.erase(itReceiver);
- }
-
// Remove from disk. There can still be a lingering file on disk so we check
// whether or not the config was on memory.
remove_saved_configs(key);
@@ -238,12 +224,6 @@ void ConfigManager::RemoveConfigs(int uid) {
// Remove from map
remove_saved_configs(*it);
removed.push_back(*it);
- mConfigReceivers.erase(*it);
- }
-
- auto itActiveConfigsChangedReceiver = mActiveConfigsChangedReceivers.find(uid);
- if (itActiveConfigsChangedReceiver != mActiveConfigsChangedReceivers.end()) {
- mActiveConfigsChangedReceivers.erase(itActiveConfigsChangedReceiver);
}
mConfigs.erase(uidIt);
@@ -277,8 +257,6 @@ void ConfigManager::RemoveAllConfigs() {
uidIt = mConfigs.erase(uidIt);
}
- mConfigReceivers.clear();
- mActiveConfigsChangedReceivers.clear();
for (const sp<ConfigListener>& listener : mListeners) {
broadcastList.push_back(listener);
}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 50896f84da43..1d31873209b2 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -41,7 +41,6 @@
#include "StatsCallbackPullerDeprecated.h"
#include "StatsCompanionServicePuller.h"
#include "SubsystemSleepStatePuller.h"
-#include "SurfaceflingerStatsPuller.h"
#include "TrainInfoPuller.h"
#include "statslog.h"
@@ -273,10 +272,6 @@ std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// App ops
{{.atomTag = android::util::APP_OPS},
{.puller = new StatsCompanionServicePuller(android::util::APP_OPS)}},
- // SurfaceflingerStatsGlobalInfo
- {{.atomTag = android::util::SURFACEFLINGER_STATS_GLOBAL_INFO},
- {.puller =
- new SurfaceflingerStatsPuller(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO)}},
// VmsClientStats
{{.atomTag = android::util::VMS_CLIENT_STATS},
{.additiveFields = {5, 6, 7, 8, 9, 10},
diff --git a/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp b/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp
deleted file mode 100644
index 23b2236f35f2..000000000000
--- a/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#include "SurfaceflingerStatsPuller.h"
-
-#include <cutils/compiler.h>
-
-#include <numeric>
-
-#include "logd/LogEvent.h"
-#include "stats_log_util.h"
-#include "statslog.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-SurfaceflingerStatsPuller::SurfaceflingerStatsPuller(const int tagId) : StatsPuller(tagId) {
-}
-
-bool SurfaceflingerStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) {
- switch (mTagId) {
- case android::util::SURFACEFLINGER_STATS_GLOBAL_INFO:
- return pullGlobalInfo(data);
- default:
- break;
- }
-
- return false;
-}
-
-static int64_t getTotalTime(
- const google::protobuf::RepeatedPtrField<surfaceflinger::SFTimeStatsHistogramBucketProto>&
- buckets) {
- int64_t total = 0;
- for (const auto& bucket : buckets) {
- if (bucket.time_millis() == 1000) {
- continue;
- }
-
- total += bucket.time_millis() * bucket.frame_count();
- }
-
- return total;
-}
-
-bool SurfaceflingerStatsPuller::pullGlobalInfo(std::vector<std::shared_ptr<LogEvent>>* data) {
- std::string protoBytes;
- if (CC_UNLIKELY(mStatsProvider)) {
- protoBytes = mStatsProvider();
- } else {
- std::unique_ptr<FILE, decltype(&pclose)> pipe(popen("dumpsys SurfaceFlinger --timestats -dump --proto", "r"), pclose);
- if (!pipe.get()) {
- return false;
- }
- char buf[1024];
- size_t bytesRead = 0;
- do {
- bytesRead = fread(buf, 1, sizeof(buf), pipe.get());
- protoBytes.append(buf, bytesRead);
- } while (bytesRead > 0);
- }
- surfaceflinger::SFTimeStatsGlobalProto proto;
- proto.ParseFromString(protoBytes);
-
- int64_t totalTime = getTotalTime(proto.present_to_present());
-
- data->clear();
- data->reserve(1);
- std::shared_ptr<LogEvent> event =
- make_shared<LogEvent>(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, getWallClockNs(),
- getElapsedRealtimeNs());
- if (!event->write(proto.total_frames())) return false;
- if (!event->write(proto.missed_frames())) return false;
- if (!event->write(proto.client_composition_frames())) return false;
- if (!event->write(proto.display_on_time())) return false;
- if (!event->write(totalTime)) return false;
- event->init();
- data->emplace_back(event);
-
- return true;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/SurfaceflingerStatsPuller.h b/cmds/statsd/src/external/SurfaceflingerStatsPuller.h
deleted file mode 100644
index ed7153edf797..000000000000
--- a/cmds/statsd/src/external/SurfaceflingerStatsPuller.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#pragma once
-
-#include <timestatsproto/TimeStatsProtoHeader.h>
-
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Pull metrics from Surfaceflinger
- */
-class SurfaceflingerStatsPuller : public StatsPuller {
-public:
- explicit SurfaceflingerStatsPuller(const int tagId);
-
- // StatsPuller interface
- bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) override;
-
-protected:
- // Test-only, for injecting fake data
- using StatsProvider = std::function<std::string()>;
- StatsProvider mStatsProvider;
-
-private:
- bool pullGlobalInfo(std::vector<std::shared_ptr<LogEvent>>* data);
-};
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 35c6d373418e..e85b97514242 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -207,10 +207,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio
&linkedConditionDimensionKey);
if (trueConditionDimensions.find(linkedConditionDimensionKey) !=
trueConditionDimensions.end()) {
- for (auto& condIt : whatIt.second) {
- condIt.second->onConditionChanged(
- currentUnSlicedPartCondition, eventTime);
- }
+ whatIt.second->onConditionChanged(currentUnSlicedPartCondition, eventTime);
}
}
} else {
@@ -222,15 +219,11 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio
&linkedConditionDimensionKey);
if (dimensionsChangedToTrue->find(linkedConditionDimensionKey) !=
dimensionsChangedToTrue->end()) {
- for (auto& condIt : whatIt.second) {
- condIt.second->onConditionChanged(true, eventTime);
- }
+ whatIt.second->onConditionChanged(true, eventTime);
}
if (dimensionsChangedToFalse->find(linkedConditionDimensionKey) !=
dimensionsChangedToFalse->end()) {
- for (auto& condIt : whatIt.second) {
- condIt.second->onConditionChanged(false, eventTime);
- }
+ whatIt.second->onConditionChanged(false, eventTime);
}
}
}
@@ -247,9 +240,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeInternalLocked(bool overa
// Now for each of the on-going event, check if the condition has changed for them.
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
- }
+ whatIt.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
}
}
@@ -283,18 +274,14 @@ void DurationMetricProducer::onActiveStateChangedLocked(const int64_t& eventTime
}
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onConditionChanged(mIsActive, eventTimeNs);
- }
+ whatIt.second->onConditionChanged(mIsActive, eventTimeNs);
}
} else if (mIsActive) {
flushIfNeededLocked(eventTimeNs);
onSlicedConditionMayChangeInternalLocked(mIsActive, eventTimeNs);
} else { // mConditionSliced == true && !mIsActive
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onConditionChanged(mIsActive, eventTimeNs);
- }
+ whatIt.second->onConditionChanged(mIsActive, eventTimeNs);
}
}
}
@@ -310,9 +297,7 @@ void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
flushIfNeededLocked(eventTime);
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onConditionChanged(conditionMet, eventTime);
- }
+ whatIt.second->onConditionChanged(conditionMet, eventTime);
}
}
@@ -425,19 +410,11 @@ void DurationMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs
const int64_t& nextBucketStartTimeNs) {
for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
whatIt != mCurrentSlicedDurationTrackerMap.end();) {
- for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
- if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
- VLOG("erase bucket for key %s %s", whatIt->first.toString().c_str(),
- it->first.toString().c_str());
- it = whatIt->second.erase(it);
- } else {
- ++it;
- }
- }
- if (whatIt->second.empty()) {
+ if (whatIt->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
+ VLOG("erase bucket for key %s", whatIt->first.toString().c_str());
whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
} else {
- whatIt++;
+ ++whatIt;
}
}
StatsdStats::getInstance().noteBucketCount(mMetricId);
@@ -453,35 +430,15 @@ void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
(unsigned long)mCurrentSlicedDurationTrackerMap.size());
if (verbose) {
for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (const auto& slice : whatIt.second) {
- fprintf(out, "\t(what)%s\t(states)%s\n", whatIt.first.toString().c_str(),
- slice.first.toString().c_str());
- slice.second->dumpStates(out, verbose);
- }
+ fprintf(out, "\t(what)%s\n", whatIt.first.toString().c_str());
+ whatIt.second->dumpStates(out, verbose);
}
}
}
bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat());
- if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- auto stateIt = whatIt->second.find(newKey.getStateValuesKey());
- if (stateIt != whatIt->second.end()) {
- return false;
- }
- if (whatIt->second.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
- size_t newTupleCount = whatIt->second.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionInConditionSize(
- mConfigKey, mMetricId, newTupleCount);
- // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
- if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("DurationMetric %lld dropping data for state values key %s",
- (long long)mMetricId, newKey.getStateValuesKey().toString().c_str());
- StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
- return true;
- }
- }
- } else {
+ if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
// 1. Report the tuple count if the tuple count > soft limit
if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
@@ -503,24 +460,16 @@ void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey
const ConditionKey& conditionKeys,
bool condition, const LogEvent& event) {
const auto& whatKey = eventKey.getDimensionKeyInWhat();
- const auto& stateKey = eventKey.getStateValuesKey();
auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
if (hitGuardRailLocked(eventKey)) {
return;
}
- mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
- } else {
- if (whatIt->second.find(stateKey) == whatIt->second.end()) {
- if (hitGuardRailLocked(eventKey)) {
- return;
- }
- mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
- }
+ mCurrentSlicedDurationTrackerMap[whatKey] = createDurationTracker(eventKey);
}
- auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(stateKey);
+ auto it = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (mUseWhatDimensionAsInternalDimension) {
it->second->noteStart(whatKey, condition,
event.GetElapsedTimestampNs(), conditionKeys);
@@ -560,18 +509,14 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
// Handles Stopall events.
if (matcherIndex == mStopAllIndex) {
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->noteStopAll(event.GetElapsedTimestampNs());
- }
+ whatIt.second->noteStopAll(event.GetElapsedTimestampNs());
}
return;
}
- HashableDimensionKey dimensionInWhat;
+ HashableDimensionKey dimensionInWhat = DEFAULT_DIMENSION_KEY;
if (!mDimensionsInWhat.empty()) {
filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
- } else {
- dimensionInWhat = DEFAULT_DIMENSION_KEY;
}
// Handles Stop events.
@@ -579,9 +524,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
if (mUseWhatDimensionAsInternalDimension) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& stateIt : whatIt->second) {
- stateIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
- }
+ whatIt->second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
}
return;
}
@@ -593,10 +536,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& stateIt : whatIt->second) {
- stateIt.second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(),
- false);
- }
+ whatIt->second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(), false);
}
return;
}
@@ -619,8 +559,8 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
condition = condition && mIsActive;
- handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY),
- conditionKey, condition, event);
+ handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY), conditionKey,
+ condition, event);
}
size_t DurationMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 45908fb48f75..06da0f64aedb 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -132,8 +132,7 @@ private:
std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>> mPastBuckets;
// The duration trackers in the current bucket.
- std::unordered_map<HashableDimensionKey,
- std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>>
+ std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>
mCurrentSlicedDurationTrackerMap;
// Helper function to create a duration tracker given the metric aggregation type.
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 6b5c2994a0c8..afe93d445e1d 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -82,8 +82,6 @@ public:
virtual ~DurationTracker(){};
- virtual unique_ptr<DurationTracker> clone(const int64_t eventTime) = 0;
-
virtual void noteStart(const HashableDimensionKey& key, bool condition,
const int64_t eventTime, const ConditionKey& conditionKey) = 0;
virtual void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index df66cb0c53e5..2be5855e90e6 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -37,24 +37,6 @@ MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id,
conditionSliced, fullLink, anomalyTrackers) {
}
-unique_ptr<DurationTracker> MaxDurationTracker::clone(const int64_t eventTime) {
- auto clonedTracker = make_unique<MaxDurationTracker>(*this);
- for (auto it = clonedTracker->mInfos.begin(); it != clonedTracker->mInfos.end();) {
- if (it->second.state != kStopped) {
- it->second.lastStartTime = eventTime;
- it->second.lastDuration = 0;
- it++;
- } else {
- it = clonedTracker->mInfos.erase(it);
- }
- }
- if (clonedTracker->mInfos.empty()) {
- return nullptr;
- } else {
- return clonedTracker;
- }
-}
-
bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
// ===========GuardRail==============
if (mInfos.find(newKey) != mInfos.end()) {
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index d0371da096ea..efb8dc70afd1 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -38,8 +38,6 @@ public:
MaxDurationTracker(const MaxDurationTracker& tracker) = default;
- unique_ptr<DurationTracker> clone(const int64_t eventTime) override;
-
void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index b0fd975b2328..57f39656fdfe 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -38,13 +38,6 @@ OringDurationTracker::OringDurationTracker(
mLastStartTime = 0;
}
-unique_ptr<DurationTracker> OringDurationTracker::clone(const int64_t eventTime) {
- auto clonedTracker = make_unique<OringDurationTracker>(*this);
- clonedTracker->mLastStartTime = eventTime;
- clonedTracker->mDuration = 0;
- return clonedTracker;
-}
-
bool OringDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
// ===========GuardRail==============
// 1. Report the tuple count if the tuple count > soft limit
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 43c48d5f536b..c3aad668aa78 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -37,8 +37,6 @@ public:
OringDurationTracker(const OringDurationTracker& tracker) = default;
- unique_ptr<DurationTracker> clone(const int64_t eventTime) override;
-
void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index a9a105f0fda7..a37cad14fcbc 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -69,12 +69,6 @@ void SubscriberReporter::unsetBroadcastSubscriber(const ConfigKey& configKey,
}
}
-void SubscriberReporter::removeConfig(const ConfigKey& configKey) {
- VLOG("SubscriberReporter::removeConfig called.");
- lock_guard<std::mutex> lock(mLock);
- mIntentMap.erase(configKey);
-}
-
void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
const Subscription& subscription,
const MetricDimensionKey& dimKey) const {
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
index 8ccc8ee626d4..087a1b84b91f 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.h
@@ -59,9 +59,6 @@ public:
*/
void unsetBroadcastSubscriber(const ConfigKey& configKey, int64_t subscriberId);
- /** Remove all information stored by SubscriberReporter about the given config. */
- void removeConfig(const ConfigKey& configKey);
-
/**
* Sends a broadcast via the intentSender previously stored for the
* given (configKey, subscriberId) pair by setBroadcastSubscriber.
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 0bc3ebb81ce6..16b51d99535b 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -28,16 +28,16 @@ namespace statsd {
#ifdef __ANDROID__
-const string kAndroid = "android";
const string kApp1 = "app1.sharing.1";
const int kConfigKey = 789130123; // Randomly chosen to avoid collisions with existing configs.
+const int kCallingUid = 0; // Randomly chosen
void SendConfig(StatsService& service, const StatsdConfig& config) {
string str;
config.SerializeToString(&str);
std::vector<uint8_t> configAsVec(str.begin(), str.end());
bool success;
- service.addConfiguration(kConfigKey, configAsVec, String16(kAndroid.c_str()));
+ service.addConfiguration(kConfigKey, configAsVec, kCallingUid);
}
ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestamp,
@@ -50,7 +50,7 @@ ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestam
ConfigMetricsReportList reports;
reports.ParseFromArray(output.data(), output.size());
EXPECT_EQ(1, reports.reports_size());
- return reports.reports(0);
+ return reports.reports(kCallingUid);
}
StatsdConfig MakeConfig() {
diff --git a/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp b/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp
deleted file mode 100644
index 5b7a30d4a5aa..000000000000
--- a/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "SurfaceflingerStatsPuller_test"
-
-#include "src/external/SurfaceflingerStatsPuller.h"
-#include "statslog.h"
-
-#include <gtest/gtest.h>
-#include <log/log.h>
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class TestableSurfaceflingerStatsPuller : public SurfaceflingerStatsPuller {
-public:
- TestableSurfaceflingerStatsPuller(const int tagId) : SurfaceflingerStatsPuller(tagId){};
-
- void injectStats(const StatsProvider& statsProvider) {
- mStatsProvider = statsProvider;
- }
-};
-
-class SurfaceflingerStatsPullerTest : public ::testing::Test {
-public:
- SurfaceflingerStatsPullerTest() {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
- ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- }
-
- ~SurfaceflingerStatsPullerTest() {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
- ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
- }
-};
-
-TEST_F(SurfaceflingerStatsPullerTest, pullGlobalStats) {
- surfaceflinger::SFTimeStatsGlobalProto proto;
- proto.set_total_frames(1);
- proto.set_missed_frames(2);
- proto.set_client_composition_frames(2);
- proto.set_display_on_time(4);
-
- auto bucketOne = proto.add_present_to_present();
- bucketOne->set_time_millis(2);
- bucketOne->set_frame_count(4);
- auto bucketTwo = proto.add_present_to_present();
- bucketTwo->set_time_millis(4);
- bucketTwo->set_frame_count(1);
- auto bucketThree = proto.add_present_to_present();
- bucketThree->set_time_millis(1000);
- bucketThree->set_frame_count(1);
- static constexpr int64_t expectedAnimationMillis = 12;
- TestableSurfaceflingerStatsPuller puller(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
-
- puller.injectStats([&] {
- return proto.SerializeAsString();
- });
- puller.ForceClearCache();
- vector<std::shared_ptr<LogEvent>> outData;
- puller.Pull(&outData);
-
- ASSERT_EQ(1, outData.size());
- EXPECT_EQ(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, outData[0]->GetTagId());
- EXPECT_EQ(proto.total_frames(), outData[0]->getValues()[0].mValue.long_value);
- EXPECT_EQ(proto.missed_frames(), outData[0]->getValues()[1].mValue.long_value);
- EXPECT_EQ(proto.client_composition_frames(), outData[0]->getValues()[2].mValue.long_value);
- EXPECT_EQ(proto.display_on_time(), outData[0]->getValues()[3].mValue.long_value);
- EXPECT_EQ(expectedAnimationMillis, outData[0]->getValues()[4].mValue.long_value);
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a4f6f57c097e..b82a67556fc0 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3349,8 +3349,8 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void handleStartActivity(ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void handleStartActivity(IBinder token, PendingTransactionActions pendingActions) {
+ final ActivityClientRecord r = mActivities.get(token);
final Activity activity = r.activity;
if (r.activity == null) {
// TODO(lifecycler): What do we do in this case?
@@ -3364,6 +3364,8 @@ public final class ActivityThread extends ClientTransactionHandler {
return;
}
+ unscheduleGcIdler();
+
// Start
activity.performStart("handleStartActivity");
r.setState(ON_START);
@@ -3400,6 +3402,9 @@ public final class ActivityThread extends ClientTransactionHandler {
+ " did not call through to super.onPostCreate()");
}
}
+
+ updateVisibility(r, true /* show */);
+ mSomeActivitiesChanged = true;
}
/**
@@ -4660,8 +4665,8 @@ public final class ActivityThread extends ClientTransactionHandler {
@UnsupportedAppUsage
final void performStopActivity(IBinder token, boolean saveState, String reason) {
ActivityClientRecord r = mActivities.get(token);
- performStopActivityInner(r, null /* stopInfo */, false /* keepShown */, saveState,
- false /* finalStateRequest */, reason);
+ performStopActivityInner(r, null /* stopInfo */, saveState, false /* finalStateRequest */,
+ reason);
}
private static final class ProviderRefCount {
@@ -4687,25 +4692,19 @@ public final class ActivityThread extends ClientTransactionHandler {
}
/**
- * Core implementation of stopping an activity. Note this is a little
- * tricky because the server's meaning of stop is slightly different
- * than our client -- for the server, stop means to save state and give
- * it the result when it is done, but the window may still be visible.
- * For the client, we want to call onStop()/onStart() to indicate when
- * the activity's UI visibility changes.
+ * Core implementation of stopping an activity.
* @param r Target activity client record.
* @param info Action that will report activity stop to server.
- * @param keepShown Flag indicating whether the activity is still shown.
* @param saveState Flag indicating whether the activity state should be saved.
* @param finalStateRequest Flag indicating if this call is handling final lifecycle state
* request for a transaction.
* @param reason Reason for performing this operation.
*/
- private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown,
+ private void performStopActivityInner(ActivityClientRecord r, StopInfo info,
boolean saveState, boolean finalStateRequest, String reason) {
if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
if (r != null) {
- if (!keepShown && r.stopped) {
+ if (r.stopped) {
if (r.activity.mFinished) {
// If we are finishing, we won't call onResume() in certain
// cases. So here we likewise don't want to call onStop()
@@ -4740,9 +4739,7 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
- if (!keepShown) {
- callActivityOnStop(r, saveState, reason);
- }
+ callActivityOnStop(r, saveState, reason);
}
}
@@ -4810,20 +4807,19 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void handleStopActivity(IBinder token, boolean show, int configChanges,
+ public void handleStopActivity(IBinder token, int configChanges,
PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {
final ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;
final StopInfo stopInfo = new StopInfo();
- performStopActivityInner(r, stopInfo, show, true /* saveState */, finalStateRequest,
+ performStopActivityInner(r, stopInfo, true /* saveState */, finalStateRequest,
reason);
if (localLOGV) Slog.v(
- TAG, "Finishing stop of " + r + ": show=" + show
- + " win=" + r.window);
+ TAG, "Finishing stop of " + r + ": win=" + r.window);
- updateVisibility(r, show);
+ updateVisibility(r, false);
// Make sure any pending writes are now committed.
if (!r.isPreHoneycomb()) {
@@ -4859,34 +4855,6 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
- @Override
- public void handleWindowVisibility(IBinder token, boolean show) {
- ActivityClientRecord r = mActivities.get(token);
-
- if (r == null) {
- Log.w(TAG, "handleWindowVisibility: no activity for token " + token);
- return;
- }
-
- if (!show && !r.stopped) {
- performStopActivityInner(r, null /* stopInfo */, show, false /* saveState */,
- false /* finalStateRequest */, "handleWindowVisibility");
- } else if (show && r.getLifecycleState() == ON_STOP) {
- // If we are getting ready to gc after going to the background, well
- // we are back active so skip it.
- unscheduleGcIdler();
-
- r.activity.performRestart(true /* start */, "handleWindowVisibility");
- r.setState(ON_START);
- }
- if (r.activity.mDecor != null) {
- if (false) Slog.v(
- TAG, "Handle window " + r + " visibility: " + show);
- updateVisibility(r, show);
- }
- mSomeActivitiesChanged = true;
- }
-
// TODO: This method should be changed to use {@link #performStopActivityInner} to perform to
// stop operation on the activity to reduce code duplication and the chance of fixing a bug in
// one place and missing the other.
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index f9a689a7e1de..d2235f10da99 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -119,7 +119,6 @@ public abstract class ClientTransactionHandler {
/**
* Stop the activity.
* @param token Target activity token.
- * @param show Flag indicating whether activity is still shown.
* @param configChanges Activity configuration changes.
* @param pendingActions Pending actions to be used on this or later stages of activity
* transaction.
@@ -127,7 +126,7 @@ public abstract class ClientTransactionHandler {
* request for a transaction.
* @param reason Reason for performing this operation.
*/
- public abstract void handleStopActivity(IBinder token, boolean show, int configChanges,
+ public abstract void handleStopActivity(IBinder token, int configChanges,
PendingTransactionActions pendingActions, boolean finalStateRequest, String reason);
/** Report that activity was stopped to server. */
@@ -161,15 +160,12 @@ public abstract class ClientTransactionHandler {
/** Request that an activity enter picture-in-picture. */
public abstract void handlePictureInPictureRequested(IBinder token);
- /** Update window visibility. */
- public abstract void handleWindowVisibility(IBinder token, boolean show);
-
/** Perform activity launch. */
public abstract Activity handleLaunchActivity(ActivityThread.ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent);
/** Perform activity start. */
- public abstract void handleStartActivity(ActivityThread.ActivityClientRecord r,
+ public abstract void handleStartActivity(IBinder token,
PendingTransactionActions pendingActions);
/** Get package info. */
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 49c389a0c4a7..1278ff6817fd 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -16,7 +16,9 @@
package android.app;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -40,11 +42,13 @@ import android.os.Environment;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.provider.BaseColumns;
import android.provider.Downloads;
import android.provider.MediaStore;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
+import android.util.LongSparseArray;
import android.util.Pair;
import java.io.File;
@@ -1069,6 +1073,37 @@ public class DownloadManager {
}
/**
+ * Notify {@link DownloadManager} that the given {@link MediaStore} items
+ * were just deleted so that {@link DownloadManager} internal data
+ * structures can be cleaned up.
+ *
+ * @param idToMime map from {@link BaseColumns#_ID} to
+ * {@link ContentResolver#getType(Uri)}.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE)
+ public void onMediaStoreDownloadsDeleted(@NonNull LongSparseArray<String> idToMime) {
+ try (ContentProviderClient client = mResolver
+ .acquireUnstableContentProviderClient(mBaseUri)) {
+ final Bundle callExtras = new Bundle();
+ final long[] ids = new long[idToMime.size()];
+ final String[] mimeTypes = new String[idToMime.size()];
+ for (int i = idToMime.size() - 1; i >= 0; --i) {
+ ids[i] = idToMime.keyAt(i);
+ mimeTypes[i] = idToMime.valueAt(i);
+ }
+ callExtras.putLongArray(android.provider.Downloads.EXTRA_IDS, ids);
+ callExtras.putStringArray(android.provider.Downloads.EXTRA_MIME_TYPES,
+ mimeTypes);
+ client.call(android.provider.Downloads.CALL_MEDIASTORE_DOWNLOADS_DELETED,
+ null, callExtras);
+ } catch (RemoteException e) {
+ // Should not happen
+ }
+ }
+
+ /**
* Enqueue a new download. The download will start automatically once the download manager is
* ready to execute it and connectivity is available.
*
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 4033aea32b55..7cdf85e0a6b8 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -177,7 +177,7 @@ public class LocalActivityManager {
pendingActions = null;
}
- mActivityThread.handleStartActivity(clientRecord, pendingActions);
+ mActivityThread.handleStartActivity(r, pendingActions);
r.curState = STARTED;
if (desiredState == RESUMED) {
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 83d1de60cac7..84263749232d 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -157,11 +157,11 @@ public final class StatsManager {
public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
// can throw IllegalArgumentException
service.addConfiguration(configKey, config, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when adding configuration");
+ Slog.e(TAG, "Failed to connect to statsmanager when adding configuration");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -194,10 +194,10 @@ public final class StatsManager {
public void removeConfig(long configKey) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
service.removeConfiguration(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when removing configuration");
+ Slog.e(TAG, "Failed to connect to statsmanager when removing configuration");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -390,10 +390,10 @@ public final class StatsManager {
public byte[] getReports(long configKey) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
return service.getData(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when getting data");
+ Slog.e(TAG, "Failed to connect to statsmanager when getting data");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -427,10 +427,10 @@ public final class StatsManager {
public byte[] getStatsMetadata() throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
return service.getMetadata(mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when getting metadata");
+ Slog.e(TAG, "Failed to connect to statsmanager when getting metadata");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -462,21 +462,19 @@ public final class StatsManager {
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
if (service == null) {
- if (DEBUG) {
- Slog.d(TAG, "Failed to find statsd when getting experiment IDs");
- }
- return new long[0];
+ throw new StatsUnavailableException("Failed to find statsmanager when "
+ + "getting experiment IDs");
}
return service.getRegisteredExperimentIds();
} catch (RemoteException e) {
if (DEBUG) {
Slog.d(TAG,
- "Failed to connect to StatsCompanionService when getting "
+ "Failed to connect to StatsManagerService when getting "
+ "registered experiment IDs");
}
- return new long[0];
+ throw new StatsUnavailableException("could not connect", e);
}
}
}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index a1765c85d57b..078e4538c66b 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -153,6 +153,11 @@ public class StatusBarManager {
*/
public static final int DEFAULT_SETUP_DISABLE2_FLAGS = DISABLE2_ROTATE_SUGGESTIONS;
+ /**
+ * disable flags to be applied when the device is sim-locked.
+ */
+ private static final int DEFAULT_SIM_LOCKED_DISABLED_FLAGS = DISABLE_EXPAND;
+
/** @hide */
public static final int NAVIGATION_HINT_BACK_ALT = 1 << 0;
/** @hide */
@@ -385,6 +390,30 @@ public class StatusBarManager {
}
/**
+ * Enable or disable expansion of the status bar. When the device is SIM-locked, the status
+ * bar should not be expandable.
+ *
+ * @param disabled If {@code true}, the status bar will be set to non-expandable. If
+ * {@code false}, re-enables expansion of the status bar.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.STATUS_BAR)
+ public void setDisabledForSimNetworkLock(boolean disabled) {
+ try {
+ final int userId = Binder.getCallingUserHandle().getIdentifier();
+ final IStatusBarService svc = getService();
+ if (svc != null) {
+ svc.disableForUser(disabled ? DEFAULT_SIM_LOCKED_DISABLED_FLAGS : DISABLE_NONE,
+ mToken, mContext.getPackageName(), userId);
+ }
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get this app's currently requested disabled components
*
* @return a new DisableInfo
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f3028a10bb10..2aac94c6f5da 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -88,7 +88,6 @@ import android.telephony.data.ApnSetting;
import android.util.ArraySet;
import android.util.Log;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.Preconditions;
@@ -6757,6 +6756,34 @@ public class DevicePolicyManager {
}
/**
+ * @hide
+ * Privileged apps can use this method to find out if the device was provisioned as
+ * organization-owend device with a managed profile.
+ *
+ * This, together with checking whether the device has a device owner (by calling
+ * {@link #isDeviceManaged()}), could be used to learn whether the device is owned by an
+ * organization or an individual:
+ * If this method returns true OR {@link #isDeviceManaged()} returns true, then
+ * the device is owned by an organization. Otherwise, it's owned by an individual.
+ *
+ * @return {@code true} if the device was provisioned as organization-owned device,
+ * {@code false} otherwise.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public boolean isOrganizationOwnedDeviceWithManagedProfile() {
+ throwIfParentInstance("isOrganizationOwnedDeviceWithManagedProfile");
+ if (mService != null) {
+ try {
+ return mService.isOrganizationOwnedDeviceWithManagedProfile();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Returns whether the specified package can read the device identifiers.
*
* @param packageName The package name of the app to check for device identifier access.
@@ -11215,12 +11242,12 @@ public class DevicePolicyManager {
* #setCrossProfilePackages(ComponentName, Set)}.</li>
* <li>The default package names set by the OEM that are allowed to request user consent for
* cross-profile communication without being explicitly enabled by the admin, via
- * {@link R.array#cross_profile_apps}</li>
+ * {@link com.android.internal.R.array#cross_profile_apps}</li>
* </ul>
*
* @return the combined set of whitelisted package names set via
* {@link #setCrossProfilePackages(ComponentName, Set)} and
- * {@link R.array#cross_profile_apps}
+ * {@link com.android.internal.R.array#cross_profile_apps}
*
* @hide
*/
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index f299d456a18f..e6c89d9071e6 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -17,9 +17,12 @@
package android.app.admin;
import android.annotation.UserIdInt;
+import android.content.ComponentName;
import android.content.Intent;
+import android.os.UserHandle;
import java.util.List;
+import java.util.Set;
/**
* Device policy manager local system service interface.
@@ -165,4 +168,23 @@ public abstract class DevicePolicyManagerInternal {
* Do not call it directly. Use {@link DevicePolicyCache#getInstance()} instead.
*/
protected abstract DeviceStateCache getDeviceStateCache();
+
+ /**
+ * Returns the combined set of the following:
+ * <ul>
+ * <li>The package names that the admin has previously set as allowed to request user consent
+ * for cross-profile communication, via {@link
+ * DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)}.</li>
+ * <li>The default package names that are allowed to request user consent for cross-profile
+ * communication without being explicitly enabled by the admin , via {@link
+ * DevicePolicyManager#setDefaultCrossProfilePackages(ComponentName, UserHandle, Set)}.</li>
+ * </ul>
+ *
+ * @return the combined set of whitelisted package names set via
+ * {@link DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)} and
+ * {@link DevicePolicyManager#setDefaultCrossProfilePackages(ComponentName, UserHandle, Set)}
+ *
+ * @hide
+ */
+ public abstract List<String> getAllCrossProfilePackages();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 55dfe2fec4c9..3eec46bd010e 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -156,6 +156,7 @@ interface IDevicePolicyManager {
void setProfileName(in ComponentName who, String profileName);
void clearProfileOwner(in ComponentName who);
boolean hasUserSetupCompleted();
+ boolean isOrganizationOwnedDeviceWithManagedProfile();
boolean checkDeviceIdentifierAccess(in String packageName, int pid, int uid);
diff --git a/core/java/android/app/servertransaction/WindowVisibilityItem.java b/core/java/android/app/servertransaction/StartActivityItem.java
index 115d1ececc0e..4fbe02b9cf76 100644
--- a/core/java/android/app/servertransaction/WindowVisibilityItem.java
+++ b/core/java/android/app/servertransaction/StartActivityItem.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 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.
@@ -24,41 +24,44 @@ import android.os.Parcel;
import android.os.Trace;
/**
- * Window visibility change message.
+ * Request to move an activity to started and visible state.
* @hide
*/
-public class WindowVisibilityItem extends ClientTransactionItem {
+public class StartActivityItem extends ActivityLifecycleItem {
- private boolean mShowWindow;
+ private static final String TAG = "StartActivityItem";
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
- Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
- mShowWindow ? "activityShowWindow" : "activityHideWindow");
- client.handleWindowVisibility(token, mShowWindow);
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "startActivityItem");
+ client.handleStartActivity(token, pendingActions);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
+ @Override
+ public int getTargetState() {
+ return ON_START;
+ }
+
// ObjectPoolItem implementation
- private WindowVisibilityItem() {}
+ private StartActivityItem() {}
/** Obtain an instance initialized with provided params. */
- public static WindowVisibilityItem obtain(boolean showWindow) {
- WindowVisibilityItem instance = ObjectPool.obtain(WindowVisibilityItem.class);
+ public static StartActivityItem obtain() {
+ StartActivityItem instance = ObjectPool.obtain(StartActivityItem.class);
if (instance == null) {
- instance = new WindowVisibilityItem();
+ instance = new StartActivityItem();
}
- instance.mShowWindow = showWindow;
return instance;
}
@Override
public void recycle() {
- mShowWindow = false;
+ super.recycle();
ObjectPool.recycle(this);
}
@@ -68,24 +71,24 @@ public class WindowVisibilityItem extends ClientTransactionItem {
/** Write to Parcel. */
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeBoolean(mShowWindow);
+ // Empty
}
/** Read from Parcel. */
- private WindowVisibilityItem(Parcel in) {
- mShowWindow = in.readBoolean();
+ private StartActivityItem(Parcel in) {
+ // Empty
}
- public static final @android.annotation.NonNull Creator<WindowVisibilityItem> CREATOR =
- new Creator<WindowVisibilityItem>() {
- public WindowVisibilityItem createFromParcel(Parcel in) {
- return new WindowVisibilityItem(in);
- }
+ public static final @android.annotation.NonNull Creator<StartActivityItem> CREATOR =
+ new Creator<StartActivityItem>() {
+ public StartActivityItem createFromParcel(Parcel in) {
+ return new StartActivityItem(in);
+ }
- public WindowVisibilityItem[] newArray(int size) {
- return new WindowVisibilityItem[size];
- }
- };
+ public StartActivityItem[] newArray(int size) {
+ return new StartActivityItem[size];
+ }
+ };
@Override
public boolean equals(Object o) {
@@ -95,17 +98,17 @@ public class WindowVisibilityItem extends ClientTransactionItem {
if (o == null || getClass() != o.getClass()) {
return false;
}
- final WindowVisibilityItem other = (WindowVisibilityItem) o;
- return mShowWindow == other.mShowWindow;
+ return true;
}
@Override
public int hashCode() {
- return 17 + 31 * (mShowWindow ? 1 : 0);
+ return 17;
}
@Override
public String toString() {
- return "WindowVisibilityItem{showWindow=" + mShowWindow + "}";
+ return "StartActivityItem{}";
}
}
+
diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java
index 63efa6fe7c17..8668bd49c8f5 100644
--- a/core/java/android/app/servertransaction/StopActivityItem.java
+++ b/core/java/android/app/servertransaction/StopActivityItem.java
@@ -31,14 +31,13 @@ public class StopActivityItem extends ActivityLifecycleItem {
private static final String TAG = "StopActivityItem";
- private boolean mShowWindow;
private int mConfigChanges;
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
- client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions,
+ client.handleStopActivity(token, mConfigChanges, pendingActions,
true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -59,13 +58,15 @@ public class StopActivityItem extends ActivityLifecycleItem {
private StopActivityItem() {}
- /** Obtain an instance initialized with provided params. */
- public static StopActivityItem obtain(boolean showWindow, int configChanges) {
+ /**
+ * Obtain an instance initialized with provided params.
+ * @param configChanges Configuration pieces that changed.
+ */
+ public static StopActivityItem obtain(int configChanges) {
StopActivityItem instance = ObjectPool.obtain(StopActivityItem.class);
if (instance == null) {
instance = new StopActivityItem();
}
- instance.mShowWindow = showWindow;
instance.mConfigChanges = configChanges;
return instance;
@@ -74,7 +75,6 @@ public class StopActivityItem extends ActivityLifecycleItem {
@Override
public void recycle() {
super.recycle();
- mShowWindow = false;
mConfigChanges = 0;
ObjectPool.recycle(this);
}
@@ -85,13 +85,11 @@ public class StopActivityItem extends ActivityLifecycleItem {
/** Write to Parcel. */
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeBoolean(mShowWindow);
dest.writeInt(mConfigChanges);
}
/** Read from Parcel. */
private StopActivityItem(Parcel in) {
- mShowWindow = in.readBoolean();
mConfigChanges = in.readInt();
}
@@ -115,20 +113,18 @@ public class StopActivityItem extends ActivityLifecycleItem {
return false;
}
final StopActivityItem other = (StopActivityItem) o;
- return mShowWindow == other.mShowWindow && mConfigChanges == other.mConfigChanges;
+ return mConfigChanges == other.mConfigChanges;
}
@Override
public int hashCode() {
int result = 17;
- result = 31 * result + (mShowWindow ? 1 : 0);
result = 31 * result + mConfigChanges;
return result;
}
@Override
public String toString() {
- return "StopActivityItem{showWindow=" + mShowWindow + ",configChanges=" + mConfigChanges
- + "}";
+ return "StopActivityItem{configChanges=" + mConfigChanges + "}";
}
}
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 20e0da3ead8a..17fcda587322 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -218,7 +218,7 @@ public class TransactionExecutor {
null /* customIntent */);
break;
case ON_START:
- mTransactionHandler.handleStartActivity(r, mPendingActions);
+ mTransactionHandler.handleStartActivity(r.token, mPendingActions);
break;
case ON_RESUME:
mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */,
@@ -230,8 +230,8 @@ public class TransactionExecutor {
"LIFECYCLER_PAUSE_ACTIVITY");
break;
case ON_STOP:
- mTransactionHandler.handleStopActivity(r.token, false /* show */,
- 0 /* configChanges */, mPendingActions, false /* finalStateRequest */,
+ mTransactionHandler.handleStopActivity(r.token, 0 /* configChanges */,
+ mPendingActions, false /* finalStateRequest */,
"LIFECYCLER_STOP_ACTIVITY");
break;
case ON_DESTROY:
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
index 0ea8c3c159fa..6df92a78cc9f 100644
--- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -183,8 +183,7 @@ public class TransactionExecutorHelper {
lifecycleItem = PauseActivityItem.obtain();
break;
case ON_STOP:
- lifecycleItem = StopActivityItem.obtain(r.isVisibleFromServer(),
- 0 /* configChanges */);
+ lifecycleItem = StopActivityItem.obtain(0 /* configChanges */);
break;
default:
lifecycleItem = ResumeActivityItem.obtain(false /* isForward */);
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
index 55f92be14cd0..50de73855511 100644
--- a/core/java/android/app/timedetector/ManualTimeSuggestion.java
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
index 4c55ba12d881..17e9c5a79fa5 100644
--- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java
+++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
index 4a89a1245473..479e4b4efb4c 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index af9ece00f491..54dd1bed5361 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -24,8 +24,8 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemClock;
+import android.os.TimestampedValue;
import android.util.Log;
-import android.util.TimestampedValue;
/**
* The interface through which system components can send signals to the TimeDetectorService.
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b1b6f0d61f9f..cb1f05573d93 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2670,6 +2670,9 @@ public final class BluetoothAdapter {
} else if (profile == BluetoothProfile.PAN) {
BluetoothPan pan = new BluetoothPan(context, listener);
return true;
+ } else if (profile == BluetoothProfile.PBAP) {
+ BluetoothPbap pbap = new BluetoothPbap(context, listener);
+ return true;
} else if (profile == BluetoothProfile.HEALTH) {
Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated");
return false;
@@ -2742,6 +2745,10 @@ public final class BluetoothAdapter {
BluetoothPan pan = (BluetoothPan) proxy;
pan.close();
break;
+ case BluetoothProfile.PBAP:
+ BluetoothPbap pbap = (BluetoothPbap) proxy;
+ pbap.close();
+ break;
case BluetoothProfile.GATT:
BluetoothGatt gatt = (BluetoothGatt) proxy;
gatt.close();
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 393d48891d64..85826fd4e669 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -27,6 +27,7 @@ import static android.os.Trace.TRACE_TAG_DATABASE;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.app.AppOpsManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.PackageManager;
@@ -942,7 +943,18 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
return null;
}
- /** {@hide} */
+ /**
+ * Return the package name of the caller that initiated the request being
+ * processed on the current thread. The returned package will have
+ * <em>not</em> been verified to belong to the calling UID. Returns
+ * {@code null} if not currently processing a request.
+ * <p>
+ * This will always return {@code null} when processing
+ * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
+ *
+ * @see Binder#getCallingUid()
+ * @see Context#grantUriPermission(String, Uri, int)
+ */
public final @Nullable String getCallingPackageUnchecked() {
final Pair<String, String> pkg = mCallingPackage.get();
if (pkg != null) {
@@ -952,7 +964,14 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
return null;
}
- /** {@hide} */
+ /**
+ * Called whenever the value of {@link #getCallingPackage()} changes, giving
+ * the provider an opportunity to invalidate any security related caching it
+ * may be performing.
+ * <p>
+ * This typically happens when a {@link ContentProvider} makes a nested call
+ * back into itself when already processing a call from a remote process.
+ */
public void onCallingPackageChanged() {
}
@@ -1390,8 +1409,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
* @param uri The URI to query. This will be the full URI sent by the client.
* @param projection The list of columns to put into the cursor.
* If {@code null} provide a default set of columns.
- * @param queryArgs A Bundle containing all additional information necessary for the query.
- * Values in the Bundle may include SQL style arguments.
+ * @param queryArgs A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @param cancellationSignal A signal to cancel the operation in progress,
* or {@code null}.
* @return a Cursor or {@code null}.
@@ -1525,8 +1547,24 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
return false;
}
- /** {@hide} */
+ /**
+ * Perform a detailed internal check on a {@link Uri} to determine if a UID
+ * is able to access it with specific mode flags.
+ * <p>
+ * This method is typically used when the provider implements more dynamic
+ * access controls that cannot be expressed with {@code <path-permission>}
+ * style static rules.
+ *
+ * @param uri the {@link Uri} to perform an access check on.
+ * @param uid the UID to check the permission for.
+ * @param modeFlags the access flags to use for the access check, such as
+ * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}.
+ * @return {@link PackageManager#PERMISSION_GRANTED} if access is allowed,
+ * otherwise {@link PackageManager#PERMISSION_DENIED}.
+ * @hide
+ */
@Override
+ @SystemApi
public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) {
return PackageManager.PERMISSION_DENIED;
}
@@ -1574,9 +1612,14 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
*
* @param uri The content:// URI of the insertion request.
* @param values A set of column_name/value pairs to add to the database.
- * @param extras A Bundle containing all additional information necessary
- * for the insert.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @return The URI for the newly inserted item.
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
*/
@Override
public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues values,
@@ -1653,10 +1696,13 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
*
* @param uri The full URI to query, including a row ID (if a specific
* record is requested).
- * @param extras A Bundle containing all additional information necessary
- * for the delete. Values in the Bundle may include SQL style
- * arguments.
- * @return The number of rows affected.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
* @throws SQLException
*/
@Override
@@ -1699,10 +1745,14 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
* @param uri The URI to query. This can potentially have a record ID if
* this is an update request for a specific record.
* @param values A set of column_name/value pairs to update in the database.
- * @param extras A Bundle containing all additional information necessary
- * for the update. Values in the Bundle may include SQL style
- * arguments.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @return the number of rows affected.
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
*/
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values,
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 93f42879d946..494d2aeaf42a 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -18,7 +18,7 @@ package android.content;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java
index 11dda83a6e6c..4fb1ddb958d5 100644
--- a/core/java/android/content/ContentProviderResult.java
+++ b/core/java/android/content/ContentProviderResult.java
@@ -36,7 +36,7 @@ public class ContentProviderResult implements Parcelable {
public final @Nullable Uri uri;
public final @Nullable Integer count;
public final @Nullable Bundle extras;
- public final @Nullable Exception exception;
+ public final @Nullable Throwable exception;
public ContentProviderResult(@NonNull Uri uri) {
this(Objects.requireNonNull(uri), null, null, null);
@@ -50,12 +50,12 @@ public class ContentProviderResult implements Parcelable {
this(null, null, Objects.requireNonNull(extras), null);
}
- public ContentProviderResult(@NonNull Exception exception) {
+ public ContentProviderResult(@NonNull Throwable exception) {
this(null, null, null, exception);
}
/** {@hide} */
- public ContentProviderResult(Uri uri, Integer count, Bundle extras, Exception exception) {
+ public ContentProviderResult(Uri uri, Integer count, Bundle extras, Throwable exception) {
this.uri = uri;
this.count = count;
this.extras = extras;
@@ -79,7 +79,7 @@ public class ContentProviderResult implements Parcelable {
extras = null;
}
if (source.readInt() != 0) {
- exception = (Exception) ParcelableException.readFromParcel(source);
+ exception = ParcelableException.readFromParcel(source);
} else {
exception = null;
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 1d3c6505f677..6cd1cd3354c2 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -984,7 +984,11 @@ public abstract class ContentResolver implements ContentInterface {
* retrieve.
* @param projection A list of which columns to return. Passing null will
* return all columns, which is inefficient.
- * @param queryArgs A Bundle containing any arguments to the query.
+ * @param queryArgs A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
@@ -1925,9 +1929,15 @@ public abstract class ContentResolver implements ContentInterface {
* @param url The URL of the table to insert into.
* @param values The initial values for the newly inserted row. The key is the column name for
* the field. Passing an empty ContentValues will create an empty row.
- * @param extras A Bundle containing all additional information necessary for the insert.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @return the URL of the newly created row. May return <code>null</code> if the underlying
* content provider returns <code>null</code>, or if it crashes.
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
*/
@Override
public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
@@ -2061,9 +2071,14 @@ public abstract class ContentResolver implements ContentInterface {
* If the content provider supports transactions, the deletion will be atomic.
*
* @param url The URL of the row to delete.
- * @param extras A Bundle containing all additional information necessary for the delete.
- * Values in the Bundle may include SQL style arguments.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @return The number of rows deleted.
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
*/
@Override
public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable Bundle extras) {
@@ -2121,10 +2136,15 @@ public abstract class ContentResolver implements ContentInterface {
* @param uri The URI to modify.
* @param values The new field values. The key is the column name for the field.
A null value will remove an existing field value.
- * @param extras A Bundle containing all additional information necessary for the update.
- * Values in the Bundle may include SQL style arguments.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @return the number of rows updated.
* @throws NullPointerException if uri or values are null
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
*/
@Override
public final int update(@RequiresPermission.Write @NonNull Uri uri,
@@ -3851,15 +3871,47 @@ public abstract class ContentResolver implements ContentInterface {
}
}
+ /**
+ * Decode a path generated by {@link #encodeToFile(Uri)} back into
+ * the original {@link Uri}.
+ * <p>
+ * This is used to offer a way to intercept filesystem calls in
+ * {@link ContentProvider} unaware code and redirect them to a
+ * {@link ContentProvider} when they attempt to use {@code _DATA} columns
+ * that are otherwise deprecated.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static @NonNull Uri decodeFromFile(@NonNull File file) {
+ return translateDeprecatedDataPath(file.getAbsolutePath());
+ }
+
+ /**
+ * Encode a {@link Uri} into an opaque filesystem path which can then be
+ * resurrected by {@link #decodeFromFile(File)}.
+ * <p>
+ * This is used to offer a way to intercept filesystem calls in
+ * {@link ContentProvider} unaware code and redirect them to a
+ * {@link ContentProvider} when they attempt to use {@code _DATA} columns
+ * that are otherwise deprecated.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static @NonNull File encodeToFile(@NonNull Uri uri) {
+ return new File(translateDeprecatedDataPath(uri));
+ }
+
/** {@hide} */
- public static Uri translateDeprecatedDataPath(String path) {
+ public static @NonNull Uri translateDeprecatedDataPath(@NonNull String path) {
final String ssp = "//" + path.substring(DEPRECATE_DATA_PREFIX.length());
return Uri.parse(new Uri.Builder().scheme(SCHEME_CONTENT)
.encodedOpaquePart(ssp).build().toString());
}
/** {@hide} */
- public static String translateDeprecatedDataPath(Uri uri) {
+ public static @NonNull String translateDeprecatedDataPath(@NonNull Uri uri) {
return DEPRECATE_DATA_PREFIX + uri.getEncodedSchemeSpecificPart().substring(2);
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a28868ef38f8..5cb2907dfba4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3391,6 +3391,7 @@ public abstract class Context {
TELEPHONY_SUBSCRIPTION_SERVICE,
CARRIER_CONFIG_SERVICE,
EUICC_SERVICE,
+ MMS_SERVICE,
TELECOM_SERVICE,
CLIPBOARD_SERVICE,
INPUT_METHOD_SERVICE,
@@ -3587,6 +3588,8 @@ public abstract class Context {
* @see android.telephony.CarrierConfigManager
* @see #EUICC_SERVICE
* @see android.telephony.euicc.EuiccManager
+ * @see #MMS_SERVICE
+ * @see android.telephony.MmsManager
* @see #INPUT_METHOD_SERVICE
* @see android.view.inputmethod.InputMethodManager
* @see #UI_MODE_SERVICE
@@ -4016,6 +4019,7 @@ public abstract class Context {
* @see android.net.wifi.WifiCondManager
* @hide
*/
+ @SystemApi
public static final String WIFI_COND_SERVICE = "wificond";
/**
@@ -4262,6 +4266,15 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.telephony.MmsManager} to send/receive MMS messages.
+ *
+ * @see #getSystemService(String)
+ * @see android.telephony.MmsManager
+ */
+ public static final String MMS_SERVICE = "mms";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.content.ClipboardManager} for accessing and modifying
* the contents of the global clipboard.
*
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index e897b917fcc2..abf32c5e0840 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -30,6 +30,7 @@ import com.android.internal.R;
import com.android.internal.util.UserIcons;
import java.util.List;
+import java.util.Set;
/**
* Class for handling cross profile operations. Apps can use this class to interact with its
@@ -169,6 +170,62 @@ public class CrossProfileApps {
}
}
+ /**
+ * Returns whether the calling package can request to interact across profiles.
+ *
+ * <p>The package's current ability to interact across profiles can be checked with
+ * {@link #canInteractAcrossProfiles()}.
+ *
+ * <p>Specifically, returns whether the following are all true:
+ * <ul>
+ * <li>{@link #getTargetUserProfiles()} returns a non-empty list for the calling user.</li>
+ * <li>The calling app has requested</li>
+ * {@code android.Manifest.permission.INTERACT_ACROSS_PROFILES} in its manifest.
+ * <li>The calling package has either been whitelisted by default by the OEM or has been
+ * explicitly whitelisted by the admin via
+ * {@link android.app.admin.DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)}.
+ * </li>
+ * </ul>
+ *
+ * @return true if the calling package can request to interact across profiles.
+ */
+ public boolean canRequestInteractAcrossProfiles() {
+ try {
+ return mService.canRequestInteractAcrossProfiles(mContext.getPackageName());
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether the calling package can interact across profiles.
+ *
+ * <p>The package's current ability to request to interact across profiles can be checked with
+ * {@link #canRequestInteractAcrossProfiles()}.
+ *
+ * <p>Specifically, returns whether the following are all true:
+ * <ul>
+ * <li>{@link #getTargetUserProfiles()} returns a non-empty list for the calling user.</li>
+ * <li>The user has previously consented to cross-profile communication for the calling
+ * package.</li>
+ * <li>The calling package has either been whitelisted by default by the OEM or has been
+ * explicitly whitelisted by the admin via
+ * {@link android.app.admin.DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)}.
+ * </li>
+ * </ul>
+ *
+ * @return true if the calling package can interact across profiles.
+ * @throws SecurityException if {@code mContext.getPackageName()} does not belong to the
+ * calling UID.
+ */
+ public boolean canInteractAcrossProfiles() {
+ try {
+ return mService.canInteractAcrossProfiles(mContext.getPackageName());
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
private void verifyCanAccessUser(UserHandle userHandle) {
if (!getTargetUserProfiles().contains(userHandle)) {
throw new SecurityException("Not allowed to access " + userHandle);
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index d2d66cbda610..c5db0ccebf52 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -30,4 +30,6 @@ interface ICrossProfileApps {
void startActivityAsUser(in IApplicationThread caller, in String callingPackage,
in ComponentName component, int userId, boolean launchMainActivity);
List<UserHandle> getTargetUserProfiles(in String callingPackage);
+ boolean canInteractAcrossProfiles(in String callingPackage);
+ boolean canRequestInteractAcrossProfiles(in String callingPackage);
} \ No newline at end of file
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b85c58ad0e2f..4bfc40e698b9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2323,6 +2323,13 @@ public abstract class PackageManager {
public static final String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * has a telephony radio that support data.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_TELEPHONY_DATA = "android.hardware.telephony.data";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports telephony carrier restriction mechanism.
*
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index ac2e373f000d..6639b3d5c0b5 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -18,7 +18,7 @@ package android.content.pm.parsing;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
index 595685729a0c..f04a30ce4239 100644
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -27,8 +27,8 @@ import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
import android.app.ActivityTaskManager;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index bba14c39de72..36ec67ee1471 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -35,8 +35,8 @@ import com.android.internal.util.ArrayUtils;
import libcore.util.EmptyArray;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
@@ -56,7 +56,7 @@ public class SQLiteQueryBuilder {
"(?i)(AVG|COUNT|MAX|MIN|SUM|TOTAL|GROUP_CONCAT)\\((.+)\\)");
private Map<String, String> mProjectionMap = null;
- private List<Pattern> mProjectionGreylist = null;
+ private Collection<Pattern> mProjectionGreylist = null;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mTables = "";
@@ -196,20 +196,16 @@ public class SQLiteQueryBuilder {
* Sets a projection greylist of columns that will be allowed through, even
* when {@link #setStrict(boolean)} is enabled. This provides a way for
* abusive custom columns like {@code COUNT(*)} to continue working.
- *
- * @hide
*/
- public void setProjectionGreylist(@Nullable List<Pattern> projectionGreylist) {
+ public void setProjectionGreylist(@Nullable Collection<Pattern> projectionGreylist) {
mProjectionGreylist = projectionGreylist;
}
/**
* Gets the projection greylist for the query, as last configured by
- * {@link #setProjectionGreylist(List)}.
- *
- * @hide
+ * {@link #setProjectionGreylist}.
*/
- public @Nullable List<Pattern> getProjectionGreylist() {
+ public @Nullable Collection<Pattern> getProjectionGreylist() {
return mProjectionGreylist;
}
@@ -244,25 +240,27 @@ public class SQLiteQueryBuilder {
}
/**
- * When set, the selection is verified against malicious arguments.
- * When using this class to create a statement using
+ * When set, the selection is verified against malicious arguments. When
+ * using this class to create a statement using
* {@link #buildQueryString(boolean, String, String[], String, String, String, String, String)},
- * non-numeric limits will raise an exception. If a projection map is specified, fields
- * not in that map will be ignored.
- * If this class is used to execute the statement directly using
+ * non-numeric limits will raise an exception. If a projection map is
+ * specified, fields not in that map will be ignored. If this class is used
+ * to execute the statement directly using
* {@link #query(SQLiteDatabase, String[], String, String[], String, String, String)}
* or
* {@link #query(SQLiteDatabase, String[], String, String[], String, String, String, String)},
- * additionally also parenthesis escaping selection are caught.
- *
- * To summarize: To get maximum protection against malicious third party apps (for example
- * content provider consumers), make sure to do the following:
+ * additionally also parenthesis escaping selection are caught. To
+ * summarize: To get maximum protection against malicious third party apps
+ * (for example content provider consumers), make sure to do the following:
* <ul>
* <li>Set this value to true</li>
* <li>Use a projection map</li>
- * <li>Use one of the query overloads instead of getting the statement as a sql string</li>
+ * <li>Use one of the query overloads instead of getting the statement as a
+ * sql string</li>
* </ul>
- * By default, this value is false.
+ * <p>
+ * This feature is disabled by default on each newly constructed
+ * {@link SQLiteQueryBuilder} and needs to be manually enabled.
*/
public void setStrict(boolean strict) {
if (strict) {
@@ -287,6 +285,9 @@ public class SQLiteQueryBuilder {
* This enforcement applies to {@link #insert}, {@link #query}, and
* {@link #update} operations. Any enforcement failures will throw an
* {@link IllegalArgumentException}.
+ * <p>
+ * This feature is disabled by default on each newly constructed
+ * {@link SQLiteQueryBuilder} and needs to be manually enabled.
*/
public void setStrictColumns(boolean strictColumns) {
if (strictColumns) {
@@ -323,6 +324,9 @@ public class SQLiteQueryBuilder {
* {@link #delete} operations. This enforcement does not apply to trusted
* inputs, such as those provided by {@link #appendWhere}. Any enforcement
* failures will throw an {@link IllegalArgumentException}.
+ * <p>
+ * This feature is disabled by default on each newly constructed
+ * {@link SQLiteQueryBuilder} and needs to be manually enabled.
*/
public void setStrictGrammar(boolean strictGrammar) {
if (strictGrammar) {
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 638d81b2f635..6e1987c47d20 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -90,4 +90,11 @@ interface IInputManager {
/** Create an input monitor for gestures. */
InputMonitor monitorGestureInput(String name, int displayId);
+
+ // Add a runtime association between the input port and the display port. This overrides any
+ // static associations.
+ void addPortAssociation(in String inputPort, int displayPort);
+ // Remove the runtime association between the input port and the display port. Any existing
+ // static association for the cleared input port will be restored.
+ void removePortAssociation(in String inputPort);
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 8d32db013fb3..83f01a5dca35 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -17,6 +17,7 @@
package android.hardware.input;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
@@ -963,6 +964,41 @@ public final class InputManager {
}
}
+ /**
+ * Add a runtime association between the input port and the display port. This overrides any
+ * static associations.
+ * @param inputPort The port of the input device.
+ * @param displayPort The physical port of the associated display.
+ * <p>
+ * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT}.
+ * </p>
+ * @hide
+ */
+ public void addPortAssociation(@NonNull String inputPort, int displayPort) {
+ try {
+ mIm.addPortAssociation(inputPort, displayPort);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Remove the runtime association between the input port and the display port. Any existing
+ * static association for the cleared input port will be restored.
+ * @param inputPort The port of the input device to be cleared.
+ * <p>
+ * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT}.
+ * </p>
+ * @hide
+ */
+ public void removePortAssociation(@NonNull String inputPort) {
+ try {
+ mIm.removePortAssociation(inputPort);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
private void populateInputDevicesLocked() {
if (mInputDevicesChangedListener == null) {
final InputDevicesChangedListener listener = new InputDevicesChangedListener();
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 250e8c3428a6..d87200931830 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -601,19 +601,19 @@ public class SoundTrigger {
}
}
- /*****************************************************************************
+ /**
* A ModelParamRange is a representation of supported parameter range for a
* given loaded model.
- ****************************************************************************/
+ */
public static final class ModelParamRange implements Parcelable {
/**
- * start of supported range inclusive
+ * The inclusive start of supported range.
*/
public final int start;
/**
- * end of supported range inclusive
+ * The inclusive end of supported range.
*/
public final int end;
@@ -622,31 +622,65 @@ public class SoundTrigger {
this.end = end;
}
+ /** @hide */
private ModelParamRange(@NonNull Parcel in) {
this.start = in.readInt();
this.end = in.readInt();
}
@NonNull
- public static final Creator<ModelParamRange> CREATOR = new Creator<ModelParamRange>() {
- @Override
- @NonNull
- public ModelParamRange createFromParcel(@NonNull Parcel in) {
- return new ModelParamRange(in);
- }
-
- @Override
- @NonNull
- public ModelParamRange[] newArray(int size) {
- return new ModelParamRange[size];
- }
- };
+ public static final Creator<ModelParamRange> CREATOR =
+ new Creator<ModelParamRange>() {
+ @Override
+ @NonNull
+ public ModelParamRange createFromParcel(@NonNull Parcel in) {
+ return new ModelParamRange(in);
+ }
+
+ @Override
+ @NonNull
+ public ModelParamRange[] newArray(int size) {
+ return new ModelParamRange[size];
+ }
+ };
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
+ /** @hide */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (start);
+ result = prime * result + (end);
+ return result;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ ModelParamRange other = (ModelParamRange) obj;
+ if (start != other.start) {
+ return false;
+ }
+ if (end != other.end) {
+ return false;
+ }
+ return true;
+ }
+
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(start);
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 73b9d1739061..67fdda37ed3b 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -91,7 +91,7 @@ public class UsbManager {
*
* {@hide}
*/
- @UnsupportedAppUsage
+ @SystemApi
public static final String ACTION_USB_STATE =
"android.hardware.usb.action.USB_STATE";
@@ -164,7 +164,7 @@ public class UsbManager {
*
* {@hide}
*/
- @UnsupportedAppUsage
+ @SystemApi
public static final String USB_CONNECTED = "connected";
/**
@@ -181,6 +181,7 @@ public class UsbManager {
*
* {@hide}
*/
+ @SystemApi
public static final String USB_CONFIGURED = "configured";
/**
@@ -217,6 +218,7 @@ public class UsbManager {
*
* {@hide}
*/
+ @SystemApi
public static final String USB_FUNCTION_RNDIS = "rndis";
/**
@@ -319,6 +321,7 @@ public class UsbManager {
* Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
* {@hide}
*/
+ @SystemApi
public static final long FUNCTION_NONE = 0;
/**
@@ -337,6 +340,7 @@ public class UsbManager {
* Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
* {@hide}
*/
+ @SystemApi
public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;
/**
@@ -698,6 +702,8 @@ public class UsbManager {
*
* {@hide}
*/
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
public void setCurrentFunctions(long functions) {
try {
mService.setCurrentFunctions(functions);
@@ -737,6 +743,8 @@ public class UsbManager {
*
* {@hide}
*/
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
public long getCurrentFunctions() {
try {
return mService.getCurrentFunctions();
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
new file mode 100644
index 000000000000..6afdb5ef1b16
--- /dev/null
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -0,0 +1,242 @@
+/*
+ * 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.IntDef;
+import android.annotation.NonNull;
+import android.os.PersistableBundle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
+/**
+ * Class that provides utilities for collecting network connectivity diagnostics information.
+ * Connectivity information is made available through triggerable diagnostics tools and by listening
+ * to System validations. Some diagnostics information may be permissions-restricted.
+ *
+ * <p>ConnectivityDiagnosticsManager is intended for use by applications offering network
+ * connectivity on a user device. These tools will provide several mechanisms for these applications
+ * to be alerted to network conditions as well as diagnose potential network issues themselves.
+ *
+ * <p>The primary responsibilities of this class are to:
+ *
+ * <ul>
+ * <li>Allow permissioned applications to register and unregister callbacks for network event
+ * notifications
+ * <li>Invoke callbacks for network event notifications, including:
+ * <ul>
+ * <li>Network validations
+ * <li>Data stalls
+ * <li>Connectivity reports from applications
+ * </ul>
+ * </ul>
+ */
+public class ConnectivityDiagnosticsManager {
+ public static final int DETECTION_METHOD_DNS_EVENTS = 1;
+ public static final int DETECTION_METHOD_TCP_METRICS = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = {"DETECTION_METHOD_"},
+ value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
+ public @interface DetectionMethod {}
+
+ /** @hide */
+ public ConnectivityDiagnosticsManager() {}
+
+ /** Class that includes connectivity information for a specific Network at a specific time. */
+ public static class ConnectivityReport {
+ /** The Network for which this ConnectivityReport applied */
+ @NonNull public final Network network;
+
+ /**
+ * The timestamp for the report. The timestamp is taken from {@link
+ * System#currentTimeMillis}.
+ */
+ public final long reportTimestamp;
+
+ /** LinkProperties available on the Network at the reported timestamp */
+ @NonNull public final LinkProperties linkProperties;
+
+ /** NetworkCapabilities available on the Network at the reported timestamp */
+ @NonNull public final NetworkCapabilities networkCapabilities;
+
+ /** PersistableBundle that may contain additional info about the report */
+ @NonNull public final PersistableBundle additionalInfo;
+
+ /**
+ * Constructor for ConnectivityReport.
+ *
+ * <p>Apps should obtain instances through {@link
+ * ConnectivityDiagnosticsCallback#onConnectivityReport} instead of instantiating their own
+ * instances (unless for testing purposes).
+ *
+ * @param network The Network for which this ConnectivityReport applies
+ * @param reportTimestamp The timestamp for the report
+ * @param linkProperties The LinkProperties available on network at reportTimestamp
+ * @param networkCapabilities The NetworkCapabilities available on network at
+ * reportTimestamp
+ * @param additionalInfo A PersistableBundle that may contain additional info about the
+ * report
+ */
+ public ConnectivityReport(
+ @NonNull Network network,
+ long reportTimestamp,
+ @NonNull LinkProperties linkProperties,
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull PersistableBundle additionalInfo) {
+ this.network = network;
+ this.reportTimestamp = reportTimestamp;
+ this.linkProperties = linkProperties;
+ this.networkCapabilities = networkCapabilities;
+ this.additionalInfo = additionalInfo;
+ }
+ }
+
+ /** Class that includes information for a suspected data stall on a specific Network */
+ public static class DataStallReport {
+ /** The Network for which this DataStallReport applied */
+ @NonNull public final Network network;
+
+ /**
+ * The timestamp for the report. The timestamp is taken from {@link
+ * System#currentTimeMillis}.
+ */
+ public final long reportTimestamp;
+
+ /** The detection method used to identify the suspected data stall */
+ @DetectionMethod public final int detectionMethod;
+
+ /** PersistableBundle that may contain additional information on the suspected data stall */
+ @NonNull public final PersistableBundle stallDetails;
+
+ /**
+ * Constructor for DataStallReport.
+ *
+ * <p>Apps should obtain instances through {@link
+ * ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own
+ * instances (unless for testing purposes).
+ *
+ * @param network The Network for which this DataStallReport applies
+ * @param reportTimestamp The timestamp for the report
+ * @param detectionMethod The detection method used to identify this data stall
+ * @param stallDetails A PersistableBundle that may contain additional info about the report
+ */
+ public DataStallReport(
+ @NonNull Network network,
+ long reportTimestamp,
+ @DetectionMethod int detectionMethod,
+ @NonNull PersistableBundle stallDetails) {
+ this.network = network;
+ this.reportTimestamp = reportTimestamp;
+ this.detectionMethod = detectionMethod;
+ this.stallDetails = stallDetails;
+ }
+ }
+
+ /**
+ * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about
+ * network connectivity events. Must be extended by applications wanting notifications.
+ */
+ public abstract static class ConnectivityDiagnosticsCallback {
+ /**
+ * Called when the platform completes a data connectivity check. This will also be invoked
+ * upon registration with the latest report.
+ *
+ * <p>The Network specified in the ConnectivityReport may not be active any more when this
+ * method is invoked.
+ *
+ * @param report The ConnectivityReport containing information about a connectivity check
+ */
+ public void onConnectivityReport(@NonNull ConnectivityReport report) {}
+
+ /**
+ * Called when the platform suspects a data stall on some Network.
+ *
+ * <p>The Network specified in the DataStallReport may not be active any more when this
+ * method is invoked.
+ *
+ * @param report The DataStallReport containing information about the suspected data stall
+ */
+ public void onDataStallSuspected(@NonNull DataStallReport report) {}
+
+ /**
+ * Called when any app reports connectivity to the System.
+ *
+ * @param network The Network for which connectivity has been reported
+ * @param hasConnectivity The connectivity reported to the System
+ */
+ public void onNetworkConnectivityReported(
+ @NonNull Network network, boolean hasConnectivity) {}
+ }
+
+ /**
+ * Registers a ConnectivityDiagnosticsCallback with the System.
+ *
+ * <p>Only apps that offer network connectivity to the user are allowed to register callbacks.
+ * This includes:
+ *
+ * <ul>
+ * <li>Carrier apps with active subscriptions
+ * <li>Active VPNs
+ * <li>WiFi Suggesters
+ * </ul>
+ *
+ * <p>Callbacks will be limited to receiving notifications for networks over which apps provide
+ * connectivity.
+ *
+ * <p>If a registering app loses its relevant permissions, any callbacks it registered will
+ * silently stop receiving callbacks.
+ *
+ * <p>Each register() call <b>MUST</b> use a unique ConnectivityDiagnosticsCallback instance. If
+ * a single instance is registered with multiple NetworkRequests, an IllegalArgumentException
+ * will be thrown.
+ *
+ * @param request The NetworkRequest that will be used to match with Networks for which
+ * callbacks will be fired
+ * @param e The Executor to be used for running the callback method invocations
+ * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the
+ * System
+ * @throws IllegalArgumentException if the same callback instance is registered with multiple
+ * NetworkRequests
+ * @throws SecurityException if the caller does not have appropriate permissions to register a
+ * callback
+ */
+ public void registerConnectivityDiagnosticsCallback(
+ @NonNull NetworkRequest request,
+ @NonNull Executor e,
+ @NonNull ConnectivityDiagnosticsCallback callback) {
+ // TODO(b/143187964): implement ConnectivityDiagnostics functionality
+ throw new UnsupportedOperationException("registerCallback() not supported yet");
+ }
+
+ /**
+ * Unregisters a ConnectivityDiagnosticsCallback with the System.
+ *
+ * <p>If the given callback is not currently registered with the System, this operation will be
+ * a no-op.
+ *
+ * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System.
+ */
+ public void unregisterConnectivityDiagnosticsCallback(
+ @NonNull ConnectivityDiagnosticsCallback callback) {
+ // TODO(b/143187964): implement ConnectivityDiagnostics functionality
+ throw new UnsupportedOperationException("registerCallback() not supported yet");
+ }
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 6da16a82c822..03d4200bd90f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -363,7 +363,7 @@ public class ConnectivityManager {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@UnsupportedAppUsage
public static final String ACTION_TETHER_STATE_CHANGED =
- "android.net.conn.TETHER_STATE_CHANGED";
+ TetheringManager.ACTION_TETHER_STATE_CHANGED;
/**
* @hide
@@ -371,14 +371,14 @@ public class ConnectivityManager {
* tethering and currently available for tethering.
*/
@UnsupportedAppUsage
- public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+ public static final String EXTRA_AVAILABLE_TETHER = TetheringManager.EXTRA_AVAILABLE_TETHER;
/**
* @hide
* gives a String[] listing all the interfaces currently in local-only
* mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
*/
- public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray";
+ public static final String EXTRA_ACTIVE_LOCAL_ONLY = TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
/**
* @hide
@@ -386,7 +386,7 @@ public class ConnectivityManager {
* (ie, has DHCPv4 support and packets potentially forwarded/NATed)
*/
@UnsupportedAppUsage
- public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+ public static final String EXTRA_ACTIVE_TETHER = TetheringManager.EXTRA_ACTIVE_TETHER;
/**
* @hide
@@ -395,7 +395,7 @@ public class ConnectivityManager {
* for any interfaces listed here.
*/
@UnsupportedAppUsage
- public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+ public static final String EXTRA_ERRORED_TETHER = TetheringManager.EXTRA_ERRORED_TETHER;
/**
* Broadcast Action: The captive portal tracker has finished its test.
@@ -445,7 +445,7 @@ public class ConnectivityManager {
* @see #startTethering(int, boolean, OnStartTetheringCallback)
* @hide
*/
- public static final int TETHERING_INVALID = -1;
+ public static final int TETHERING_INVALID = TetheringManager.TETHERING_INVALID;
/**
* Wifi tethering type.
@@ -453,7 +453,7 @@ public class ConnectivityManager {
* @hide
*/
@SystemApi
- public static final int TETHERING_WIFI = 0;
+ public static final int TETHERING_WIFI = TetheringManager.TETHERING_WIFI;
/**
* USB tethering type.
@@ -461,7 +461,7 @@ public class ConnectivityManager {
* @hide
*/
@SystemApi
- public static final int TETHERING_USB = 1;
+ public static final int TETHERING_USB = TetheringManager.TETHERING_USB;
/**
* Bluetooth tethering type.
@@ -469,7 +469,7 @@ public class ConnectivityManager {
* @hide
*/
@SystemApi
- public static final int TETHERING_BLUETOOTH = 2;
+ public static final int TETHERING_BLUETOOTH = TetheringManager.TETHERING_BLUETOOTH;
/**
* Wifi P2p tethering type.
@@ -477,41 +477,41 @@ public class ConnectivityManager {
* need to start from #startTethering(int, boolean, OnStartTetheringCallback).
* @hide
*/
- public static final int TETHERING_WIFI_P2P = 3;
+ public static final int TETHERING_WIFI_P2P = TetheringManager.TETHERING_WIFI_P2P;
/**
* Extra used for communicating with the TetherService. Includes the type of tethering to
* enable if any.
* @hide
*/
- public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+ public static final String EXTRA_ADD_TETHER_TYPE = TetheringManager.EXTRA_ADD_TETHER_TYPE;
/**
* Extra used for communicating with the TetherService. Includes the type of tethering for
* which to cancel provisioning.
* @hide
*/
- public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
+ public static final String EXTRA_REM_TETHER_TYPE = TetheringManager.EXTRA_REM_TETHER_TYPE;
/**
* Extra used for communicating with the TetherService. True to schedule a recheck of tether
* provisioning.
* @hide
*/
- public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+ public static final String EXTRA_SET_ALARM = TetheringManager.EXTRA_SET_ALARM;
/**
* Tells the TetherService to run a provision check now.
* @hide
*/
- public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
+ public static final String EXTRA_RUN_PROVISION = TetheringManager.EXTRA_RUN_PROVISION;
/**
* Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
* which will receive provisioning results. Can be left empty.
* @hide
*/
- public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+ public static final String EXTRA_PROVISION_CALLBACK = TetheringManager.EXTRA_PROVISION_CALLBACK;
/**
* The absence of a connection type.
@@ -3107,6 +3107,63 @@ public class ConnectivityManager {
}
}
+ /**
+ * Registers the specified {@link NetworkProvider}.
+ * Each listener must only be registered once. The listener can be unregistered with
+ * {@link #unregisterNetworkProvider}.
+ *
+ * @param provider the provider to register
+ * @return the ID of the provider. This ID must be used by the provider when registering
+ * {@link android.net.NetworkAgent}s.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public int registerNetworkProvider(@NonNull NetworkProvider provider) {
+ if (provider.getProviderId() != NetworkProvider.ID_NONE) {
+ // TODO: Provide a better method for checking this by moving NetworkFactory.SerialNumber
+ // out of NetworkFactory.
+ throw new IllegalStateException("NetworkProviders can only be registered once");
+ }
+
+ try {
+ int providerId = mService.registerNetworkProvider(provider.getMessenger(),
+ provider.getName());
+ provider.setProviderId(providerId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return provider.getProviderId();
+ }
+
+ /**
+ * Unregisters the specified NetworkProvider.
+ *
+ * @param provider the provider to unregister
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public void unregisterNetworkProvider(@NonNull NetworkProvider provider) {
+ try {
+ mService.unregisterNetworkProvider(provider.getMessenger());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ provider.setProviderId(NetworkProvider.ID_NONE);
+ }
+
+
+ /** @hide exposed via the NetworkProvider class. */
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
+ try {
+ mService.declareNetworkRequestUnfulfillable(request);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
// TODO : remove this method. It is a stopgap measure to help sheperding a number
// of dependent changes that would conflict throughout the automerger graph. Having this
// temporarily helps with the process of going through with all these dependent changes across
diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java
index 98bab44e19fb..912df67a0b45 100644
--- a/core/java/android/net/DhcpInfo.java
+++ b/core/java/android/net/DhcpInfo.java
@@ -16,8 +16,8 @@
package android.net;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
/**
* A simple object for retrieving the results of a DHCP request.
@@ -67,12 +67,12 @@ public class DhcpInfo implements Parcelable {
buf.append(NetworkUtils.intToInetAddress(addr).getHostAddress());
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public int describeContents() {
return 0;
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(ipAddress);
dest.writeInt(gateway);
@@ -83,7 +83,7 @@ public class DhcpInfo implements Parcelable {
dest.writeInt(leaseDuration);
}
- /** Implement the Parcelable interface {@hide} */
+ /** Implement the Parcelable interface */
public static final @android.annotation.NonNull Creator<DhcpInfo> CREATOR =
new Creator<DhcpInfo>() {
public DhcpInfo createFromParcel(Parcel in) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 09c02efbcfc4..e6a0379ff629 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -142,12 +142,16 @@ interface IConnectivityManager
void setAirplaneMode(boolean enable);
- int registerNetworkFactory(in Messenger messenger, in String name);
-
boolean requestBandwidthUpdate(in Network network);
+ int registerNetworkFactory(in Messenger messenger, in String name);
void unregisterNetworkFactory(in Messenger messenger);
+ int registerNetworkProvider(in Messenger messenger, in String name);
+ void unregisterNetworkProvider(in Messenger messenger);
+
+ void declareNetworkRequestUnfulfillable(in NetworkRequest request);
+
int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
in NetworkCapabilities nc, int score, in NetworkMisc misc, in int factorySerialNumber);
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 45d0c7313fca..09ec6c35fcb9 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -17,7 +17,6 @@ package android.net;
import static com.android.internal.util.Preconditions.checkNotNull;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
@@ -26,6 +25,7 @@ import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.net.annotations.PolicyDirection;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -41,8 +41,6 @@ import dalvik.system.CloseGuard;
import java.io.FileDescriptor;
import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
@@ -78,11 +76,6 @@ public final class IpSecManager {
*/
public static final int DIRECTION_OUT = 1;
- /** @hide */
- @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
- @Retention(RetentionPolicy.SOURCE)
- public @interface PolicyDirection {}
-
/**
* The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
*
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 33c39d489835..739e8178e68e 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -587,15 +587,14 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
- * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are
- * typically provided by restricted networks.
+ * Deduces that all the capabilities it provides are typically provided by restricted networks
+ * or not.
*
- * TODO: consider:
- * - Renaming it to guessRestrictedCapability and make it set the
- * restricted capability bit in addition to clearing it.
+ * @return {@code true} if the network should be restricted.
* @hide
*/
- public void maybeMarkCapabilitiesRestricted() {
+ @SystemApi
+ public boolean deduceRestrictedCapability() {
// Check if we have any capability that forces the network to be restricted.
final boolean forceRestrictedCapability =
(mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0;
@@ -609,8 +608,17 @@ public final class NetworkCapabilities implements Parcelable {
final boolean hasRestrictedCapabilities =
(mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0;
- if (forceRestrictedCapability
- || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities)) {
+ return forceRestrictedCapability
+ || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities);
+ }
+
+ /**
+ * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if deducing the network is restricted.
+ *
+ * @hide
+ */
+ public void maybeMarkCapabilitiesRestricted() {
+ if (deduceRestrictedCapability()) {
removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
}
}
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
new file mode 100644
index 000000000000..2c0e4aa700b1
--- /dev/null
+++ b/core/java/android/net/NetworkProvider.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.util.Log;
+
+/**
+ * Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device
+ * to networks and makes them available to to the core network stack by creating
+ * {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted
+ * with via networking APIs such as {@link ConnectivityManager}.
+ *
+ * Subclasses should implement {@link #onNetworkRequested} and {@link #onRequestWithdrawn} to
+ * receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the
+ * best (highest-scoring) network for any request is generally not used by the system, and torn
+ * down.
+ *
+ * @hide
+ */
+@SystemApi
+public class NetworkProvider {
+ /**
+ * {@code providerId} value that indicates the absence of a provider. It is the providerId of
+ * any NetworkProvider that is not currently registered, and of any NetworkRequest that is not
+ * currently being satisfied by a network.
+ */
+ public static final int ID_NONE = -1;
+
+ /**
+ * A hardcoded ID for NetworkAgents representing VPNs. These agents are not created by any
+ * provider, so they use this constant for clarity instead of NONE.
+ * @hide only used by ConnectivityService.
+ */
+ public static final int ID_VPN = -2;
+
+ /**
+ * The first providerId value that will be allocated.
+ * @hide only used by ConnectivityService.
+ */
+ public static final int FIRST_PROVIDER_ID = 1;
+
+ /** @hide only used by ConnectivityService */
+ public static final int CMD_REQUEST_NETWORK = 1;
+ /** @hide only used by ConnectivityService */
+ public static final int CMD_CANCEL_REQUEST = 2;
+
+ private final Messenger mMessenger;
+ private final String mName;
+ private final ConnectivityManager mCm;
+
+ private int mProviderId = ID_NONE;
+
+ /**
+ * Constructs a new NetworkProvider.
+ *
+ * @param looper the Looper on which to run {@link #onNetworkRequested} and
+ * {@link #onRequestWithdrawn}.
+ * @param name the name of the listener, used only for debugging.
+ *
+ * @hide
+ */
+ @SystemApi
+ public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) {
+ mCm = ConnectivityManager.from(context);
+
+ Handler handler = new Handler(looper) {
+ @Override
+ public void handleMessage(Message m) {
+ switch (m.what) {
+ case CMD_REQUEST_NETWORK:
+ onNetworkRequested((NetworkRequest) m.obj, m.arg1, m.arg2);
+ break;
+ case CMD_CANCEL_REQUEST:
+ onRequestWithdrawn((NetworkRequest) m.obj);
+ break;
+ default:
+ Log.e(mName, "Unhandled message: " + m.what);
+ }
+ }
+ };
+ mMessenger = new Messenger(handler);
+ mName = name;
+ }
+
+ // TODO: consider adding a register() method so ConnectivityManager does not need to call this.
+ public @Nullable Messenger getMessenger() {
+ return mMessenger;
+ }
+
+ public @NonNull String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the ID of this provider. This is known only once the provider is registered via
+ * {@link ConnectivityManager#registerNetworkProvider()}, otherwise the ID is {@link #ID_NONE}.
+ * This ID must be used when registering any {@link NetworkAgent}s.
+ */
+ public int getProviderId() {
+ return mProviderId;
+ }
+
+ /** @hide */
+ public void setProviderId(int providerId) {
+ mProviderId = providerId;
+ }
+
+ /**
+ * Called when a NetworkRequest is received. The request may be a new request or an existing
+ * request with a different score.
+ *
+ * @param request the NetworkRequest being received
+ * @param score the score of the network currently satisfying the request, or 0 if none.
+ * @param providerId the ID of the provider that created the network currently satisfying this
+ * request, or {@link #ID_NONE} if none.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {}
+
+ /**
+ * Called when a NetworkRequest is withdrawn.
+ * @hide
+ */
+ @SystemApi
+ public void onRequestWithdrawn(@NonNull NetworkRequest request) {}
+
+ /**
+ * Asserts that no provider will ever be able to satisfy the specified request. The provider
+ * must only call this method if it knows that it is the only provider on the system capable of
+ * satisfying this request, and that the request cannot be satisfied. The application filing the
+ * request will receive an {@link NetworkCallback#onUnavailable()} callback.
+ *
+ * @param request the request that cannot be fulfilled
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
+ mCm.declareNetworkRequestUnfulfillable(request);
+ }
+}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 431773dc2622..9731f3ca186d 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -247,9 +247,8 @@ public class NetworkRequest implements Parcelable {
* removing even the capabilities that are set by default when the object is constructed.
*
* @return The builder to facilitate chaining.
- * @hide
*/
- @UnsupportedAppUsage
+ @NonNull
public Builder clearCapabilities() {
mNetworkCapabilities.clearAll();
return this;
diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java
index 2bc3eb56ec2d..cf31d217c967 100644
--- a/core/java/android/net/NetworkSpecifier.java
+++ b/core/java/android/net/NetworkSpecifier.java
@@ -16,6 +16,9 @@
package android.net;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
/**
* Describes specific properties of a requested network for use in a {@link NetworkRequest}.
*
@@ -31,7 +34,8 @@ public abstract class NetworkSpecifier {
*
* @hide
*/
- public abstract boolean satisfiedBy(NetworkSpecifier other);
+ @SystemApi
+ public abstract boolean satisfiedBy(@Nullable NetworkSpecifier other);
/**
* Optional method which can be overridden by concrete implementations of NetworkSpecifier to
@@ -45,6 +49,7 @@ public abstract class NetworkSpecifier {
*
* @hide
*/
+ @SystemApi
public void assertValidFromUid(int requestorUid) {
// empty
}
@@ -68,6 +73,8 @@ public abstract class NetworkSpecifier {
*
* @hide
*/
+ @SystemApi
+ @Nullable
public NetworkSpecifier redact() {
// TODO (b/122160111): convert default to null once all platform NetworkSpecifiers
// implement this method.
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 45bf4d2e1358..96d7a80886a5 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -19,6 +19,9 @@ package android.net;
import static android.os.Process.CLAT_UID;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -48,59 +51,104 @@ import java.util.function.Predicate;
* @hide
*/
// @NotThreadSafe
-public class NetworkStats implements Parcelable {
+@SystemApi
+public final class NetworkStats implements Parcelable {
private static final String TAG = "NetworkStats";
+
/** {@link #iface} value when interface details unavailable. */
- public static final String IFACE_ALL = null;
+ @SuppressLint("CompileTimeConstant")
+ @Nullable public static final String IFACE_ALL = null;
+ /**
+ * Virtual network interface for video telephony. This is for VT data usage counting
+ * purpose.
+ */
+ public static final String IFACE_VT = "vt_data0";
+
/** {@link #uid} value when UID details unavailable. */
public static final int UID_ALL = -1;
- /** {@link #tag} value matching any tag. */
+ /** Special UID value for data usage by tethering. */
+ public static final int UID_TETHERING = -5;
+
+ /**
+ * {@link #tag} value matching any tag.
+ * @hide
+ */
// TODO: Rename TAG_ALL to TAG_ANY.
public static final int TAG_ALL = -1;
- /** {@link #set} value for all sets combined, not including debug sets. */
+ /**
+ * {@link #set} value for all sets combined, not including debug sets.
+ * @hide
+ */
public static final int SET_ALL = -1;
/** {@link #set} value where background data is accounted. */
public static final int SET_DEFAULT = 0;
/** {@link #set} value where foreground data is accounted. */
public static final int SET_FOREGROUND = 1;
- /** All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. */
+ /**
+ * All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values.
+ * @hide
+ */
public static final int SET_DEBUG_START = 1000;
- /** Debug {@link #set} value when the VPN stats are moved in. */
+ /**
+ * Debug {@link #set} value when the VPN stats are moved in.
+ * @hide
+ */
public static final int SET_DBG_VPN_IN = 1001;
- /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */
+ /**
+ * Debug {@link #set} value when the VPN stats are moved out of a vpn UID.
+ * @hide
+ */
public static final int SET_DBG_VPN_OUT = 1002;
- /** Include all interfaces when filtering */
- public static final String[] INTERFACES_ALL = null;
+ /**
+ * Include all interfaces when filtering
+ * @hide
+ */
+ public @Nullable static final String[] INTERFACES_ALL = null;
/** {@link #tag} value for total data across all tags. */
// TODO: Rename TAG_NONE to TAG_ALL.
public static final int TAG_NONE = 0;
- /** {@link #metered} value to account for all metered states. */
+ /**
+ * {@link #metered} value to account for all metered states.
+ * @hide
+ */
public static final int METERED_ALL = -1;
/** {@link #metered} value where native, unmetered data is accounted. */
public static final int METERED_NO = 0;
/** {@link #metered} value where metered data is accounted. */
public static final int METERED_YES = 1;
- /** {@link #roaming} value to account for all roaming states. */
+ /**
+ * {@link #roaming} value to account for all roaming states.
+ * @hide
+ */
public static final int ROAMING_ALL = -1;
/** {@link #roaming} value where native, non-roaming data is accounted. */
public static final int ROAMING_NO = 0;
/** {@link #roaming} value where roaming data is accounted. */
public static final int ROAMING_YES = 1;
- /** {@link #onDefaultNetwork} value to account for all default network states. */
+ /**
+ * {@link #onDefaultNetwork} value to account for all default network states.
+ * @hide
+ */
public static final int DEFAULT_NETWORK_ALL = -1;
/** {@link #onDefaultNetwork} value to account for usage while not the default network. */
public static final int DEFAULT_NETWORK_NO = 0;
/** {@link #onDefaultNetwork} value to account for usage while the default network. */
public static final int DEFAULT_NETWORK_YES = 1;
- /** Denotes a request for stats at the interface level. */
+ /**
+ * Denotes a request for stats at the interface level.
+ * @hide
+ */
public static final int STATS_PER_IFACE = 0;
- /** Denotes a request for stats at the interface and UID level. */
+ /**
+ * Denotes a request for stats at the interface and UID level.
+ * @hide
+ */
public static final int STATS_PER_UID = 1;
private static final String CLATD_INTERFACE_PREFIX = "v4-";
@@ -144,60 +192,78 @@ public class NetworkStats implements Parcelable {
@UnsupportedAppUsage
private long[] operations;
+ /** @hide */
+ @SystemApi
public static class Entry {
+ /** @hide */
@UnsupportedAppUsage
public String iface;
+ /** @hide */
@UnsupportedAppUsage
public int uid;
+ /** @hide */
@UnsupportedAppUsage
public int set;
+ /** @hide */
@UnsupportedAppUsage
public int tag;
/**
* Note that this is only populated w/ the default value when read from /proc or written
* to disk. We merge in the correct value when reporting this value to clients of
* getSummary().
+ * @hide
*/
public int metered;
/**
* Note that this is only populated w/ the default value when read from /proc or written
* to disk. We merge in the correct value when reporting this value to clients of
* getSummary().
+ * @hide
*/
public int roaming;
/**
* Note that this is only populated w/ the default value when read from /proc or written
* to disk. We merge in the correct value when reporting this value to clients of
* getSummary().
+ * @hide
*/
public int defaultNetwork;
+ /** @hide */
@UnsupportedAppUsage
public long rxBytes;
+ /** @hide */
@UnsupportedAppUsage
public long rxPackets;
+ /** @hide */
@UnsupportedAppUsage
public long txBytes;
+ /** @hide */
@UnsupportedAppUsage
public long txPackets;
+ /** @hide */
+ @UnsupportedAppUsage
public long operations;
+ /** @hide */
@UnsupportedAppUsage
public Entry() {
this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
}
+ /** @hide */
public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
operations);
}
+ /** @hide */
public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
long txBytes, long txPackets, long operations) {
this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
rxBytes, rxPackets, txBytes, txPackets, operations);
}
- public Entry(String iface, int uid, int set, int tag, int metered, int roaming,
+ public Entry(@Nullable String iface, int uid, int set, int tag, int metered, int roaming,
int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
long operations) {
this.iface = iface;
@@ -214,15 +280,18 @@ public class NetworkStats implements Parcelable {
this.operations = operations;
}
+ /** @hide */
public boolean isNegative() {
return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0;
}
+ /** @hide */
public boolean isEmpty() {
return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0
&& operations == 0;
}
+ /** @hide */
public void add(Entry another) {
this.rxBytes += another.rxBytes;
this.rxPackets += another.rxPackets;
@@ -249,6 +318,7 @@ public class NetworkStats implements Parcelable {
return builder.toString();
}
+ /** @hide */
@Override
public boolean equals(Object o) {
if (o instanceof Entry) {
@@ -262,13 +332,13 @@ public class NetworkStats implements Parcelable {
return false;
}
+ /** @hide */
@Override
public int hashCode() {
return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface);
}
}
- @UnsupportedAppUsage
public NetworkStats(long elapsedRealtime, int initialSize) {
this.elapsedRealtime = elapsedRealtime;
this.size = 0;
@@ -292,6 +362,7 @@ public class NetworkStats implements Parcelable {
}
}
+ /** @hide */
@UnsupportedAppUsage
public NetworkStats(Parcel parcel) {
elapsedRealtime = parcel.readLong();
@@ -312,7 +383,7 @@ public class NetworkStats implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeLong(elapsedRealtime);
dest.writeInt(size);
dest.writeInt(capacity);
@@ -330,19 +401,23 @@ public class NetworkStats implements Parcelable {
dest.writeLongArray(operations);
}
+ /**
+ * @hide
+ */
@Override
public NetworkStats clone() {
final NetworkStats clone = new NetworkStats(elapsedRealtime, size);
NetworkStats.Entry entry = null;
for (int i = 0; i < size; i++) {
entry = getValues(i, entry);
- clone.addValues(entry);
+ clone.addEntry(entry);
}
return clone;
}
/**
* Clear all data stored in this object.
+ * @hide
*/
public void clear() {
this.capacity = 0;
@@ -360,25 +435,28 @@ public class NetworkStats implements Parcelable {
this.operations = EmptyArray.LONG;
}
+ /** @hide */
@VisibleForTesting
public NetworkStats addIfaceValues(
String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- return addValues(
+ return addEntry(
iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
}
+ /** @hide */
@VisibleForTesting
- public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
+ public NetworkStats addEntry(String iface, int uid, int set, int tag, long rxBytes,
long rxPackets, long txBytes, long txPackets, long operations) {
- return addValues(new Entry(
+ return addEntry(new Entry(
iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
}
+ /** @hide */
@VisibleForTesting
- public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming,
+ public NetworkStats addEntry(String iface, int uid, int set, int tag, int metered, int roaming,
int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
long operations) {
- return addValues(new Entry(
+ return addEntry(new Entry(
iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets,
txBytes, txPackets, operations));
}
@@ -386,8 +464,9 @@ public class NetworkStats implements Parcelable {
/**
* Add new stats entry, copying from given {@link Entry}. The {@link Entry}
* object can be recycled across multiple calls.
+ * @hide
*/
- public NetworkStats addValues(Entry entry) {
+ public NetworkStats addEntry(Entry entry) {
if (size >= capacity) {
final int newLength = Math.max(size, 10) * 3 / 2;
iface = Arrays.copyOf(iface, newLength);
@@ -428,6 +507,7 @@ public class NetworkStats implements Parcelable {
/**
* Return specific stats entry.
+ * @hide
*/
@UnsupportedAppUsage
public Entry getValues(int i, Entry recycle) {
@@ -467,10 +547,12 @@ public class NetworkStats implements Parcelable {
operations[dest] = operations[src];
}
+ /** @hide */
public long getElapsedRealtime() {
return elapsedRealtime;
}
+ /** @hide */
public void setElapsedRealtime(long time) {
elapsedRealtime = time;
}
@@ -478,21 +560,25 @@ public class NetworkStats implements Parcelable {
/**
* Return age of this {@link NetworkStats} object with respect to
* {@link SystemClock#elapsedRealtime()}.
+ * @hide
*/
public long getElapsedRealtimeAge() {
return SystemClock.elapsedRealtime() - elapsedRealtime;
}
+ /** @hide */
@UnsupportedAppUsage
public int size() {
return size;
}
+ /** @hide */
@VisibleForTesting
public int internalSize() {
return capacity;
}
+ /** @hide */
@Deprecated
public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
long txBytes, long txPackets, long operations) {
@@ -501,6 +587,7 @@ public class NetworkStats implements Parcelable {
txPackets, operations);
}
+ /** @hide */
public NetworkStats combineValues(String iface, int uid, int set, int tag,
long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
return combineValues(new Entry(
@@ -509,16 +596,20 @@ public class NetworkStats implements Parcelable {
/**
* Combine given values with an existing row, or create a new row if
- * {@link #findIndex(String, int, int, int, int)} is unable to find match. Can
- * also be used to subtract values from existing rows.
+ * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can
+ * also be used to subtract values from existing rows. This method mutates the referencing
+ * {@link NetworkStats} object.
+ *
+ * @param entry the {@link Entry} to combine.
+ * @return a reference to this mutated {@link NetworkStats} object.
+ * @hide
*/
- @UnsupportedAppUsage
- public NetworkStats combineValues(Entry entry) {
+ public @NonNull NetworkStats combineValues(@NonNull Entry entry) {
final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered,
entry.roaming, entry.defaultNetwork);
if (i == -1) {
// only create new entry when positive contribution
- addValues(entry);
+ addEntry(entry);
} else {
rxBytes[i] += entry.rxBytes;
rxPackets[i] += entry.rxPackets;
@@ -530,10 +621,33 @@ public class NetworkStats implements Parcelable {
}
/**
+ * Add given values with an existing row, or create a new row if
+ * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can
+ * also be used to subtract values from existing rows.
+ *
+ * @param entry the {@link Entry} to add.
+ * @return a new constructed {@link NetworkStats} object that contains the result.
+ */
+ public @NonNull NetworkStats addValues(@NonNull Entry entry) {
+ return this.clone().combineValues(entry);
+ }
+
+ /**
+ * Add the given {@link NetworkStats} objects.
+ *
+ * @return the sum of two objects.
+ */
+ public @NonNull NetworkStats add(@NonNull NetworkStats another) {
+ final NetworkStats ret = this.clone();
+ ret.combineAllValues(another);
+ return ret;
+ }
+
+ /**
* Combine all values from another {@link NetworkStats} into this object.
+ * @hide
*/
- @UnsupportedAppUsage
- public void combineAllValues(NetworkStats another) {
+ public void combineAllValues(@NonNull NetworkStats another) {
NetworkStats.Entry entry = null;
for (int i = 0; i < another.size; i++) {
entry = another.getValues(i, entry);
@@ -543,6 +657,7 @@ public class NetworkStats implements Parcelable {
/**
* Find first stats index that matches the requested parameters.
+ * @hide
*/
public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming,
int defaultNetwork) {
@@ -560,6 +675,7 @@ public class NetworkStats implements Parcelable {
/**
* Find first stats index that matches the requested parameters, starting
* search around the hinted index as an optimization.
+ * @hide
*/
@VisibleForTesting
public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming,
@@ -589,6 +705,7 @@ public class NetworkStats implements Parcelable {
* Splice in {@link #operations} from the given {@link NetworkStats} based
* on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
* since operation counts are at data layer.
+ * @hide
*/
public void spliceOperationsFrom(NetworkStats stats) {
for (int i = 0; i < size; i++) {
@@ -604,6 +721,7 @@ public class NetworkStats implements Parcelable {
/**
* Return list of unique interfaces known by this data structure.
+ * @hide
*/
public String[] getUniqueIfaces() {
final HashSet<String> ifaces = new HashSet<String>();
@@ -617,6 +735,7 @@ public class NetworkStats implements Parcelable {
/**
* Return list of unique UIDs known by this data structure.
+ * @hide
*/
@UnsupportedAppUsage
public int[] getUniqueUids() {
@@ -636,6 +755,7 @@ public class NetworkStats implements Parcelable {
/**
* Return total bytes represented by this snapshot object, usually used when
* checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
+ * @hide
*/
@UnsupportedAppUsage
public long getTotalBytes() {
@@ -645,6 +765,7 @@ public class NetworkStats implements Parcelable {
/**
* Return total of all fields represented by this snapshot object.
+ * @hide
*/
@UnsupportedAppUsage
public Entry getTotal(Entry recycle) {
@@ -654,6 +775,7 @@ public class NetworkStats implements Parcelable {
/**
* Return total of all fields represented by this snapshot object matching
* the requested {@link #uid}.
+ * @hide
*/
@UnsupportedAppUsage
public Entry getTotal(Entry recycle, int limitUid) {
@@ -663,11 +785,13 @@ public class NetworkStats implements Parcelable {
/**
* Return total of all fields represented by this snapshot object matching
* the requested {@link #iface}.
+ * @hide
*/
public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
return getTotal(recycle, limitIface, UID_ALL, false);
}
+ /** @hide */
@UnsupportedAppUsage
public Entry getTotalIncludingTags(Entry recycle) {
return getTotal(recycle, null, UID_ALL, true);
@@ -717,6 +841,7 @@ public class NetworkStats implements Parcelable {
/**
* Fast path for battery stats.
+ * @hide
*/
public long getTotalPackets() {
long total = 0;
@@ -729,9 +854,12 @@ public class NetworkStats implements Parcelable {
/**
* Subtract the given {@link NetworkStats}, effectively leaving the delta
* between two snapshots in time. Assumes that statistics rows collect over
- * time, and that none of them have disappeared.
+ * time, and that none of them have disappeared. This method does not mutate
+ * the referencing object.
+ *
+ * @return the delta between two objects.
*/
- public NetworkStats subtract(NetworkStats right) {
+ public @NonNull NetworkStats subtract(@NonNull NetworkStats right) {
return subtract(this, right, null, null);
}
@@ -742,6 +870,7 @@ public class NetworkStats implements Parcelable {
* <p>
* If counters have rolled backwards, they are clamped to {@code 0} and
* reported to the given {@link NonMonotonicObserver}.
+ * @hide
*/
public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
NonMonotonicObserver<C> observer, C cookie) {
@@ -759,6 +888,7 @@ public class NetworkStats implements Parcelable {
* If <var>recycle</var> is supplied, this NetworkStats object will be
* reused (and returned) as the result if it is large enough to contain
* the data.
+ * @hide
*/
public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) {
@@ -817,7 +947,7 @@ public class NetworkStats implements Parcelable {
entry.operations = Math.max(entry.operations, 0);
}
- result.addValues(entry);
+ result.addEntry(entry);
}
return result;
@@ -847,6 +977,7 @@ public class NetworkStats implements Parcelable {
* @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated.
* @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
* @param useBpfStats True if eBPF is in use.
+ * @hide
*/
public static void apply464xlatAdjustments(NetworkStats baseTraffic,
NetworkStats stackedTraffic, Map<String, String> stackedIfaces, boolean useBpfStats) {
@@ -899,6 +1030,7 @@ public class NetworkStats implements Parcelable {
* {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as
* base and stacked traffic.
* @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
+ * @hide
*/
public void apply464xlatAdjustments(Map<String, String> stackedIfaces, boolean useBpfStats) {
apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats);
@@ -907,6 +1039,7 @@ public class NetworkStats implements Parcelable {
/**
* Return total statistics grouped by {@link #iface}; doesn't mutate the
* original structure.
+ * @hide
*/
public NetworkStats groupedByIface() {
final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
@@ -938,6 +1071,7 @@ public class NetworkStats implements Parcelable {
/**
* Return total statistics grouped by {@link #uid}; doesn't mutate the
* original structure.
+ * @hide
*/
public NetworkStats groupedByUid() {
final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
@@ -968,6 +1102,7 @@ public class NetworkStats implements Parcelable {
/**
* Remove all rows that match one of specified UIDs.
+ * @hide
*/
public void removeUids(int[] uids) {
int nextOutputEntry = 0;
@@ -989,6 +1124,7 @@ public class NetworkStats implements Parcelable {
* @param limitUid UID to filter for, or {@link #UID_ALL}.
* @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}.
* @param limitTag Tag to filter for, or {@link #TAG_ALL}.
+ * @hide
*/
public void filter(int limitUid, String[] limitIfaces, int limitTag) {
if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) {
@@ -1004,6 +1140,7 @@ public class NetworkStats implements Parcelable {
* Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}.
*
* <p>This mutates the original structure in place.
+ * @hide
*/
public void filterDebugEntries() {
filter(e -> e.set < SET_DEBUG_START);
@@ -1024,6 +1161,7 @@ public class NetworkStats implements Parcelable {
size = nextOutputEntry;
}
+ /** @hide */
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
@@ -1047,6 +1185,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #set} value.
+ * @hide
*/
public static String setToString(int set) {
switch (set) {
@@ -1067,6 +1206,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #set} value.
+ * @hide
*/
public static String setToCheckinString(int set) {
switch (set) {
@@ -1087,6 +1227,7 @@ public class NetworkStats implements Parcelable {
/**
* @return true if the querySet matches the dataSet.
+ * @hide
*/
public static boolean setMatches(int querySet, int dataSet) {
if (querySet == dataSet) {
@@ -1098,6 +1239,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #tag} value.
+ * @hide
*/
public static String tagToString(int tag) {
return "0x" + Integer.toHexString(tag);
@@ -1105,6 +1247,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #metered} value.
+ * @hide
*/
public static String meteredToString(int metered) {
switch (metered) {
@@ -1121,6 +1264,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #roaming} value.
+ * @hide
*/
public static String roamingToString(int roaming) {
switch (roaming) {
@@ -1137,6 +1281,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #defaultNetwork} value.
+ * @hide
*/
public static String defaultNetworkToString(int defaultNetwork) {
switch (defaultNetwork) {
@@ -1151,6 +1296,7 @@ public class NetworkStats implements Parcelable {
}
}
+ /** @hide */
@Override
public String toString() {
final CharArrayWriter writer = new CharArrayWriter();
@@ -1163,8 +1309,7 @@ public class NetworkStats implements Parcelable {
return 0;
}
- @UnsupportedAppUsage
- public static final @android.annotation.NonNull Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
+ public static final @NonNull Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
@Override
public NetworkStats createFromParcel(Parcel in) {
return new NetworkStats(in);
@@ -1176,6 +1321,7 @@ public class NetworkStats implements Parcelable {
}
};
+ /** @hide */
public interface NonMonotonicObserver<C> {
public void foundNonMonotonic(
NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
@@ -1195,6 +1341,7 @@ public class NetworkStats implements Parcelable {
* @param tunUid uid of the VPN application
* @param tunIface iface of the vpn tunnel
* @param underlyingIfaces underlying network ifaces used by the VPN application
+ * @hide
*/
public void migrateTun(int tunUid, @NonNull String tunIface,
@NonNull String[] underlyingIfaces) {
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 162d6e27bd42..8108cf08d5c3 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -89,7 +89,7 @@ public class TrafficStats {
*
* @hide
*/
- public static final int UID_TETHERING = -5;
+ public static final int UID_TETHERING = NetworkStats.UID_TETHERING;
/**
* Tag values in this range are reserved for the network stack. The network stack is
diff --git a/core/java/android/net/annotations/PolicyDirection.java b/core/java/android/net/annotations/PolicyDirection.java
new file mode 100644
index 000000000000..febd9b406111
--- /dev/null
+++ b/core/java/android/net/annotations/PolicyDirection.java
@@ -0,0 +1,35 @@
+/*
+ * 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.annotations;
+
+import android.annotation.IntDef;
+import android.net.IpSecManager;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * IPsec traffic direction.
+ *
+ * <p>Mainline modules cannot reference hidden @IntDef. Moving this annotation to a separate class
+ * to allow others to statically include it.
+ *
+ * @hide
+ */
+@IntDef(value = {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT})
+@Retention(RetentionPolicy.SOURCE)
+public @interface PolicyDirection {}
diff --git a/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java b/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java
new file mode 100644
index 000000000000..740aa92ad484
--- /dev/null
+++ b/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netstats.provider;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.NetworkStats;
+
+/**
+ * A base class that allows external modules to implement a custom network statistics provider.
+ * @hide
+ */
+@SystemApi
+public abstract class AbstractNetworkStatsProvider {
+ /**
+ * A value used by {@link #setLimit} and {@link #setAlert} indicates there is no limit.
+ */
+ public static final int QUOTA_UNLIMITED = -1;
+
+ /**
+ * Called by {@code NetworkStatsService} when global polling is needed. Custom
+ * implementation of providers MUST respond to it by calling
+ * {@link NetworkStatsProviderCallback#onStatsUpdated} within one minute. Responding
+ * later than this may cause the stats to be dropped.
+ *
+ * @param token a positive number identifying the new state of the system under which
+ * {@link NetworkStats} have to be gathered from now on. When this is called,
+ * custom implementations of providers MUST report the latest stats with the
+ * previous token, under which stats were being gathered so far.
+ */
+ public abstract void requestStatsUpdate(int token);
+
+ /**
+ * Called by {@code NetworkStatsService} when setting the interface quota for the specified
+ * upstream interface. When this is called, the custom implementation should block all egress
+ * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have
+ * been reached, and MUST respond to it by calling
+ * {@link NetworkStatsProviderCallback#onLimitReached()}.
+ *
+ * @param iface the interface requiring the operation.
+ * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting
+ * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
+ */
+ public abstract void setLimit(@NonNull String iface, long quotaBytes);
+
+ /**
+ * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations
+ * MUST call {@link NetworkStatsProviderCallback#onAlertReached()} when {@code quotaBytes} bytes
+ * have been reached. Unlike {@link #setLimit(String, long)}, the custom implementation should
+ * not block all egress packets.
+ *
+ * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting
+ * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert.
+ */
+ public abstract void setAlert(long quotaBytes);
+}
diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
new file mode 100644
index 000000000000..55b3d4edb157
--- /dev/null
+++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netstats.provider;
+
+/**
+ * Interface for NetworkStatsService to query network statistics and set data limits.
+ *
+ * @hide
+ */
+oneway interface INetworkStatsProvider {
+ void requestStatsUpdate(int token);
+ void setLimit(String iface, long quotaBytes);
+ void setAlert(long quotaBytes);
+}
diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
new file mode 100644
index 000000000000..3ea9318f10d4
--- /dev/null
+++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netstats.provider;
+
+import android.net.NetworkStats;
+
+/**
+ * Interface for implementor of {@link INetworkStatsProviderCallback} to push events
+ * such as network statistics update or notify limit reached.
+ * @hide
+ */
+oneway interface INetworkStatsProviderCallback {
+ void onStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
+ void onAlertReached();
+ void onLimitReached();
+ void unregister();
+}
diff --git a/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java b/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java
new file mode 100644
index 000000000000..e17a8eee7ff0
--- /dev/null
+++ b/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netstats.provider;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.net.NetworkStats;
+import android.os.RemoteException;
+
+/**
+ * A callback class that allows callers to report events to the system.
+ * @hide
+ */
+@SystemApi
+@SuppressLint("CallbackMethodName")
+public class NetworkStatsProviderCallback {
+ @NonNull private final INetworkStatsProviderCallback mBinder;
+
+ /** @hide */
+ public NetworkStatsProviderCallback(@NonNull INetworkStatsProviderCallback binder) {
+ mBinder = binder;
+ }
+
+ /**
+ * Notify the system of new network statistics.
+ *
+ * Send the network statistics recorded since the last call to {@link #onStatsUpdated}. Must be
+ * called within one minute of {@link AbstractNetworkStatsProvider#requestStatsUpdate(int)}
+ * being called. The provider can also call this whenever it wants to reports new stats for any
+ * reason. Note that the system will not necessarily immediately propagate the statistics to
+ * reflect the update.
+ *
+ * @param token the token under which these stats were gathered. Providers can call this method
+ * with the current token as often as they want, until the token changes.
+ * {@see AbstractNetworkStatsProvider#requestStatsUpdate()}
+ * @param ifaceStats the {@link NetworkStats} per interface to be reported.
+ * The provider should not include any traffic that is already counted by
+ * kernel interface counters.
+ * @param uidStats the same stats as above, but counts {@link NetworkStats}
+ * per uid.
+ */
+ public void onStatsUpdated(int token, @NonNull NetworkStats ifaceStats,
+ @NonNull NetworkStats uidStats) {
+ try {
+ mBinder.onStatsUpdated(token, ifaceStats, uidStats);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Notify system that the quota set by {@code setAlert} has been reached.
+ */
+ public void onAlertReached() {
+ try {
+ mBinder.onAlertReached();
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Notify system that the quota set by {@code setLimit} has been reached.
+ */
+ public void onLimitReached() {
+ try {
+ mBinder.onLimitReached();
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Unregister the provider and the referencing callback.
+ */
+ public void unregister() {
+ try {
+ mBinder.unregister();
+ } catch (RemoteException e) {
+ // Ignore error.
+ }
+ }
+}
diff --git a/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java b/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java
new file mode 100644
index 000000000000..4bf7c9bc086e
--- /dev/null
+++ b/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netstats.provider;
+
+import android.annotation.NonNull;
+
+/**
+ * A wrapper class of {@link INetworkStatsProvider} that hides the binder interface from exposing
+ * to outer world.
+ *
+ * @hide
+ */
+public class NetworkStatsProviderWrapper extends INetworkStatsProvider.Stub {
+ @NonNull final AbstractNetworkStatsProvider mProvider;
+
+ public NetworkStatsProviderWrapper(AbstractNetworkStatsProvider provider) {
+ mProvider = provider;
+ }
+
+ @Override
+ public void requestStatsUpdate(int token) {
+ mProvider.requestStatsUpdate(token);
+ }
+
+ @Override
+ public void setLimit(@NonNull String iface, long quotaBytes) {
+ mProvider.setLimit(iface, quotaBytes);
+ }
+
+ @Override
+ public void setAlert(long quotaBytes) {
+ mProvider.setAlert(quotaBytes);
+ }
+}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index c9ebed3bd0a2..1a4dac78855f 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1886,29 +1886,7 @@ public final class Parcel {
public final void writeException(@NonNull Exception e) {
AppOpsManager.prefixParcelWithAppOpsIfNeeded(this);
- int code = 0;
- if (e instanceof Parcelable
- && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) {
- // We only send Parcelable exceptions that are in the
- // BootClassLoader to ensure that the receiver can unpack them
- code = EX_PARCELABLE;
- } else if (e instanceof SecurityException) {
- code = EX_SECURITY;
- } else if (e instanceof BadParcelableException) {
- code = EX_BAD_PARCELABLE;
- } else if (e instanceof IllegalArgumentException) {
- code = EX_ILLEGAL_ARGUMENT;
- } else if (e instanceof NullPointerException) {
- code = EX_NULL_POINTER;
- } else if (e instanceof IllegalStateException) {
- code = EX_ILLEGAL_STATE;
- } else if (e instanceof NetworkOnMainThreadException) {
- code = EX_NETWORK_MAIN_THREAD;
- } else if (e instanceof UnsupportedOperationException) {
- code = EX_UNSUPPORTED_OPERATION;
- } else if (e instanceof ServiceSpecificException) {
- code = EX_SERVICE_SPECIFIC;
- }
+ int code = getExceptionCode(e);
writeInt(code);
StrictMode.clearGatheredViolations();
if (code == 0) {
@@ -1922,20 +1900,7 @@ public final class Parcel {
if (sParcelExceptionStackTrace && (timeNow - sLastWriteExceptionStackTrace
> WRITE_EXCEPTION_STACK_TRACE_THRESHOLD_MS)) {
sLastWriteExceptionStackTrace = timeNow;
- final int sizePosition = dataPosition();
- writeInt(0); // Header size will be filled in later
- StackTraceElement[] stackTrace = e.getStackTrace();
- final int truncatedSize = Math.min(stackTrace.length, 5);
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < truncatedSize; i++) {
- sb.append("\tat ").append(stackTrace[i]).append('\n');
- }
- writeString(sb.toString());
- final int payloadPosition = dataPosition();
- setDataPosition(sizePosition);
- // Write stack trace header size. Used in native side to skip the header
- writeInt(payloadPosition - sizePosition);
- setDataPosition(payloadPosition);
+ writeStackTrace(e);
} else {
writeInt(0);
}
@@ -1956,6 +1921,52 @@ public final class Parcel {
}
}
+ /** @hide */
+ public static int getExceptionCode(@NonNull Throwable e) {
+ int code = 0;
+ if (e instanceof Parcelable
+ && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) {
+ // We only send Parcelable exceptions that are in the
+ // BootClassLoader to ensure that the receiver can unpack them
+ code = EX_PARCELABLE;
+ } else if (e instanceof SecurityException) {
+ code = EX_SECURITY;
+ } else if (e instanceof BadParcelableException) {
+ code = EX_BAD_PARCELABLE;
+ } else if (e instanceof IllegalArgumentException) {
+ code = EX_ILLEGAL_ARGUMENT;
+ } else if (e instanceof NullPointerException) {
+ code = EX_NULL_POINTER;
+ } else if (e instanceof IllegalStateException) {
+ code = EX_ILLEGAL_STATE;
+ } else if (e instanceof NetworkOnMainThreadException) {
+ code = EX_NETWORK_MAIN_THREAD;
+ } else if (e instanceof UnsupportedOperationException) {
+ code = EX_UNSUPPORTED_OPERATION;
+ } else if (e instanceof ServiceSpecificException) {
+ code = EX_SERVICE_SPECIFIC;
+ }
+ return code;
+ }
+
+ /** @hide */
+ public void writeStackTrace(@NonNull Throwable e) {
+ final int sizePosition = dataPosition();
+ writeInt(0); // Header size will be filled in later
+ StackTraceElement[] stackTrace = e.getStackTrace();
+ final int truncatedSize = Math.min(stackTrace.length, 5);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < truncatedSize; i++) {
+ sb.append("\tat ").append(stackTrace[i]).append('\n');
+ }
+ writeString(sb.toString());
+ final int payloadPosition = dataPosition();
+ setDataPosition(sizePosition);
+ // Write stack trace header size. Used in native side to skip the header
+ writeInt(payloadPosition - sizePosition);
+ setDataPosition(payloadPosition);
+ }
+
/**
* Special function for writing information at the front of the Parcel
* indicating that no exception occurred.
@@ -2069,14 +2080,7 @@ public final class Parcel {
if (remoteStackTrace != null) {
RemoteException cause = new RemoteException(
"Remote stack trace:\n" + remoteStackTrace, null, false, false);
- try {
- Throwable rootCause = ExceptionUtils.getRootCause(e);
- if (rootCause != null) {
- rootCause.initCause(cause);
- }
- } catch (RuntimeException ex) {
- Log.e(TAG, "Cannot set cause " + cause + " for " + e, ex);
- }
+ ExceptionUtils.appendCause(e, cause);
}
SneakyThrow.sneakyThrow(e);
}
@@ -2088,6 +2092,14 @@ public final class Parcel {
* @param msg The exception message.
*/
private Exception createException(int code, String msg) {
+ Exception exception = createExceptionOrNull(code, msg);
+ return exception != null
+ ? exception
+ : new RuntimeException("Unknown exception code: " + code + " msg " + msg);
+ }
+
+ /** @hide */
+ public Exception createExceptionOrNull(int code, String msg) {
switch (code) {
case EX_PARCELABLE:
if (readInt() > 0) {
@@ -2111,9 +2123,9 @@ public final class Parcel {
return new UnsupportedOperationException(msg);
case EX_SERVICE_SPECIFIC:
return new ServiceSpecificException(readInt(), msg);
+ default:
+ return null;
}
- return new RuntimeException("Unknown exception code: " + code
- + " msg " + msg);
}
/**
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 983053bbe7fd..89ddf8cbd96a 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -31,6 +31,9 @@ import static android.system.OsConstants.S_ISLNK;
import static android.system.OsConstants.S_ISREG;
import static android.system.OsConstants.S_IWOTH;
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
@@ -253,6 +256,9 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
* be opened with the requested mode.
* @see #parseMode(String)
*/
+ // We can't accept a generic Executor here, since we need to use
+ // MessageQueue.addOnFileDescriptorEventListener()
+ @SuppressLint("ExecutorRegistration")
public static ParcelFileDescriptor open(File file, int mode, Handler handler,
final OnCloseListener listener) throws IOException {
if (handler == null) {
@@ -268,9 +274,22 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
return fromFd(fd, handler, listener);
}
- /** {@hide} */
- public static ParcelFileDescriptor fromPfd(ParcelFileDescriptor pfd, Handler handler,
- final OnCloseListener listener) throws IOException {
+ /**
+ * Create a new ParcelFileDescriptor wrapping an already-opened file.
+ *
+ * @param pfd The already-opened file.
+ * @param handler to call listener from.
+ * @param listener to be invoked when the returned descriptor has been
+ * closed.
+ * @return a new ParcelFileDescriptor pointing to the given file.
+ * @hide
+ */
+ @SystemApi
+ // We can't accept a generic Executor here, since we need to use
+ // MessageQueue.addOnFileDescriptorEventListener()
+ @SuppressLint("ExecutorRegistration")
+ public static @NonNull ParcelFileDescriptor wrap(@NonNull ParcelFileDescriptor pfd,
+ @NonNull Handler handler, @NonNull OnCloseListener listener) throws IOException {
final FileDescriptor original = new FileDescriptor();
original.setInt$(pfd.detachFd());
return fromFd(original, handler, listener);
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index b40283f49408..7a837e167fb0 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -16,17 +16,24 @@
package android.os;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArrayMap;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
/**
@@ -339,4 +346,44 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
proto.end(token);
}
+
+ /**
+ * Writes the content of the {@link PersistableBundle} to a {@link OutputStream}.
+ *
+ * <p>The content can be read by a {@link #readFromStream}.
+ *
+ * @see #readFromStream
+ */
+ public void writeToStream(@NonNull OutputStream outputStream) throws IOException {
+ FastXmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(outputStream, UTF_8.name());
+ serializer.startTag(null, "bundle");
+ try {
+ saveToXml(serializer);
+ } catch (XmlPullParserException e) {
+ throw new IOException(e);
+ }
+ serializer.endTag(null, "bundle");
+ serializer.flush();
+ }
+
+ /**
+ * Reads a {@link PersistableBundle} from an {@link InputStream}.
+ *
+ * <p>The stream must be generated by {@link #writeToStream}.
+ *
+ * @see #writeToStream
+ */
+ @NonNull
+ public static PersistableBundle readFromStream(@NonNull InputStream inputStream)
+ throws IOException {
+ try {
+ XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
+ parser.setInput(inputStream, UTF_8.name());
+ parser.next();
+ return PersistableBundle.restoreFromXml(parser);
+ } catch (XmlPullParserException e) {
+ throw new IOException(e);
+ }
+ }
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 94623bc71346..5d80ab6453cc 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -68,10 +68,9 @@ public class Process {
public static final int LOG_UID = 1007;
/**
- * Defines the UID/GID for the WIFI supplicant process.
- * @hide
+ * Defines the UID/GID for the WIFI native processes like wificond, supplicant, hostapd,
+ * vendor HAL, etc.
*/
- @UnsupportedAppUsage
public static final int WIFI_UID = 1010;
/**
@@ -89,6 +88,12 @@ public class Process {
public static final int DRM_UID = 1019;
/**
+ * Defines the GID for the group that allows write access to the internal media storage.
+ * @hide
+ */
+ public static final int SDCARD_RW_GID = 1015;
+
+ /**
* Defines the UID/GID for the group that controls VPN services.
* @hide
*/
@@ -752,11 +757,12 @@ public class Process {
/**
* Set the priority of a thread, based on Linux priorities.
- *
- * @param tid The identifier of the thread/process to change.
+ *
+ * @param tid The identifier of the thread/process to change. It should be
+ * the native thread id but not the managed id of {@link java.lang.Thread}.
* @param priority A Linux priority level, from -20 for highest scheduling
* priority to 19 for lowest scheduling priority.
- *
+ *
* @throws IllegalArgumentException Throws IllegalArgumentException if
* <var>tid</var> does not exist.
* @throws SecurityException Throws SecurityException if your process does
diff --git a/core/java/android/os/TelephonyServiceManager.java b/core/java/android/os/TelephonyServiceManager.java
index 1211dd60f591..064cf7d825b5 100644
--- a/core/java/android/os/TelephonyServiceManager.java
+++ b/core/java/android/os/TelephonyServiceManager.java
@@ -18,6 +18,7 @@ package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.Context;
/**
* Provides a way to register and obtain the system service binder objects managed by the telephony
@@ -51,8 +52,8 @@ public class TelephonyServiceManager {
/**
* Register a system server binding object for a service.
*/
- public void register(@NonNull IBinder binder) {
- ServiceManager.addService(mServiceName, binder);
+ public void register(@NonNull IBinder service) {
+ ServiceManager.addService(mServiceName, service);
}
/**
@@ -114,25 +115,123 @@ public class TelephonyServiceManager {
*/
@NonNull
public ServiceRegisterer getTelephonyServiceRegisterer() {
- return new ServiceRegisterer("phone");
- }
-
-
-// TODO: Add more services...
-//
-// /**
-// * Returns {@link ServiceRegisterer} for the "subscription" service.
-// */
-// @NonNull
-// public ServiceRegisterer getSubscriptionServiceRegisterer() {
-// return new ServiceRegisterer("isub");
-// }
-//
-// /**
-// * Returns {@link ServiceRegisterer} for the "SMS" service.
-// */
-// @NonNull
-// public ServiceRegisterer getSmsServiceRegisterer() {
-// return new ServiceRegisterer("isms");
-// }
+ return new ServiceRegisterer(Context.TELEPHONY_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the telephony registry service.
+ */
+ @NonNull
+ public ServiceRegisterer getTelephonyRegistryServiceRegisterer() {
+ return new ServiceRegisterer("telephony.registry");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the telephony IMS service.
+ */
+ @NonNull
+ public ServiceRegisterer getTelephonyImsServiceRegisterer() {
+ return new ServiceRegisterer(Context.TELEPHONY_IMS_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the telephony RCS message service.
+ */
+ @NonNull
+ public ServiceRegisterer getTelephonyRcsMessageServiceRegisterer() {
+ return new ServiceRegisterer(Context.TELEPHONY_RCS_MESSAGE_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the subscription service.
+ */
+ @NonNull
+ public ServiceRegisterer getSubscriptionServiceRegisterer() {
+ return new ServiceRegisterer("isub");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the network policy service.
+ */
+ @NonNull
+ public ServiceRegisterer getNetworkPolicyServiceRegisterer() {
+ return new ServiceRegisterer(Context.NETWORK_POLICY_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the phone sub service.
+ */
+ @NonNull
+ public ServiceRegisterer getPhoneSubServiceRegisterer() {
+ return new ServiceRegisterer("iphonesubinfo");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the opportunistic network service.
+ */
+ @NonNull
+ public ServiceRegisterer getOpportunisticNetworkServiceRegisterer() {
+ return new ServiceRegisterer("ions");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the carrier config service.
+ */
+ @NonNull
+ public ServiceRegisterer getCarrierConfigServiceRegisterer() {
+ return new ServiceRegisterer(Context.CARRIER_CONFIG_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the "SMS" service.
+ */
+ @NonNull
+ public ServiceRegisterer getSmsServiceRegisterer() {
+ return new ServiceRegisterer("isms");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the eUICC controller service.
+ */
+ @NonNull
+ public ServiceRegisterer getEuiccControllerService() {
+ return new ServiceRegisterer("econtroller");
+ }
+
+ @NonNull
+ public ServiceRegisterer getEuiccCardControllerServiceRegisterer() {
+ return new ServiceRegisterer("euicc_card_controller");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the package manager service.
+ */
+ @NonNull
+ public ServiceRegisterer getPackageManagerServiceRegisterer() {
+ return new ServiceRegisterer("package");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the permission manager service.
+ */
+ @NonNull
+ public ServiceRegisterer getPermissionManagerServiceRegisterer() {
+ return new ServiceRegisterer("permissionmgr");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the ICC phone book service.
+ */
+ @NonNull
+ public ServiceRegisterer getIccPhoneBookServiceRegisterer() {
+ return new ServiceRegisterer("simphonebook");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the window service.
+ */
+ @NonNull
+ public ServiceRegisterer getWindowServiceRegisterer() {
+ return new ServiceRegisterer(Context.WINDOW_SERVICE);
+ }
}
diff --git a/core/java/android/util/TimestampedValue.java b/core/java/android/os/TimestampedValue.java
index 45056730b08b..348574ed43c7 100644
--- a/core/java/android/util/TimestampedValue.java
+++ b/core/java/android/os/TimestampedValue.java
@@ -14,13 +14,10 @@
* limitations under the License.
*/
-package android.util;
+package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
import java.util.Objects;
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index a9ddffe7d55c..73e1adf134f2 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -16,8 +16,10 @@
package android.os;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.content.res.AssetFileDescriptor;
import android.os.IUpdateEngine;
import android.os.IUpdateEngineCallback;
import android.os.RemoteException;
@@ -140,8 +142,43 @@ public class UpdateEngine {
* {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}.
*/
public static final int UPDATED_BUT_NOT_ACTIVE = 52;
+
+ /**
+ * Error code: there is not enough space on the device to apply the update. User should
+ * be prompted to free up space and re-try the update.
+ *
+ * <p>See {@link UpdateEngine#allocateSpace}.
+ */
+ public static final int NOT_ENOUGH_SPACE = 60;
+
+ /**
+ * Error code: the device is corrupted and no further updates may be applied.
+ *
+ * <p>See {@link UpdateEngine#cleanupAppliedPayload}.
+ */
+ public static final int DEVICE_CORRUPTED = 61;
}
+ /** @hide */
+ @IntDef(value = {
+ ErrorCodeConstants.SUCCESS,
+ ErrorCodeConstants.ERROR,
+ ErrorCodeConstants.FILESYSTEM_COPIER_ERROR,
+ ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR,
+ ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR,
+ ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR,
+ ErrorCodeConstants.KERNEL_DEVICE_OPEN_ERROR,
+ ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR,
+ ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR,
+ ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR,
+ ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR,
+ ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR,
+ ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE,
+ ErrorCodeConstants.NOT_ENOUGH_SPACE,
+ ErrorCodeConstants.DEVICE_CORRUPTED,
+ })
+ public @interface ErrorCode {}
+
/**
* Status codes for update engine. Values must agree with the ones in
* {@code system/update_engine/client_library/include/update_engine/update_status.h}.
@@ -313,16 +350,17 @@ public class UpdateEngine {
}
/**
- * Applies the payload passed as ParcelFileDescriptor {@code pfd} instead of
- * using the {@code file://} scheme.
+ * Applies the payload passed as AssetFileDescriptor {@code assetFd}
+ * instead of using the {@code file://} scheme.
*
* <p>See {@link #applyPayload(String)} for {@code offset}, {@code size} and
* {@code headerKeyValuePairs} parameters.
*/
- public void applyPayload(@NonNull ParcelFileDescriptor pfd, long offset, long size,
+ public void applyPayload(@NonNull AssetFileDescriptor assetFd,
@NonNull String[] headerKeyValuePairs) {
try {
- mUpdateEngine.applyPayloadFd(pfd, offset, size, headerKeyValuePairs);
+ mUpdateEngine.applyPayloadFd(assetFd.getParcelFileDescriptor(),
+ assetFd.getStartOffset(), assetFd.getLength(), headerKeyValuePairs);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -419,4 +457,138 @@ public class UpdateEngine {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Return value of {@link #allocateSpace.}
+ */
+ public static final class AllocateSpaceResult {
+ private @ErrorCode int mErrorCode = ErrorCodeConstants.SUCCESS;
+ private long mFreeSpaceRequired = 0;
+ private AllocateSpaceResult() {}
+ /**
+ * Error code.
+ *
+ * @return The following error codes:
+ * <ul>
+ * <li>{@link ErrorCodeConstants#SUCCESS} if space has been allocated
+ * successfully.</li>
+ * <li>{@link ErrorCodeConstants#NOT_ENOUGH_SPACE} if insufficient
+ * space.</li>
+ * <li>Other {@link ErrorCodeConstants} for other errors.</li>
+ * </ul>
+ */
+ @ErrorCode
+ public int errorCode() {
+ return mErrorCode;
+ }
+
+ /**
+ * Estimated total space that needs to be available on the userdata partition to apply the
+ * payload (in bytes).
+ *
+ * <p>
+ * Note that in practice, more space needs to be made available before applying the payload
+ * to keep the device working.
+ *
+ * @return The following values:
+ * <ul>
+ * <li>zero if {@link #errorCode} returns {@link ErrorCodeConstants#SUCCESS}</li>
+ * <li>non-zero if {@link #errorCode} returns {@link ErrorCodeConstants#NOT_ENOUGH_SPACE}.
+ * Value is the estimated total space required on userdata partition.</li>
+ * </ul>
+ * @throws IllegalStateException if {@link #errorCode} is not one of the above.
+ *
+ */
+ public long freeSpaceRequired() {
+ if (mErrorCode == ErrorCodeConstants.SUCCESS) {
+ return 0;
+ }
+ if (mErrorCode == ErrorCodeConstants.NOT_ENOUGH_SPACE) {
+ return mFreeSpaceRequired;
+ }
+ throw new IllegalStateException(String.format(
+ "freeSpaceRequired() is not available when error code is %d", mErrorCode));
+ }
+ }
+
+ /**
+ * Initialize partitions for a payload associated with the given payload
+ * metadata {@code payloadMetadataFilename} by preallocating required space.
+ *
+ * <p>This function should be called after payload has been verified after
+ * {@link #verifyPayloadMetadata}. This function does not verify whether
+ * the given payload is applicable or not.
+ *
+ * <p>Implementation of {@code allocateSpace} uses
+ * {@code headerKeyValuePairs} to determine whether space has been allocated
+ * for a different or same payload previously. If space has been allocated
+ * for a different payload before, space will be reallocated for the given
+ * payload. If space has been allocated for the same payload, no actions to
+ * storage devices are taken.
+ *
+ * <p>This function is synchronous and may take a non-trivial amount of
+ * time. Callers should call this function in a background thread.
+ *
+ * @param payloadMetadataFilename See {@link #verifyPayloadMetadata}.
+ * @param headerKeyValuePairs See {@link #applyPayload}.
+ * @return See {@link AllocateSpaceResult}.
+ */
+ @NonNull
+ public AllocateSpaceResult allocateSpace(
+ @NonNull String payloadMetadataFilename,
+ @NonNull String[] headerKeyValuePairs) {
+ AllocateSpaceResult result = new AllocateSpaceResult();
+ try {
+ result.mFreeSpaceRequired = mUpdateEngine.allocateSpaceForPayload(
+ payloadMetadataFilename,
+ headerKeyValuePairs);
+ result.mErrorCode = result.mFreeSpaceRequired == 0
+ ? ErrorCodeConstants.SUCCESS
+ : ErrorCodeConstants.NOT_ENOUGH_SPACE;
+ return result;
+ } catch (ServiceSpecificException e) {
+ result.mErrorCode = e.errorCode;
+ result.mFreeSpaceRequired = 0;
+ return result;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Cleanup files used by the previous update and free up space after the
+ * device has been booted successfully into the new build.
+ *
+ * <p>In particular, this function waits until delta files for snapshots for
+ * Virtual A/B update are merged to OS partitions, then delete these delta
+ * files.
+ *
+ * <p>This function is synchronous and may take a non-trivial amount of
+ * time. Callers should call this function in a background thread.
+ *
+ * <p>This function does not delete payload binaries downloaded for a
+ * non-streaming OTA update.
+ *
+ * @return One of the following:
+ * <ul>
+ * <li>{@link ErrorCodeConstants#SUCCESS} if execution is successful.</li>
+ * <li>{@link ErrorCodeConstants#ERROR} if a transient error has occurred.
+ * The device should be able to recover after a reboot. The function should
+ * be retried after the reboot.</li>
+ * <li>{@link ErrorCodeConstants#DEVICE_CORRUPTED} if a permanent error is
+ * encountered. Device is corrupted, and future updates must not be applied.
+ * The device cannot recover without flashing and factory resets.
+ * </ul>
+ *
+ * @throws ServiceSpecificException if other transient errors has occurred.
+ * A reboot may or may not help resolving the issue.
+ */
+ @ErrorCode
+ public int cleanupAppliedPayload() {
+ try {
+ return mUpdateEngine.cleanupSuccessfulUpdate();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/os/UpdateEngineCallback.java b/core/java/android/os/UpdateEngineCallback.java
index f07294e222e2..7fe7024f25b3 100644
--- a/core/java/android/os/UpdateEngineCallback.java
+++ b/core/java/android/os/UpdateEngineCallback.java
@@ -44,5 +44,6 @@ public abstract class UpdateEngineCallback {
* unsuccessfully. The value of {@code errorCode} will be one of the
* values from {@link UpdateEngine.ErrorCodeConstants}.
*/
- public abstract void onPayloadApplicationComplete(int errorCode);
+ public abstract void onPayloadApplicationComplete(
+ @UpdateEngine.ErrorCode int errorCode);
}
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 62b8953b158a..3846f894c4c3 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -594,6 +594,8 @@ public class ZygoteProcess {
argsForZygote.add("--mount-external-legacy");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) {
argsForZygote.add("--mount-external-pass-through");
+ } else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
+ argsForZygote.add("--mount-external-android-writable");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 8959fcf7ac18..f0a11748fbd6 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -31,6 +31,7 @@ import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.annotation.BytesLong;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -72,6 +73,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.provider.MediaStore;
import android.provider.Settings;
import android.sysprop.VoldProperties;
@@ -93,7 +95,6 @@ import com.android.internal.os.AppFuseMount;
import com.android.internal.os.FuseAppLoop;
import com.android.internal.os.FuseUnavailableMountException;
import com.android.internal.os.RoSystemProperties;
-import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
import dalvik.system.BlockGuard;
@@ -114,6 +115,7 @@ import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -305,109 +307,85 @@ public class StorageManager {
private final Looper mLooper;
private final AtomicInteger mNextNonce = new AtomicInteger(0);
+ @GuardedBy("mDelegates")
private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
- private static class StorageEventListenerDelegate extends IStorageEventListener.Stub implements
- Handler.Callback {
- private static final int MSG_STORAGE_STATE_CHANGED = 1;
- private static final int MSG_VOLUME_STATE_CHANGED = 2;
- private static final int MSG_VOLUME_RECORD_CHANGED = 3;
- private static final int MSG_VOLUME_FORGOTTEN = 4;
- private static final int MSG_DISK_SCANNED = 5;
- private static final int MSG_DISK_DESTROYED = 6;
+ private class StorageEventListenerDelegate extends IStorageEventListener.Stub {
+ final Executor mExecutor;
+ final StorageEventListener mListener;
+ final StorageVolumeCallback mCallback;
- final StorageEventListener mCallback;
- final Handler mHandler;
-
- public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
+ public StorageEventListenerDelegate(@NonNull Executor executor,
+ @NonNull StorageEventListener listener, @NonNull StorageVolumeCallback callback) {
+ mExecutor = executor;
+ mListener = listener;
mCallback = callback;
- mHandler = new Handler(looper, this);
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- final SomeArgs args = (SomeArgs) msg.obj;
- switch (msg.what) {
- case MSG_STORAGE_STATE_CHANGED:
- mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
- (String) args.arg3);
- args.recycle();
- return true;
- case MSG_VOLUME_STATE_CHANGED:
- mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
- args.recycle();
- return true;
- case MSG_VOLUME_RECORD_CHANGED:
- mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1);
- args.recycle();
- return true;
- case MSG_VOLUME_FORGOTTEN:
- mCallback.onVolumeForgotten((String) args.arg1);
- args.recycle();
- return true;
- case MSG_DISK_SCANNED:
- mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
- args.recycle();
- return true;
- case MSG_DISK_DESTROYED:
- mCallback.onDiskDestroyed((DiskInfo) args.arg1);
- args.recycle();
- return true;
- }
- args.recycle();
- return false;
}
@Override
public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
- // Ignored
+ mExecutor.execute(() -> {
+ mListener.onUsbMassStorageConnectionChanged(connected);
+ });
}
@Override
public void onStorageStateChanged(String path, String oldState, String newState) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = path;
- args.arg2 = oldState;
- args.arg3 = newState;
- mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onStorageStateChanged(path, oldState, newState);
+
+ if (path != null) {
+ for (StorageVolume sv : getStorageVolumes()) {
+ if (Objects.equals(path, sv.getPath())) {
+ mCallback.onStateChanged(sv);
+ }
+ }
+ }
+ });
}
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = vol;
- args.argi2 = oldState;
- args.argi3 = newState;
- mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onVolumeStateChanged(vol, oldState, newState);
+
+ final File path = vol.getPathForUser(UserHandle.myUserId());
+ if (path != null) {
+ for (StorageVolume sv : getStorageVolumes()) {
+ if (Objects.equals(path.getAbsolutePath(), sv.getPath())) {
+ mCallback.onStateChanged(sv);
+ }
+ }
+ }
+ });
}
@Override
public void onVolumeRecordChanged(VolumeRecord rec) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = rec;
- mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onVolumeRecordChanged(rec);
+ });
}
@Override
public void onVolumeForgotten(String fsUuid) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = fsUuid;
- mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onVolumeForgotten(fsUuid);
+ });
}
@Override
public void onDiskScanned(DiskInfo disk, int volumeCount) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = disk;
- args.argi2 = volumeCount;
- mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onDiskScanned(disk, volumeCount);
+ });
}
@Override
public void onDiskDestroyed(DiskInfo disk) throws RemoteException {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = disk;
- mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onDiskDestroyed(disk);
+ });
}
}
@@ -525,8 +503,8 @@ public class StorageManager {
@UnsupportedAppUsage
public void registerListener(StorageEventListener listener) {
synchronized (mDelegates) {
- final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
- mLooper);
+ final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(
+ mContext.getMainExecutor(), listener, new StorageVolumeCallback());
try {
mStorageManager.registerListener(delegate);
} catch (RemoteException e) {
@@ -548,7 +526,76 @@ public class StorageManager {
synchronized (mDelegates) {
for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
final StorageEventListenerDelegate delegate = i.next();
- if (delegate.mCallback == listener) {
+ if (delegate.mListener == listener) {
+ try {
+ mStorageManager.unregisterListener(delegate);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ i.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * Callback that delivers {@link StorageVolume} related events.
+ * <p>
+ * For example, this can be used to detect when a volume changes to the
+ * {@link Environment#MEDIA_MOUNTED} or {@link Environment#MEDIA_UNMOUNTED}
+ * states.
+ *
+ * @see StorageManager#registerStorageVolumeCallback
+ * @see StorageManager#unregisterStorageVolumeCallback
+ */
+ public static class StorageVolumeCallback {
+ /**
+ * Called when {@link StorageVolume#getState()} changes, such as
+ * changing to the {@link Environment#MEDIA_MOUNTED} or
+ * {@link Environment#MEDIA_UNMOUNTED} states.
+ * <p>
+ * The given argument is a snapshot in time and can be used to process
+ * events in the order they occurred, or you can call
+ * {@link StorageManager#getStorageVolumes()} to observe the latest
+ * value.
+ */
+ public void onStateChanged(@NonNull StorageVolume volume) { }
+ }
+
+ /**
+ * Registers the given callback to listen for {@link StorageVolume} changes.
+ * <p>
+ * For example, this can be used to detect when a volume changes to the
+ * {@link Environment#MEDIA_MOUNTED} or {@link Environment#MEDIA_UNMOUNTED}
+ * states.
+ *
+ * @see StorageManager#unregisterStorageVolumeCallback
+ */
+ public void registerStorageVolumeCallback(@CallbackExecutor @NonNull Executor executor,
+ @NonNull StorageVolumeCallback callback) {
+ synchronized (mDelegates) {
+ final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(
+ executor, new StorageEventListener(), callback);
+ try {
+ mStorageManager.registerListener(delegate);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mDelegates.add(delegate);
+ }
+ }
+
+ /**
+ * Unregisters the given callback from listening for {@link StorageVolume}
+ * changes.
+ *
+ * @see StorageManager#registerStorageVolumeCallback
+ */
+ public void unregisterStorageVolumeCallback(@NonNull StorageVolumeCallback callback) {
+ synchronized (mDelegates) {
+ for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
+ final StorageEventListenerDelegate delegate = i.next();
+ if (delegate.mCallback == callback) {
try {
mStorageManager.unregisterListener(delegate);
} catch (RemoteException e) {
@@ -829,7 +876,14 @@ public class StorageManager {
*/
public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
Preconditions.checkNotNull(path);
- final String pathString = path.getCanonicalPath();
+ String pathString = path.getCanonicalPath();
+ if (path.getPath().startsWith("/sdcard")) {
+ // On FUSE enabled devices, realpath(2) /sdcard is /mnt/user/<userid>/emulated/<userid>
+ // as opposed to /storage/emulated/<userid>.
+ // And vol.path below expects to match with a path starting with /storage
+ pathString = pathString.replaceFirst("^/mnt/user/[0-9]+/", "/storage/");
+ }
+
if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) {
return UUID_DEFAULT;
}
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 2ab226f81bb4..e251f8072b1f 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -18,6 +18,7 @@ package android.os.storage;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -162,9 +163,13 @@ public final class StorageVolume implements Parcelable {
mState = in.readString();
}
- /** {@hide} */
- @UnsupportedAppUsage
- public String getId() {
+ /**
+ * Return an opaque ID that can be used to identify this volume.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull String getId() {
return mId;
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 0a3c333ae7b1..ef8a2860cf4f 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -553,7 +553,9 @@ public final class DocumentsContract {
/**
* Flag indicating that a document is a directory that wants to block itself
* from being selected when the user launches an {@link Intent#ACTION_OPEN_DOCUMENT_TREE}
- * intent. Only valid when {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}.
+ * intent. Individual files can still be selected when launched via other intents
+ * like {@link Intent#ACTION_OPEN_DOCUMENT} and {@link Intent#ACTION_GET_CONTENT}.
+ * Only valid when {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}.
* <p>
* Note that this flag <em>only</em> applies to the single directory to which it is
* applied. It does <em>not</em> block the user from selecting either a parent or
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bbaf94ad6ea0..06805238e6f5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -68,7 +68,6 @@ import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.speech.tts.TextToSpeech;
-import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.AndroidException;
import android.util.ArrayMap;
@@ -219,7 +218,9 @@ public final class Settings {
* @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_TETHER_PROVISIONING =
+ @SystemApi
+ @TestApi
+ public static final String ACTION_TETHER_PROVISIONING_UI =
"android.settings.TETHER_PROVISIONING_UI";
/**
@@ -9698,6 +9699,8 @@ public final class Settings {
* is interpreted as |false|.
* @hide
*/
+ @SystemApi
+ @TestApi
public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled";
/**
@@ -12459,16 +12462,17 @@ public final class Settings {
/**
* Whether the Volte is enabled. If this setting is not set then we use the Carrier Config
- * value {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
+ * value
+ * {@link android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
* <p>
* Type: int (0 for false, 1 for true)
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#ENHANCED_4G_MODE_ENABLED}
* instead.
*/
@Deprecated
public static final String ENHANCED_4G_MODE_ENABLED =
- SubscriptionManager.ENHANCED_4G_MODE_ENABLED;
+ Telephony.SimInfo.ENHANCED_4G_MODE_ENABLED;
/**
* Whether VT (Video Telephony over IMS) is enabled
@@ -12476,10 +12480,10 @@ public final class Settings {
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#VT_IMS_ENABLED} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#VT_IMS_ENABLED} instead.
*/
@Deprecated
- public static final String VT_IMS_ENABLED = SubscriptionManager.VT_IMS_ENABLED;
+ public static final String VT_IMS_ENABLED = Telephony.SimInfo.VT_IMS_ENABLED;
/**
* Whether WFC is enabled
@@ -12487,10 +12491,10 @@ public final class Settings {
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ENABLED} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ENABLED} instead.
*/
@Deprecated
- public static final String WFC_IMS_ENABLED = SubscriptionManager.WFC_IMS_ENABLED;
+ public static final String WFC_IMS_ENABLED = Telephony.SimInfo.WFC_IMS_ENABLED;
/**
* WFC mode on home/non-roaming network.
@@ -12498,10 +12502,10 @@ public final class Settings {
* Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_MODE} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_MODE} instead.
*/
@Deprecated
- public static final String WFC_IMS_MODE = SubscriptionManager.WFC_IMS_MODE;
+ public static final String WFC_IMS_MODE = Telephony.SimInfo.WFC_IMS_MODE;
/**
* WFC mode on roaming network.
@@ -12509,11 +12513,11 @@ public final class Settings {
* Type: int - see {@link #WFC_IMS_MODE} for values
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_MODE}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ROAMING_MODE}
* instead.
*/
@Deprecated
- public static final String WFC_IMS_ROAMING_MODE = SubscriptionManager.WFC_IMS_ROAMING_MODE;
+ public static final String WFC_IMS_ROAMING_MODE = Telephony.SimInfo.WFC_IMS_ROAMING_MODE;
/**
* Whether WFC roaming is enabled
@@ -12521,12 +12525,12 @@ public final class Settings {
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_ENABLED}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ROAMING_ENABLED}
* instead
*/
@Deprecated
public static final String WFC_IMS_ROAMING_ENABLED =
- SubscriptionManager.WFC_IMS_ROAMING_ENABLED;
+ Telephony.SimInfo.WFC_IMS_ROAMING_ENABLED;
/**
* Whether user can enable/disable LTE as a preferred network. A carrier might control
@@ -14400,6 +14404,42 @@ public final class Settings {
};
/**
+ * Activity Action: Show screen for controlling which apps have access to manage external
+ * storage.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
+ * <p>
+ * If you want to control a specific app's access to manage external storage, use
+ * {@link #ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION} instead.
+ * <p>
+ * Output: Nothing.
+ * @see #ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION =
+ "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION";
+
+ /**
+ * Activity Action: Show screen for controlling if the app specified in the data URI of the
+ * intent can manage external storage.
+ * <p>
+ * Launching the corresponding activity requires the permission
+ * {@link Manifest.permission#MANAGE_EXTERNAL_STORAGE}.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
+ * <p>
+ * Input: The Intent's data URI MUST specify the application package name whose ability of
+ * managing external storage you want to control.
+ * For example "package:com.my.app".
+ * <p>
+ * Output: Nothing.
+ * @see #ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION =
+ "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
+
+ /**
* Performs a strict and comprehensive check of whether a calling package is allowed to
* write/modify system settings, as the condition differs for pre-M, M+, and
* privileged/preinstalled apps. If the provided uid does not match the
@@ -14425,8 +14465,9 @@ public final class Settings {
* current time.
* @hide
*/
- public static boolean checkAndNoteWriteSettingsOperation(Context context, int uid,
- String callingPackage, boolean throwException) {
+ @SystemApi
+ public static boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid,
+ @NonNull String callingPackage, boolean throwException) {
return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid,
callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS,
PM_WRITE_SETTINGS, true);
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 1d9bdb81a05f..2e7ac3f505fa 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -38,11 +38,13 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
+import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SmsMessage;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.UiccAccessRule;
import android.text.TextUtils;
import android.util.Patterns;
@@ -4980,5 +4982,402 @@ public final class Telephony {
*/
@NonNull
public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+ /**
+ * TelephonyProvider unique key column name is the subscription id.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+
+ /**
+ * TelephonyProvider column name for a unique identifier for the subscription within the
+ * specific subscription type. For example, it contains SIM ICC Identifier subscriptions
+ * on Local SIMs. and Mac-address for Remote-SIM Subscriptions for Bluetooth devices.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String ICC_ID = "icc_id";
+
+ /**
+ * TelephonyProvider column name for user SIM_SlOT_INDEX
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String SIM_SLOT_INDEX = "sim_id";
+
+ /**
+ * SIM is not inserted
+ */
+ public static final int SIM_NOT_INSERTED = -1;
+
+ /**
+ * TelephonyProvider column name Subscription-type.
+ * <P>Type: INTEGER (int)</P> {@link #SUBSCRIPTION_TYPE_LOCAL_SIM} for Local-SIM
+ * Subscriptions, {@link #SUBSCRIPTION_TYPE_REMOTE_SIM} for Remote-SIM Subscriptions.
+ * Default value is 0.
+ */
+ public static final String SUBSCRIPTION_TYPE = "subscription_type";
+
+ /**
+ * This constant is to designate a subscription as a Local-SIM Subscription.
+ * <p> A Local-SIM can be a physical SIM inserted into a sim-slot in the device, or eSIM on
+ * the device.
+ * </p>
+ */
+ public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+
+ /**
+ * This constant is to designate a subscription as a Remote-SIM Subscription.
+ * <p>
+ * A Remote-SIM subscription is for a SIM on a phone connected to this device via some
+ * connectivity mechanism, for example bluetooth. Similar to Local SIM, this subscription
+ * can be used for SMS, Voice and data by proxying data through the connected device.
+ * Certain data of the SIM, such as IMEI, are not accessible for Remote SIMs.
+ * </p>
+ *
+ * <p>
+ * A Remote-SIM is available only as long the phone stays connected to this device.
+ * When the phone disconnects, Remote-SIM subscription is removed from this device and is
+ * no longer known. All data associated with the subscription, such as stored SMS, call
+ * logs, contacts etc, are removed from this device.
+ * </p>
+ *
+ * <p>
+ * If the phone re-connects to this device, a new Remote-SIM subscription is created for
+ * the phone. The Subscription Id associated with the new subscription is different from
+ * the Subscription Id of the previous Remote-SIM subscription created (and removed) for the
+ * phone; i.e., new Remote-SIM subscription treats the reconnected phone as a Remote-SIM
+ * that was never seen before.
+ * </p>
+ */
+ public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
+
+ /**
+ * TelephonyProvider column name data_enabled_override_rules.
+ * It's a list of rules for overriding data enabled settings. The syntax is
+ * For example, "mms=nonDefault" indicates enabling data for mms in non-default
+ * subscription.
+ * "default=nonDefault&inVoiceCall" indicates enabling data for internet in non-default
+ * subscription and while is in voice call.
+ *
+ * Default value is empty string.
+ */
+ public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+
+ /**
+ * TelephonyProvider column name for user displayed name.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String DISPLAY_NAME = "display_name";
+
+ /**
+ * TelephonyProvider column name for the service provider name for the SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String CARRIER_NAME = "carrier_name";
+
+ /**
+ * TelephonyProvider column name for source of the user displayed name.
+ * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below
+ */
+ public static final String NAME_SOURCE = "name_source";
+
+ /** The name_source is the default, which is from the carrier id. */
+ public static final int NAME_SOURCE_DEFAULT = 0;
+
+ /**
+ * The name_source is from SIM EF_SPN.
+ */
+ public static final int NAME_SOURCE_SIM_SPN = 1;
+
+ /**
+ * The name_source is from user input
+ */
+ public static final int NAME_SOURCE_USER_INPUT = 2;
+
+ /**
+ * The name_source is carrier (carrier app, carrier config, etc.)
+ */
+ public static final int NAME_SOURCE_CARRIER = 3;
+
+ /**
+ * The name_source is from SIM EF_PNN.
+ */
+ public static final int NAME_SOURCE_SIM_PNN = 4;
+
+ /**
+ * TelephonyProvider column name for the color of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String COLOR = "color";
+
+ /** TelephonyProvider column name for the default color of a SIM {@hide} */
+ public static final int COLOR_DEFAULT = 0;
+
+ /**
+ * TelephonyProvider column name for the phone number of a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String NUMBER = "number";
+
+ /**
+ * TelephonyProvider column name for the number display format of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ * @hide
+ */
+ public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
+
+ /**
+ * TelephonyProvider column name for the default display format of a SIM
+ * @hide
+ */
+ public static final int DISPLAY_NUMBER_DEFAULT = 1;
+
+ /**
+ * TelephonyProvider column name for whether data roaming is enabled.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String DATA_ROAMING = "data_roaming";
+
+ /** Indicates that data roaming is enabled for a subscription */
+ public static final int DATA_ROAMING_ENABLE = 1;
+
+ /** Indicates that data roaming is disabled for a subscription */
+ public static final int DATA_ROAMING_DISABLE = 0;
+
+ /** TelephonyProvider column name for default data roaming setting: disable */
+ public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+
+ /**
+ * TelephonyProvider column name for subscription carrier id.
+ * @see TelephonyManager#getSimCarrierId()
+ * <p>Type: INTEGER (int) </p>
+ */
+ public static final String CARRIER_ID = "carrier_id";
+
+ /**
+ * A comma-separated list of EHPLMNs associated with the subscription
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String EHPLMNS = "ehplmns";
+
+ /**
+ * A comma-separated list of HPLMNs associated with the subscription
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String HPLMNS = "hplmns";
+
+ /**
+ * TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String MCC_STRING = "mcc_string";
+
+ /**
+ * TelephonyProvider column name for the MNC associated with a SIM, stored as a string.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String MNC_STRING = "mnc_string";
+
+ /**
+ * TelephonyProvider column name for the MCC associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String MCC = "mcc";
+
+ /**
+ * TelephonyProvider column name for the MNC associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String MNC = "mnc";
+
+ /**
+ * TelephonyProvider column name for the iso country code associated with a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String ISO_COUNTRY_CODE = "iso_country_code";
+
+ /**
+ * TelephonyProvider column name for the sim provisioning status associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ * @hide
+ */
+ public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
+
+ /** The sim is provisioned {@hide} */
+ public static final int SIM_PROVISIONED = 0;
+
+ /**
+ * TelephonyProvider column name for whether a subscription is embedded (that is, present on
+ * an eSIM).
+ * <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
+ */
+ public static final String IS_EMBEDDED = "is_embedded";
+
+ /**
+ * TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of
+ * the current enabled profile on the card, while for eUICC card it is the EID of the card.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String CARD_ID = "card_id";
+
+ /**
+ * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+ * {@link UiccAccessRule#encodeRules}. Only present if {@link #IS_EMBEDDED} is 1.
+ * <p>TYPE: BLOB
+ */
+ public static final String ACCESS_RULES = "access_rules";
+
+ /**
+ * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+ * {@link UiccAccessRule#encodeRules} but for the rules that come from CarrierConfigs.
+ * Only present if there are access rules in CarrierConfigs
+ * <p>TYPE: BLOB
+ */
+ public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
+ "access_rules_from_carrier_configs";
+
+ /**
+ * TelephonyProvider column name identifying whether an embedded subscription is on a
+ * removable card. Such subscriptions are marked inaccessible as soon as the current card
+ * is removed. Otherwise, they will remain accessible unless explicitly deleted. Only
+ * present if {@link #IS_EMBEDDED} is 1.
+ * <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
+ */
+ public static final String IS_REMOVABLE = "is_removable";
+
+ /** TelephonyProvider column name for extreme threat in CB settings */
+ public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+
+ /** TelephonyProvider column name for severe threat in CB settings */
+ public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+
+ /** TelephonyProvider column name for amber alert in CB settings */
+ public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+
+ /** TelephonyProvider column name for emergency alert in CB settings */
+ public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+
+ /** TelephonyProvider column name for alert sound duration in CB settings */
+ public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+
+ /** TelephonyProvider column name for alert reminder interval in CB settings */
+ public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+
+ /** TelephonyProvider column name for enabling vibrate in CB settings */
+ public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+
+ /** TelephonyProvider column name for enabling alert speech in CB settings */
+ public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+
+ /** TelephonyProvider column name for ETWS test alert in CB settings */
+ public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+
+ /** TelephonyProvider column name for enable channel50 alert in CB settings */
+ public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+
+ /** TelephonyProvider column name for CMAS test alert in CB settings */
+ public static final String CB_CMAS_TEST_ALERT = "enable_cmas_test_alerts";
+
+ /** TelephonyProvider column name for Opt out dialog in CB settings */
+ public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+
+ /**
+ * TelephonyProvider column name for enable Volte.
+ *
+ * If this setting is not initialized (set to -1) then we use the Carrier Config value
+ * {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
+ */
+ public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+
+ /** TelephonyProvider column name for enable VT (Video Telephony over IMS) */
+ public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+
+ /** TelephonyProvider column name for enable Wifi calling */
+ public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+
+ /** TelephonyProvider column name for Wifi calling mode */
+ public static final String WFC_IMS_MODE = "wfc_ims_mode";
+
+ /** TelephonyProvider column name for Wifi calling mode in roaming */
+ public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+
+ /** TelephonyProvider column name for enable Wifi calling in roaming */
+ public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+
+ /**
+ * TelephonyProvider column name for whether a subscription is opportunistic, that is,
+ * whether the network it connects to is limited in functionality or coverage.
+ * For example, CBRS.
+ * <p>Type: INTEGER (int), 1 for opportunistic or 0 for non-opportunistic.
+ */
+ public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+
+ /**
+ * TelephonyProvider column name for group ID. Subscriptions with same group ID
+ * are considered bundled together, and should behave as a single subscription at
+ * certain scenarios.
+ */
+ public static final String GROUP_UUID = "group_uuid";
+
+ /**
+ * TelephonyProvider column name for group owner. It's the package name who created
+ * the subscription group.
+ */
+ public static final String GROUP_OWNER = "group_owner";
+
+ /**
+ * TelephonyProvider column name for whether a subscription is metered or not, that is,
+ * whether the network it connects to charges for subscription or not. For example, paid
+ * CBRS or unpaid.
+ * @hide
+ */
+ public static final String IS_METERED = "is_metered";
+
+ /**
+ * TelephonyProvider column name for the profile class of a subscription
+ * Only present if {@link #IS_EMBEDDED} is 1.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String PROFILE_CLASS = "profile_class";
+
+ /**
+ * A testing profile can be pre-loaded or downloaded onto
+ * the eUICC and provides connectivity to test equipment
+ * for the purpose of testing the device and the eUICC. It
+ * is not intended to store any operator credentials.
+ */
+ public static final int PROFILE_CLASS_TESTING = 0;
+
+ /**
+ * A provisioning profile is pre-loaded onto the eUICC and
+ * provides connectivity to a mobile network solely for the
+ * purpose of provisioning profiles.
+ */
+ public static final int PROFILE_CLASS_PROVISIONING = 1;
+
+ /**
+ * An operational profile can be pre-loaded or downloaded
+ * onto the eUICC and provides services provided by the
+ * operator.
+ */
+ public static final int PROFILE_CLASS_OPERATIONAL = 2;
+
+ /**
+ * The profile class is unset. This occurs when profile class
+ * info is not available. The subscription either has no profile
+ * metadata or the profile metadata did not encode profile class.
+ */
+ public static final int PROFILE_CLASS_UNSET = -1;
+
+ /** Default profile class */
+ public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+
+ /**
+ * IMSI (International Mobile Subscriber Identity).
+ * <P>Type: TEXT </P>
+ */
+ public static final String IMSI = "imsi";
+
+ /** Whether uicc applications is set to be enabled or disabled. By default it's enabled. */
+ public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
}
}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index d51e4ca6398f..939ae878816a 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -609,10 +609,12 @@ public final class FillResponse implements Parcelable {
"must add at least 1 dataset when using header or footer");
}
- for (final Dataset dataset : mDatasets) {
- if (dataset.getFieldInlinePresentation(0) != null) {
- mSupportsInlineSuggestions = true;
- break;
+ if (mDatasets != null) {
+ for (final Dataset dataset : mDatasets) {
+ if (dataset.getFieldInlinePresentation(0) != null) {
+ mSupportsInlineSuggestions = true;
+ break;
+ }
}
}
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 67925bfea2c2..d7c6d0f265c6 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -168,6 +168,22 @@ public class AlwaysOnHotwordDetector {
public static final int RECOGNITION_MODE_USER_IDENTIFICATION
= SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "MODEL_PARAM_" }, value = {
+ MODEL_PARAM_THRESHOLD_FACTOR,
+ })
+ public @interface ModelParams {}
+
+ /**
+ * Controls the sensitivity threshold adjustment factor for a given model.
+ * Negative value corresponds to less sensitive model (high threshold) and
+ * a positive value corresponds to a more sensitive model (low threshold).
+ * Default value is 0.
+ */
+ public static final int MODEL_PARAM_THRESHOLD_FACTOR =
+ android.hardware.soundtrigger.ModelParams.THRESHOLD_FACTOR;
+
static final String TAG = "AlwaysOnHotwordDetector";
static final boolean DBG = false;
@@ -198,6 +214,53 @@ public class AlwaysOnHotwordDetector {
private int mAvailability = STATE_NOT_READY;
/**
+ * A ModelParamRange is a representation of supported parameter range for a
+ * given loaded model.
+ */
+ public static final class ModelParamRange {
+ private final SoundTrigger.ModelParamRange mModelParamRange;
+
+ /** @hide */
+ ModelParamRange(SoundTrigger.ModelParamRange modelParamRange) {
+ mModelParamRange = modelParamRange;
+ }
+
+ /**
+ * The inclusive start of supported range.
+ *
+ * @return start of range
+ */
+ public int start() {
+ return mModelParamRange.start;
+ }
+
+ /**
+ * The inclusive end of supported range.
+ *
+ * @return end of range
+ */
+ public int end() {
+ return mModelParamRange.end;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return mModelParamRange.toString();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ return mModelParamRange.equals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return mModelParamRange.hashCode();
+ }
+ }
+
+ /**
* Additional payload for {@link Callback#onDetected}.
*/
public static class EventPayload {
@@ -445,6 +508,83 @@ public class AlwaysOnHotwordDetector {
}
/**
+ * Set a model specific {@link ModelParams} with the given value. This
+ * parameter will keep its value for the duration the model is loaded regardless of starting and
+ * stopping recognition. Once the model is unloaded, the value will be lost.
+ * {@link AlwaysOnHotwordDetector#queryParameter} should be checked first before calling this
+ * method.
+ *
+ * @param modelParam {@link ModelParams}
+ * @param value Value to set
+ * @return - {@link SoundTrigger#STATUS_OK} in case of success
+ * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
+ * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
+ * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
+ * if API is not supported by HAL
+ */
+ public int setParameter(@ModelParams int modelParam, int value) {
+ if (DBG) {
+ Slog.d(TAG, "setParameter(" + modelParam + ", " + value + ")");
+ }
+
+ synchronized (mLock) {
+ if (mAvailability == STATE_INVALID) {
+ throw new IllegalStateException("setParameter called on an invalid detector");
+ }
+
+ return setParameterLocked(modelParam, value);
+ }
+ }
+
+ /**
+ * Get a model specific {@link ModelParams}. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See {@link ModelParams} for parameter default values.
+ * {@link AlwaysOnHotwordDetector#queryParameter} should be checked first before
+ * calling this method.
+ *
+ * @param modelParam {@link ModelParams}
+ * @return value of parameter
+ */
+ public int getParameter(@ModelParams int modelParam) {
+ if (DBG) {
+ Slog.d(TAG, "getParameter(" + modelParam + ")");
+ }
+
+ synchronized (mLock) {
+ if (mAvailability == STATE_INVALID) {
+ throw new IllegalStateException("getParameter called on an invalid detector");
+ }
+
+ return getParameterLocked(modelParam);
+ }
+ }
+
+ /**
+ * Determine if parameter control is supported for the given model handle.
+ * This method should be checked prior to calling {@link AlwaysOnHotwordDetector#setParameter}
+ * or {@link AlwaysOnHotwordDetector#getParameter}.
+ *
+ * @param modelParam {@link ModelParams}
+ * @return supported range of parameter, null if not supported
+ */
+ @Nullable
+ public ModelParamRange queryParameter(@ModelParams int modelParam) {
+ if (DBG) {
+ Slog.d(TAG, "queryParameter(" + modelParam + ")");
+ }
+
+ synchronized (mLock) {
+ if (mAvailability == STATE_INVALID) {
+ throw new IllegalStateException("queryParameter called on an invalid detector");
+ }
+
+ return queryParameterLocked(modelParam);
+ }
+ }
+
+ /**
* Creates an intent to start the enrollment for the associated keyphrase.
* This intent must be invoked using {@link Context#startForegroundService(Intent)}.
* Starting re-enrollment is only valid if the keyphrase is un-enrolled,
@@ -601,6 +741,47 @@ public class AlwaysOnHotwordDetector {
return code;
}
+ private int setParameterLocked(@ModelParams int modelParam, int value) {
+ try {
+ int code = mModelManagementService.setParameter(mVoiceInteractionService,
+ mKeyphraseMetadata.id, modelParam, value);
+
+ if (code != STATUS_OK) {
+ Slog.w(TAG, "setParameter failed with error code " + code);
+ }
+
+ return code;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private int getParameterLocked(@ModelParams int modelParam) {
+ try {
+ return mModelManagementService.getParameter(mVoiceInteractionService,
+ mKeyphraseMetadata.id, modelParam);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Nullable
+ private ModelParamRange queryParameterLocked(@ModelParams int modelParam) {
+ try {
+ SoundTrigger.ModelParamRange modelParamRange =
+ mModelManagementService.queryParameter(mVoiceInteractionService,
+ mKeyphraseMetadata.id, modelParam);
+
+ if (modelParamRange == null) {
+ return null;
+ }
+
+ return new ModelParamRange(modelParamRange);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private void notifyStateChangedLocked() {
Message message = Message.obtain(mHandler, MSG_AVAILABILITY_CHANGED);
message.arg1 = mAvailability;
diff --git a/core/java/android/telephony/WapPushManagerConnector.java b/core/java/android/telephony/WapPushManagerConnector.java
new file mode 100644
index 000000000000..a9df50685d5d
--- /dev/null
+++ b/core/java/android/telephony/WapPushManagerConnector.java
@@ -0,0 +1,178 @@
+/*
+ * 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.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.telephony.IWapPushManager;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * APIs for platform to connect to the WAP push manager service.
+ *
+ * <p>To start connection, {@link #bindToWapPushManagerService} should be called.
+ *
+ * <p>Upon completion {@link #unbindWapPushManagerService} should be called to unbind the service.
+ *
+ * @hide
+ */
+@SystemApi
+public final class WapPushManagerConnector {
+ private final Context mContext;
+
+ private volatile WapPushManagerConnection mConnection;
+ private volatile IWapPushManager mWapPushManager;
+ private String mWapPushManagerPackage;
+
+ /**
+ * The {@link android.content.Intent} that must be declared as handled by the
+ * WAP push manager service.
+ * @hide
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE =
+ "com.android.internal.telephony.IWapPushManager";
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"RESULT_"}, value = {
+ RESULT_MESSAGE_HANDLED,
+ RESULT_APP_QUERY_FAILED,
+ RESULT_SIGNATURE_NO_MATCH,
+ RESULT_INVALID_RECEIVER_NAME,
+ RESULT_EXCEPTION_CAUGHT,
+ RESULT_FURTHER_PROCESSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProcessMessageResult{}
+
+ /** {@link #processMessage} return value: Message is handled. */
+ public static final int RESULT_MESSAGE_HANDLED = 0x1;
+ /** {@link #processMessage} return value: Application ID or content type was not found. */
+ public static final int RESULT_APP_QUERY_FAILED = 0x2;
+ /** {@link #processMessage} return value: Receiver application signature check failed. */
+ public static final int RESULT_SIGNATURE_NO_MATCH = 0x4;
+ /** {@link #processMessage} return value: Receiver application was not found. */
+ public static final int RESULT_INVALID_RECEIVER_NAME = 0x8;
+ /** {@link #processMessage} return value: Unknown exception. */
+ public static final int RESULT_EXCEPTION_CAUGHT = 0x10;
+ /** {@link #processMessage} return value: further processing needed. */
+ public static final int RESULT_FURTHER_PROCESSING = 0x8000;
+
+ /** The application package name of the WAP push manager service. */
+ private static final String SERVICE_PACKAGE = "com.android.smspush";
+
+ public WapPushManagerConnector(@NonNull Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Binds to the WAP push manager service. This method should be called exactly once.
+ *
+ * @return {@code true} upon successfully binding to a service, {@code false} otherwise
+ */
+ public boolean bindToWapPushManagerService() {
+ Preconditions.checkState(mConnection == null);
+
+ Intent intent = new Intent(SERVICE_INTERFACE);
+ ComponentName component = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(component);
+ mConnection = new WapPushManagerConnection();
+ if (component != null
+ && mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ mWapPushManagerPackage = component.getPackageName();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the package name of WAP push manager service application connected to,
+ * or {@code null} if not connected.
+ */
+ @Nullable
+ public String getConnectedWapPushManagerServicePackage() {
+ return mWapPushManagerPackage;
+ }
+
+ /**
+ * Processes WAP push message and triggers the {@code intent}.
+ *
+ * @see RESULT_MESSAGE_HANDLED
+ * @see RESULT_APP_QUERY_FAILED
+ * @see RESULT_SIGNATURE_NO_MATCH
+ * @see RESULT_INVALID_RECEIVER_NAME
+ * @see RESULT_EXCEPTION_CAUGHT
+ * @see RESULT_FURTHER_PROCESSING
+ */
+ @ProcessMessageResult
+ public int processMessage(
+ @NonNull String applicationId, @NonNull String contentType, @NonNull Intent intent) {
+ try {
+ return mWapPushManager.processMessage(applicationId, contentType, intent);
+ } catch (NullPointerException | RemoteException e) {
+ return RESULT_EXCEPTION_CAUGHT;
+ }
+ }
+
+ /**
+ * Unbinds the WAP push manager service. This method should be called exactly once.
+ */
+ public void unbindWapPushManagerService() {
+ Preconditions.checkNotNull(mConnection);
+
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ }
+
+ private class WapPushManagerConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ // Because we have bound to an explicit
+ // service that is running in our own process, we can
+ // cast its IBinder to a concrete class and directly access it.
+ mWapPushManager = IWapPushManager.Stub.asInterface(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mWapPushManager = null;
+ }
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ onServiceDisconnected(name);
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ onServiceDisconnected(name);
+ }
+ }
+}
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index b85ef76bd2d5..4c9328a1c372 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -40,9 +40,10 @@ import java.lang.reflect.Array;
if (source instanceof Spanned) {
if (source instanceof SpannableStringInternal) {
- copySpans((SpannableStringInternal) source, start, end, ignoreNoCopySpan);
+ copySpansFromInternal(
+ (SpannableStringInternal) source, start, end, ignoreNoCopySpan);
} else {
- copySpans((Spanned) source, start, end, ignoreNoCopySpan);
+ copySpansFromSpanned((Spanned) source, start, end, ignoreNoCopySpan);
}
}
}
@@ -65,7 +66,7 @@ import java.lang.reflect.Array;
* @param end End index in the source object.
* @param ignoreNoCopySpan whether to copy NoCopySpans in the {@code source}
*/
- private void copySpans(Spanned src, int start, int end, boolean ignoreNoCopySpan) {
+ private void copySpansFromSpanned(Spanned src, int start, int end, boolean ignoreNoCopySpan) {
Object[] spans = src.getSpans(start, end, Object.class);
for (int i = 0; i < spans.length; i++) {
@@ -94,7 +95,7 @@ import java.lang.reflect.Array;
* @param end End index in the source object.
* @param ignoreNoCopySpan copy NoCopySpan for backward compatible reasons.
*/
- private void copySpans(SpannableStringInternal src, int start, int end,
+ private void copySpansFromInternal(SpannableStringInternal src, int start, int end,
boolean ignoreNoCopySpan) {
int count = 0;
final int[] srcData = src.mSpanData;
@@ -555,12 +556,12 @@ import java.lang.reflect.Array;
*/
@UnsupportedAppUsage
private void copySpans(Spanned src, int start, int end) {
- copySpans(src, start, end, false);
+ copySpansFromSpanned(src, start, end, false);
}
@UnsupportedAppUsage
private void copySpans(SpannableStringInternal src, int start, int end) {
- copySpans(src, start, end, false);
+ copySpansFromInternal(src, start, end, false);
}
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 3f679bba88cd..f324113da925 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -387,6 +387,26 @@ public final class Log {
public static native int println_native(int bufID, int priority, String tag, String msg);
/**
+ * Send a log message to the "radio" log buffer, which can be dumped with
+ * {@code adb logcat -b radio}.
+ *
+ * <p>Only the telephony mainline module should use it.
+ *
+ * <p>Note ART will protect {@code MODULE_LIBRARIES} system APIs from regular app code.
+ *
+ * @param priority Log priority.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param message The message you would like logged.
+ * @hide
+ */
+ // @SystemApi(client= SystemApi.Client.MODULE_LIBRARIES) // TODO Uncomment once http://ag/9956147 is in.
+ public static int logToRadioBuffer(@Level int priority, @Nullable String tag,
+ @Nullable String message) {
+ return println_native(LOG_ID_RADIO, priority, tag, message);
+ }
+
+ /**
* Return the maximum payload the log daemon accepts without truncation.
* @return LOGGER_ENTRY_MAX_PAYLOAD.
*/
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 2223d14ad658..fa994ba76fd7 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -25,6 +25,7 @@ import android.net.Network;
import android.net.NetworkInfo;
import android.net.SntpClient;
import android.os.SystemClock;
+import android.os.TimestampedValue;
import android.provider.Settings;
import android.text.TextUtils;
diff --git a/core/java/android/view/IDisplayWindowInsetsController.aidl b/core/java/android/view/IDisplayWindowInsetsController.aidl
new file mode 100644
index 000000000000..429c3aeba9b3
--- /dev/null
+++ b/core/java/android/view/IDisplayWindowInsetsController.aidl
@@ -0,0 +1,48 @@
+/**
+ * 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.view;
+
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+
+/**
+ * Singular controller of insets to use when there isn't another obvious controller available.
+ * Specifically, this will take over insets control in multi-window.
+ * @hide
+ */
+oneway interface IDisplayWindowInsetsController {
+
+ /**
+ * @see IWindow#insetsChanged
+ */
+ void insetsChanged(in InsetsState insetsState);
+
+ /**
+ * @see IWindow#insetsControlChanged
+ */
+ void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls);
+
+ /**
+ * @see IWindow#showInsets
+ */
+ void showInsets(int types, boolean fromIme);
+
+ /**
+ * @see IWindow#hideInsets
+ */
+ void hideInsets(int types, boolean fromIme);
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9496827b1a84..993bdc4d6543 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -35,6 +35,7 @@ import android.os.ParcelFileDescriptor;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
+import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
import android.view.IDisplayFoldListener;
import android.view.IDisplayWindowRotationController;
@@ -49,6 +50,7 @@ import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.KeyEvent;
import android.view.InputEvent;
+import android.view.InsetsState;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
import android.view.InputChannel;
@@ -711,4 +713,16 @@ interface IWindowManager
* @return true if the display was successfully mirrored.
*/
boolean mirrorDisplay(int displayId, out SurfaceControl outSurfaceControl);
+
+ /**
+ * When in multi-window mode, the provided displayWindowInsetsController will control insets
+ * animations.
+ */
+ void setDisplayWindowInsetsController(
+ int displayId, in IDisplayWindowInsetsController displayWindowInsetsController);
+
+ /**
+ * Called when a remote process modifies insets on a display window container.
+ */
+ void modifyDisplayWindowInsets(int displayId, in InsetsState state);
}
diff --git a/core/java/android/view/InsetsAnimationControlCallbacks.java b/core/java/android/view/InsetsAnimationControlCallbacks.java
index 6fdadc60afea..27edb0b69bdd 100644
--- a/core/java/android/view/InsetsAnimationControlCallbacks.java
+++ b/core/java/android/view/InsetsAnimationControlCallbacks.java
@@ -16,17 +16,28 @@
package android.view;
+import android.view.InsetsController.LayoutInsetsDuringAnimation;
+import android.view.WindowInsetsAnimationCallback.AnimationBounds;
+import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
+
/**
* Provide an interface to let InsetsAnimationControlImpl call back into its owner.
* @hide
*/
public interface InsetsAnimationControlCallbacks {
+
/**
- * Dispatch the animation started event to all listeners.
- * @param animation
+ * Executes the necessary code to start the animation in the correct order, including:
+ * <ul>
+ * <li>Dispatch {@link WindowInsetsAnimationCallback#onPrepare}</li>
+ * <li>Update insets state and run layout according to {@code layoutDuringAnimation}</li>
+ * <li>Dispatch {@link WindowInsetsAnimationCallback#onStart}</li>
+ * <li>Dispatch {@link WindowInsetsAnimationControlListener#onReady}</li>
+ * </ul>
*/
- void dispatchAnimationStarted(WindowInsetsAnimationCallback.InsetsAnimation animation,
- WindowInsetsAnimationCallback.AnimationBounds bounds);
+ void startAnimation(InsetsAnimationControlImpl controller,
+ WindowInsetsAnimationControlListener listener, int types, InsetsAnimation animation,
+ AnimationBounds bounds, @LayoutInsetsDuringAnimation int layoutDuringAnimation);
/**
* Schedule the apply by posting the animation callback.
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 771695c2b873..6589e75c7bc2 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsState.ISIDE_BOTTOM;
import static android.view.InsetsState.ISIDE_FLOATING;
import static android.view.InsetsState.ISIDE_LEFT;
@@ -30,6 +32,7 @@ import android.util.ArraySet;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.SparseSetArray;
+import android.view.InsetsController.LayoutInsetsDuringAnimation;
import android.view.InsetsState.InternalInsetsSide;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowInsets.Type.InsetsType;
@@ -80,7 +83,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls, Rect frame,
InsetsState state, WindowInsetsAnimationControlListener listener,
@InsetsType int types,
- InsetsAnimationControlCallbacks controller, long durationMs, boolean fade) {
+ InsetsAnimationControlCallbacks controller, long durationMs, boolean fade,
+ @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
mControls = controls;
mListener = listener;
mTypes = types;
@@ -95,14 +99,11 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
mFrame = new Rect(frame);
buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mControls);
- // TODO: Check for controllability first and wait for IME if needed.
- listener.onReady(this, types);
-
mAnimation = new WindowInsetsAnimationCallback.InsetsAnimation(mTypes,
InsetsController.INTERPOLATOR, durationMs);
mAnimation.setAlpha(getCurrentAlpha());
- mController.dispatchAnimationStarted(mAnimation,
- new AnimationBounds(mHiddenInsets, mShownInsets));
+ mController.startAnimation(this, listener, types, mAnimation,
+ new AnimationBounds(mHiddenInsets, mShownInsets), layoutInsetsDuringAnimation);
}
@Override
@@ -257,10 +258,6 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
for (int i = items.size() - 1; i >= 0; i--) {
final InsetsSourceControl control = items.valueAt(i);
final InsetsSource source = mInitialInsetsState.getSource(control.getType());
- if (control == null) {
- // TODO: remove this check when we ensure the elements will not be null.
- continue;
- }
final SurfaceControl leash = control.getLeash();
mTmpMatrix.setTranslate(control.getSurfacePosition().x, control.getSurfacePosition().y);
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 4d4ace27cac9..0207abdda355 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -37,6 +37,7 @@ import android.util.SparseArray;
import android.view.InsetsSourceConsumer.ShowResult;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
+import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
@@ -47,6 +48,8 @@ import android.view.animation.PathInterpolator;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
/**
@@ -67,6 +70,37 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private @interface AnimationDirection{}
/**
+ * Layout mode during insets animation: The views should be laid out as if the changing inset
+ * types are fully shown. Before starting the animation, {@link View#onApplyWindowInsets} will
+ * be called as if the changing insets types are shown, which will result in the views being
+ * laid out as if the insets are fully shown.
+ */
+ static final int LAYOUT_INSETS_DURING_ANIMATION_SHOWN = 0;
+
+ /**
+ * Layout mode during insets animation: The views should be laid out as if the changing inset
+ * types are fully hidden. Before starting the animation, {@link View#onApplyWindowInsets} will
+ * be called as if the changing insets types are hidden, which will result in the views being
+ * laid out as if the insets are fully hidden.
+ */
+ static final int LAYOUT_INSETS_DURING_ANIMATION_HIDDEN = 1;
+
+ /**
+ * Determines the behavior of how the views should be laid out during an insets animation that
+ * is controlled by the application by calling {@link #controlWindowInsetsAnimation}.
+ * <p>
+ * When the animation is system-initiated, the layout mode is always chosen such that the
+ * pre-animation layout will represent the opposite of the starting state, i.e. when insets
+ * are appearing, {@link #LAYOUT_INSETS_DURING_ANIMATION_SHOWN} will be used. When insets
+ * are disappearing, {@link #LAYOUT_INSETS_DURING_ANIMATION_HIDDEN} will be used.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {LAYOUT_INSETS_DURING_ANIMATION_SHOWN,
+ LAYOUT_INSETS_DURING_ANIMATION_HIDDEN})
+ @interface LayoutInsetsDuringAnimation {
+ }
+
+ /**
* Translation animation evaluator.
*/
private static TypeEvaluator<Insets> sEvaluator = (fraction, startValue, endValue) -> Insets.of(
@@ -109,11 +143,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@Override
public void onReady(WindowInsetsAnimationController controller, int types) {
mController = controller;
- if (mShow) {
- showDirectly(types);
- } else {
- hideDirectly(types);
- }
+
mAnimationDirection = mShow ? DIRECTION_SHOW : DIRECTION_HIDE;
mAnimator = ObjectAnimator.ofObject(
controller,
@@ -131,7 +161,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
onAnimationFinish();
}
});
+ mStartingAnimation = true;
mAnimator.start();
+ mStartingAnimation = false;
}
@Override
@@ -185,6 +217,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private int mPendingTypesToShow;
private int mLastLegacySoftInputMode;
+ private boolean mStartingAnimation;
private SyncRtSurfaceTransactionApplier mApplier;
@@ -312,7 +345,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// Only one animator (with multiple InsetsType) can run at a time.
// previous one should be cancelled for simplicity.
cancelExistingAnimation();
- } else if (consumer.isVisible()
+ } else if (consumer.isRequestedVisible()
&& (mAnimationDirection == DIRECTION_NONE
|| mAnimationDirection == DIRECTION_HIDE)) {
// no-op: already shown or animating in (because window visibility is
@@ -338,7 +371,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
if (mAnimationDirection == DIRECTION_SHOW) {
cancelExistingAnimation();
- } else if (!consumer.isVisible()
+ } else if (!consumer.isRequestedVisible()
&& (mAnimationDirection == DIRECTION_NONE
|| mAnimationDirection == DIRECTION_HIDE)) {
// no-op: already hidden or animating out.
@@ -363,20 +396,21 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
listener.onCancelled();
return;
}
- controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, false /* fade */);
+ controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, false /* fade */,
+ getLayoutInsetsDuringAnimationMode(types));
}
private void controlAnimationUnchecked(@InsetsType int types,
WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
- long durationMs, boolean fade) {
+ long durationMs, boolean fade,
+ @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
if (types == 0) {
// nothing to animate.
return;
}
cancelExistingControllers(types);
- final ArraySet<Integer> internalTypes = mState.toInternalType(types);
- final SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>();
+ final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
Pair<Integer, Boolean> typesReadyPair = collectSourceControls(
@@ -399,7 +433,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(controls,
- frame, mState, listener, typesReady, this, durationMs, fade);
+ frame, mState, listener, typesReady, this, durationMs, fade,
+ layoutInsetsDuringAnimation);
mAnimationControls.add(controller);
}
@@ -413,7 +448,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
boolean isReady = true;
for (int i = internalTypes.size() - 1; i >= 0; i--) {
InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
- boolean setVisible = !consumer.isVisible();
+ boolean setVisible = !consumer.isRequestedVisible();
if (setVisible) {
// Show request
switch(consumer.requestShow(fromIme)) {
@@ -441,7 +476,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
typesReady |= InsetsState.toPublicType(consumer.getType());
}
- controls.put(consumer.getType(), consumer.getControl());
+ final InsetsSourceControl control = consumer.getControl();
+ if (control != null) {
+ controls.put(consumer.getType(), control);
+ }
}
return new Pair<>(typesReady, isReady);
}
@@ -452,6 +490,29 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
return typesReady;
}
+ private @LayoutInsetsDuringAnimation int getLayoutInsetsDuringAnimationMode(
+ @InsetsType int types) {
+
+ final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
+
+ // Generally, we want to layout the opposite of the current state. This is to make animation
+ // callbacks easy to use: The can capture the layout values and then treat that as end-state
+ // during the animation.
+ //
+ // However, if controlling multiple sources, we want to treat it as shown if any of the
+ // types is currently hidden.
+ for (int i = internalTypes.size() - 1; i >= 0; i--) {
+ InsetsSourceConsumer consumer = mSourceConsumers.get(internalTypes.valueAt(i));
+ if (consumer == null) {
+ continue;
+ }
+ if (!consumer.isRequestedVisible()) {
+ return LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
+ }
+ }
+ return LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
+ }
+
private void cancelExistingControllers(@InsetsType int types) {
for (int i = mAnimationControls.size() - 1; i >= 0; i--) {
InsetsAnimationControlImpl control = mAnimationControls.get(i);
@@ -595,7 +656,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// and hidden state insets are correct.
controlAnimationUnchecked(
types, listener, mState.getDisplayFrame(), fromIme, listener.getDurationMs(),
- true /* fade */);
+ true /* fade */, show
+ ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
+ : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN);
}
private void hideDirectly(@InsetsType int types) {
@@ -627,18 +690,40 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
@Override
- public void dispatchAnimationStarted(InsetsAnimation animation, AnimationBounds bounds) {
- mViewRoot.mView.dispatchWindowInsetsAnimationStarted(animation, bounds);
+ public void startAnimation(InsetsAnimationControlImpl controller,
+ WindowInsetsAnimationControlListener listener, int types, InsetsAnimation animation,
+ AnimationBounds bounds, int layoutDuringAnimation) {
+ if (layoutDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
+ showDirectly(types);
+ } else {
+ hideDirectly(types);
+ }
+ mViewRoot.mView.dispatchWindowInsetsAnimationPrepare(animation);
+ mViewRoot.mView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ mViewRoot.mView.getViewTreeObserver().removeOnPreDrawListener(this);
+ mViewRoot.mView.dispatchWindowInsetsAnimationStart(animation, bounds);
+ listener.onReady(controller, types);
+ return true;
+ }
+ });
+ mViewRoot.mView.invalidate();
}
@VisibleForTesting
public void dispatchAnimationFinished(InsetsAnimation animation) {
- mViewRoot.mView.dispatchWindowInsetsAnimationFinished(animation);
+ mViewRoot.mView.dispatchWindowInsetsAnimationFinish(animation);
}
@VisibleForTesting
@Override
public void scheduleApplyChangeInsets() {
+ if (mStartingAnimation) {
+ mAnimCallback.run();
+ mAnimCallbackScheduled = false;
+ return;
+ }
if (!mAnimCallbackScheduled) {
mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION,
mAnimCallback, null /* token*/);
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index c6d9898a425c..b2a5d915c2a6 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -53,7 +53,7 @@ public class InsetsSourceConsumer {
}
protected final InsetsController mController;
- protected boolean mVisible;
+ protected boolean mRequestedVisible;
private final Supplier<Transaction> mTransactionSupplier;
private final @InternalInsetsType int mType;
private final InsetsState mState;
@@ -66,7 +66,7 @@ public class InsetsSourceConsumer {
mState = state;
mTransactionSupplier = transactionSupplier;
mController = controller;
- mVisible = InsetsState.getDefaultVisibility(type);
+ mRequestedVisible = InsetsState.getDefaultVisibility(type);
}
public void setControl(@Nullable InsetsSourceControl control) {
@@ -94,12 +94,12 @@ public class InsetsSourceConsumer {
@VisibleForTesting
public void show() {
- setVisible(true);
+ setRequestedVisible(true);
}
@VisibleForTesting
public void hide() {
- setVisible(false);
+ setRequestedVisible(false);
}
/**
@@ -126,16 +126,16 @@ public class InsetsSourceConsumer {
if (mSourceControl == null) {
return false;
}
- if (mState.getSource(mType).isVisible() == mVisible) {
+ if (mState.getSource(mType).isVisible() == mRequestedVisible) {
return false;
}
- mState.getSource(mType).setVisible(mVisible);
+ mState.getSource(mType).setVisible(mRequestedVisible);
return true;
}
@VisibleForTesting
- public boolean isVisible() {
- return mVisible;
+ public boolean isRequestedVisible() {
+ return mRequestedVisible;
}
/**
@@ -157,11 +157,15 @@ public class InsetsSourceConsumer {
// no-op for types that always return ShowResult#SHOW_IMMEDIATELY.
}
- private void setVisible(boolean visible) {
- if (mVisible == visible) {
+ /**
+ * Sets requested visibility from the client, regardless of whether we are able to control it at
+ * the moment.
+ */
+ private void setRequestedVisible(boolean requestedVisible) {
+ if (mRequestedVisible == requestedVisible) {
return;
}
- mVisible = visible;
+ mRequestedVisible = requestedVisible;
applyLocalVisibilityOverride();
mController.notifyVisibilityChanged();
}
@@ -173,7 +177,7 @@ public class InsetsSourceConsumer {
}
final Transaction t = mTransactionSupplier.get();
- if (mVisible) {
+ if (mRequestedVisible) {
t.show(mSourceControl.getLeash());
} else {
t.hide(mSourceControl.getLeash());
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index e3fed3a5dce3..ae1e579da8f6 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -19,10 +19,15 @@ package android.view;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+import static android.view.WindowInsets.Type.IME;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
+import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.systemBars;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -156,11 +161,10 @@ public class InsetsState implements Parcelable {
&& source.getType() != ITYPE_IME;
boolean skipSystemBars = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
&& (type == ITYPE_STATUS_BAR || type == ITYPE_NAVIGATION_BAR);
- boolean skipIme = source.getType() == ITYPE_IME
- && (legacySoftInputMode & LayoutParams.SOFT_INPUT_ADJUST_RESIZE) == 0;
boolean skipLegacyTypes = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && (toPublicType(type) & Type.compatSystemInsets()) != 0;
- if (skipSystemBars || skipIme || skipLegacyTypes || skipNonImeInImeMode) {
+ && (type == ITYPE_STATUS_BAR || type == ITYPE_NAVIGATION_BAR
+ || type == ITYPE_IME);
+ if (skipSystemBars || skipLegacyTypes || skipNonImeInImeMode) {
typeVisibilityMap[indexOf(toPublicType(type))] = source.isVisible();
continue;
}
@@ -175,8 +179,11 @@ public class InsetsState implements Parcelable {
typeMaxInsetsMap, null /* typeSideMap */, null /* typeVisibilityMap */);
}
}
+ final int softInputAdjustMode = legacySoftInputMode & SOFT_INPUT_MASK_ADJUST;
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
- alwaysConsumeSystemBars, cutout);
+ alwaysConsumeSystemBars, cutout, softInputAdjustMode == SOFT_INPUT_ADJUST_RESIZE
+ ? systemBars() | ime()
+ : systemBars());
}
private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility,
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index f6d6522f80d6..ff8455ab0915 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -677,6 +677,22 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Set the initial visibility for the SurfaceControl.
+ *
+ * @param hidden Whether the Surface is initially HIDDEN.
+ * @hide
+ */
+ @NonNull
+ public Builder setHidden(boolean hidden) {
+ if (hidden) {
+ mFlags |= HIDDEN;
+ } else {
+ mFlags &= ~HIDDEN;
+ }
+ return this;
+ }
+
+ /**
* Set a parent surface for our new SurfaceControl.
*
* Child surfaces are constrained to the onscreen region of their parent.
@@ -789,8 +805,7 @@ public final class SurfaceControl implements Parcelable {
* @param name The surface name, must not be null.
* @param w The surface initial width.
* @param h The surface initial height.
- * @param flags The surface creation flags. Should always include {@link #HIDDEN}
- * in the creation flags.
+ * @param flags The surface creation flags.
* @param metadata Initial metadata.
* @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
*/
@@ -801,15 +816,6 @@ public final class SurfaceControl implements Parcelable {
throw new IllegalArgumentException("name must not be null");
}
- if ((flags & SurfaceControl.HIDDEN) == 0) {
- Log.w(TAG, "Surfaces should always be created with the HIDDEN flag set "
- + "to ensure that they are not made visible prematurely before "
- + "all of the surface's properties have been configured. "
- + "Set the other properties and make the surface visible within "
- + "a transaction. New surface name: " + name,
- new Throwable());
- }
-
mName = name;
mWidth = w;
mHeight = h;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 52ea2b2142ad..17825444a524 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -379,7 +379,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
* This gets called on a RenderThread worker thread, so members accessed here must
* be protected by a lock.
*/
- final boolean useBLAST = ViewRootImpl.USE_BLAST_BUFFERQUEUE;
+ final boolean useBLAST = WindowManagerGlobal.USE_BLAST_ADAPTER;
viewRoot.registerRtFrameCallback(frame -> {
try {
final SurfaceControl.Transaction t = useBLAST ?
@@ -1107,7 +1107,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
Rect position, long frameNumber) {
- if (frameNumber > 0 && ViewRootImpl.USE_BLAST_BUFFERQUEUE == false) {
+ if (frameNumber > 0 && !WindowManagerGlobal.USE_BLAST_ADAPTER) {
final ViewRootImpl viewRoot = getViewRootImpl();
t.deferTransactionUntilSurface(surface, viewRoot.mSurface,
@@ -1125,7 +1125,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
private void setParentSpaceRectangle(Rect position, long frameNumber) {
- final boolean useBLAST = ViewRootImpl.USE_BLAST_BUFFERQUEUE;
+ final boolean useBLAST = WindowManagerGlobal.USE_BLAST_ADAPTER;
final ViewRootImpl viewRoot = getViewRootImpl();
final SurfaceControl.Transaction t = useBLAST ? viewRoot.getBLASTSyncTransaction() :
mRtTransaction;
@@ -1186,7 +1186,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
@Override
public void positionLost(long frameNumber) {
- boolean useBLAST = ViewRootImpl.USE_BLAST_BUFFERQUEUE;
+ boolean useBLAST = WindowManagerGlobal.USE_BLAST_ADAPTER;
if (DEBUG) {
Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
System.identityHashCode(this), frameNumber));
@@ -1524,7 +1524,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
@Override
public void invalidate(boolean invalidateCache) {
super.invalidate(invalidateCache);
- if (ViewRootImpl.USE_BLAST_BUFFERQUEUE == false) {
+ if (!WindowManagerGlobal.USE_BLAST_ADAPTER) {
return;
}
final ViewRootImpl viewRoot = getViewRootImpl();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0db80e2749c3..13d609b16541 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11117,7 +11117,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Dispatches {@link WindowInsetsAnimationCallback#onStarted(InsetsAnimation, AnimationBounds)}
+ * Dispatches {@link WindowInsetsAnimationCallback#onPrepare(InsetsAnimation)}
+ * when Window Insets animation is being prepared.
+ * @param animation current animation
+ *
+ * @see WindowInsetsAnimationCallback#onPrepare(InsetsAnimation)
+ */
+ public void dispatchWindowInsetsAnimationPrepare(
+ @NonNull InsetsAnimation animation) {
+ if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) {
+ mListenerInfo.mWindowInsetsAnimationCallback.onPrepare(animation);
+ }
+ }
+
+ /**
+ * Dispatches {@link WindowInsetsAnimationCallback#onStart(InsetsAnimation, AnimationBounds)}
* when Window Insets animation is started.
* @param animation current animation
* @param bounds the upper and lower {@link AnimationBounds} that provides range of
@@ -11125,10 +11139,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return the upper and lower {@link AnimationBounds}.
*/
@NonNull
- public AnimationBounds dispatchWindowInsetsAnimationStarted(
+ public AnimationBounds dispatchWindowInsetsAnimationStart(
@NonNull InsetsAnimation animation, @NonNull AnimationBounds bounds) {
if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) {
- return mListenerInfo.mWindowInsetsAnimationCallback.onStarted(animation, bounds);
+ return mListenerInfo.mWindowInsetsAnimationCallback.onStart(animation, bounds);
}
return bounds;
}
@@ -11149,13 +11163,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Dispatches {@link WindowInsetsAnimationCallback#onFinished(InsetsAnimation)}
+ * Dispatches {@link WindowInsetsAnimationCallback#onFinish(InsetsAnimation)}
* when Window Insets animation finishes.
* @param animation The current ongoing {@link InsetsAnimation}.
*/
- public void dispatchWindowInsetsAnimationFinished(@NonNull InsetsAnimation animation) {
+ public void dispatchWindowInsetsAnimationFinish(@NonNull InsetsAnimation animation) {
if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) {
- mListenerInfo.mWindowInsetsAnimationCallback.onFinished(animation);
+ mListenerInfo.mWindowInsetsAnimationCallback.onFinish(animation);
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 5fb71773db8f..047d7da7536f 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7199,13 +7199,23 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
@Override
+ public void dispatchWindowInsetsAnimationPrepare(
+ @NonNull InsetsAnimation animation) {
+ super.dispatchWindowInsetsAnimationPrepare(animation);
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ getChildAt(i).dispatchWindowInsetsAnimationPrepare(animation);
+ }
+ }
+
+ @Override
@NonNull
- public AnimationBounds dispatchWindowInsetsAnimationStarted(
+ public AnimationBounds dispatchWindowInsetsAnimationStart(
@NonNull InsetsAnimation animation, @NonNull AnimationBounds bounds) {
- super.dispatchWindowInsetsAnimationStarted(animation, bounds);
+ super.dispatchWindowInsetsAnimationStart(animation, bounds);
final int count = getChildCount();
for (int i = 0; i < count; i++) {
- getChildAt(i).dispatchWindowInsetsAnimationStarted(animation, bounds);
+ getChildAt(i).dispatchWindowInsetsAnimationStart(animation, bounds);
}
return bounds;
}
@@ -7222,11 +7232,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
@Override
- public void dispatchWindowInsetsAnimationFinished(@NonNull InsetsAnimation animation) {
- super.dispatchWindowInsetsAnimationFinished(animation);
+ public void dispatchWindowInsetsAnimationFinish(@NonNull InsetsAnimation animation) {
+ super.dispatchWindowInsetsAnimationFinish(animation);
final int count = getChildCount();
for (int i = 0; i < count; i++) {
- getChildAt(i).dispatchWindowInsetsAnimationFinished(animation);
+ getChildAt(i).dispatchWindowInsetsAnimationFinish(animation);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 522ff9a3bcb5..ab89ef46e09e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -192,11 +192,6 @@ public final class ViewRootImpl implements ViewParent,
private static final boolean MT_RENDERER_AVAILABLE = true;
/**
- * @hide
- */
- public static final boolean USE_BLAST_BUFFERQUEUE = false;
-
- /**
* If set to 2, the view system will switch from using rectangles retrieved from window to
* dispatch to the view hierarchy to using {@link InsetsController}, that derives the insets
* directly from the full configuration, enabling richer information about the insets state, as
@@ -1312,7 +1307,7 @@ public final class ViewRootImpl implements ViewParent,
}
mWindowAttributes.privateFlags |= compatibleWindowFlag;
- if (USE_BLAST_BUFFERQUEUE) {
+ if (WindowManagerGlobal.USE_BLAST_ADAPTER) {
mWindowAttributes.privateFlags =
WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
}
@@ -1469,6 +1464,7 @@ public final class ViewRootImpl implements ViewParent,
return;
}
mApplyInsetsRequested = true;
+ requestLayout();
// If this changes during traversal, no need to schedule another one as it will dispatch it
// during the current traversal.
@@ -7273,7 +7269,7 @@ public final class ViewRootImpl implements ViewParent,
mPendingStableInsets, mPendingBackDropFrame, mPendingDisplayCutout,
mPendingMergedConfiguration, mSurfaceControl, mTempInsets);
if (mSurfaceControl.isValid()) {
- if (USE_BLAST_BUFFERQUEUE == false) {
+ if (!WindowManagerGlobal.USE_BLAST_ADAPTER) {
mSurface.copyFrom(mSurfaceControl);
} else {
mSurface.transferFrom(getOrCreateBLASTSurface(
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index a9cc50f9e65e..9df131de6754 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -27,8 +27,8 @@ import static android.view.WindowInsets.Type.STATUS_BARS;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
import static android.view.WindowInsets.Type.all;
-import static android.view.WindowInsets.Type.compatSystemInsets;
import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.systemBars;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -87,6 +87,8 @@ public final class WindowInsets {
private final boolean mStableInsetsConsumed;
private final boolean mDisplayCutoutConsumed;
+ private final int mCompatInsetTypes;
+
/**
* Since new insets may be added in the future that existing apps couldn't
* know about, this fully empty constant shouldn't be made available to apps
@@ -112,7 +114,7 @@ public final class WindowInsets {
boolean isRound, boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
- isRound, alwaysConsumeSystemBars, displayCutout);
+ isRound, alwaysConsumeSystemBars, displayCutout, systemBars());
}
/**
@@ -131,7 +133,7 @@ public final class WindowInsets {
@Nullable Insets[] typeMaxInsetsMap,
boolean[] typeVisibilityMap,
boolean isRound,
- boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
+ boolean alwaysConsumeSystemBars, DisplayCutout displayCutout, int compatInsetTypes) {
mSystemWindowInsetsConsumed = typeInsetsMap == null;
mTypeInsetsMap = mSystemWindowInsetsConsumed
? new Insets[SIZE]
@@ -145,6 +147,7 @@ public final class WindowInsets {
mTypeVisibilityMap = typeVisibilityMap;
mIsRound = isRound;
mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
+ mCompatInsetTypes = compatInsetTypes;
mDisplayCutoutConsumed = displayCutout == null;
mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
@@ -160,7 +163,8 @@ public final class WindowInsets {
this(src.mSystemWindowInsetsConsumed ? null : src.mTypeInsetsMap,
src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
src.mTypeVisibilityMap, src.mIsRound,
- src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src));
+ src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
+ src.mCompatInsetTypes);
}
private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) {
@@ -211,7 +215,8 @@ public final class WindowInsets {
/** @hide */
@UnsupportedAppUsage
public WindowInsets(Rect systemWindowInsets) {
- this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null);
+ this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null,
+ systemBars());
}
/**
@@ -280,7 +285,7 @@ public final class WindowInsets {
*/
@NonNull
public Insets getSystemWindowInsets() {
- return getInsets(mTypeInsetsMap, compatSystemInsets());
+ return getInsets(mTypeInsetsMap, mCompatInsetTypes);
}
/**
@@ -439,7 +444,8 @@ public final class WindowInsets {
mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
- null /* displayCutout */);
+ null /* displayCutout */,
+ mCompatInsetTypes);
}
@@ -485,7 +491,8 @@ public final class WindowInsets {
return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
- displayCutoutCopyConstructorArgument(this));
+ displayCutoutCopyConstructorArgument(this),
+ mCompatInsetTypes);
}
// TODO(b/119190588): replace @code with @link below
@@ -555,7 +562,7 @@ public final class WindowInsets {
*/
@NonNull
public Insets getStableInsets() {
- return getInsets(mTypeMaxInsetsMap, compatSystemInsets());
+ return getInsets(mTypeMaxInsetsMap, mCompatInsetTypes);
}
/**
@@ -733,7 +740,8 @@ public final class WindowInsets {
public WindowInsets consumeStableInsets() {
return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null,
mTypeVisibilityMap, mIsRound, mAlwaysConsumeSystemBars,
- displayCutoutCopyConstructorArgument(this));
+ displayCutoutCopyConstructorArgument(this),
+ mCompatInsetTypes);
}
/**
@@ -817,7 +825,8 @@ public final class WindowInsets {
? null
: mDisplayCutout == null
? DisplayCutout.NO_CUTOUT
- : mDisplayCutout.inset(left, top, right, bottom));
+ : mDisplayCutout.inset(left, top, right, bottom),
+ mCompatInsetTypes);
}
@Override
@@ -1134,7 +1143,8 @@ public final class WindowInsets {
public WindowInsets build() {
return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
- mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout);
+ mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout,
+ systemBars());
}
}
@@ -1271,15 +1281,6 @@ public final class WindowInsets {
}
/**
- * @return Inset types representing the list of bars that traditionally were denoted as
- * system insets.
- * @hide
- */
- static @InsetsType int compatSystemInsets() {
- return STATUS_BARS | NAVIGATION_BARS | IME;
- }
-
- /**
* @return All inset types combined.
*
* TODO: Figure out if this makes sense at all, mixing e.g {@link #systemGestures()} and
diff --git a/core/java/android/view/WindowInsetsAnimationCallback.java b/core/java/android/view/WindowInsetsAnimationCallback.java
index 5e71f271f1d4..e84c3e33c000 100644
--- a/core/java/android/view/WindowInsetsAnimationCallback.java
+++ b/core/java/android/view/WindowInsetsAnimationCallback.java
@@ -20,6 +20,7 @@ import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Insets;
+import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.animation.Interpolator;
@@ -30,7 +31,47 @@ import android.view.animation.Interpolator;
public interface WindowInsetsAnimationCallback {
/**
- * Called when an inset animation gets started.
+ * Called when an insets animation is about to start and before the views have been laid out in
+ * the end state of the animation. The ordering of events during an insets animation is the
+ * following:
+ * <p>
+ * <ul>
+ * <li>Application calls {@link WindowInsetsController#hideInputMethod()},
+ * {@link WindowInsetsController#showInputMethod()},
+ * {@link WindowInsetsController#controlInputMethodAnimation(long, WindowInsetsAnimationControlListener)}</li>
+ * <li>onPrepare is called on the view hierarchy listeners</li>
+ * <li>{@link View#onApplyWindowInsets} will be called with the end state of the
+ * animation</li>
+ * <li>View hierarchy gets laid out according to the changes the application has requested
+ * due to the new insets being dispatched</li>
+ * <li>{@link #onStart} is called <em>before</em> the view
+ * hierarchy gets drawn in the new laid out state</li>
+ * <li>{@link #onProgress} is called immediately after with the animation start state</li>
+ * <li>The frame gets drawn.</li>
+ * </ul>
+ * <p>
+ * This ordering allows the application to inspect the end state after the animation has
+ * finished, and then revert to the starting state of the animation in the first
+ * {@link #onProgress} callback by using post-layout view properties like {@link View#setX} and
+ * related methods.
+ * <p>
+ * Note: If the animation is application controlled by using
+ * {@link WindowInsetsController#controlInputMethodAnimation}, the end state of the animation
+ * is undefined as the application may decide on the end state only by passing in the
+ * {@code shown} parameter when calling {@link WindowInsetsAnimationController#finish}. In this
+ * situation, the system will dispatch the insets in the opposite visibility state before the
+ * animation starts. Example: When controlling the input method with
+ * {@link WindowInsetsController#controlInputMethodAnimation} and the input method is currently
+ * showing, {@link View#onApplyWindowInsets} will receive a {@link WindowInsets} instance for
+ * which {@link WindowInsets#isVisible} will return {@code false} for {@link Type#ime}.
+ *
+ * @param animation The animation that is about to start.
+ */
+ default void onPrepare(@NonNull InsetsAnimation animation) {
+ }
+
+ /**
+ * Called when an insets animation gets started.
* <p>
* Note that, like {@link #onProgress}, dispatch of the animation start event is hierarchical:
* It will starts at the root of the view hierarchy and then traverse it and invoke the callback
@@ -45,7 +86,7 @@ public interface WindowInsetsAnimationCallback {
* subtree of the hierarchy.
*/
@NonNull
- default AnimationBounds onStarted(
+ default AnimationBounds onStart(
@NonNull InsetsAnimation animation, @NonNull AnimationBounds bounds) {
return bounds;
}
@@ -72,12 +113,12 @@ public interface WindowInsetsAnimationCallback {
WindowInsets onProgress(@NonNull WindowInsets insets);
/**
- * Called when an inset animation has finished.
+ * Called when an insets animation has finished.
*
* @param animation The animation that has finished running. This will be the same instance as
- * passed into {@link #onStarted}
+ * passed into {@link #onStart}
*/
- default void onFinished(@NonNull InsetsAnimation animation) {
+ default void onFinish(@NonNull InsetsAnimation animation) {
}
/**
@@ -253,14 +294,14 @@ public interface WindowInsetsAnimationCallback {
/**
* Insets both the lower and upper bound by the specified insets. This is to be used in
- * {@link WindowInsetsAnimationCallback#onStarted} to indicate that a part of the insets has
+ * {@link WindowInsetsAnimationCallback#onStart} to indicate that a part of the insets has
* been used to offset or clip its children, and the children shouldn't worry about that
* part anymore.
*
* @param insets The amount to inset.
* @return A copy of this instance inset in the given directions.
* @see WindowInsets#inset
- * @see WindowInsetsAnimationCallback#onStarted
+ * @see WindowInsetsAnimationCallback#onStart
*/
@NonNull
public AnimationBounds inset(@NonNull Insets insets) {
diff --git a/core/java/android/view/WindowInsetsAnimationControlListener.java b/core/java/android/view/WindowInsetsAnimationControlListener.java
index 8a226c1bbe23..f91254de33ff 100644
--- a/core/java/android/view/WindowInsetsAnimationControlListener.java
+++ b/core/java/android/view/WindowInsetsAnimationControlListener.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.Hide;
import android.annotation.NonNull;
import android.view.WindowInsets.Type.InsetsType;
import android.view.inputmethod.EditorInfo;
@@ -26,6 +27,12 @@ import android.view.inputmethod.EditorInfo;
public interface WindowInsetsAnimationControlListener {
/**
+ * @hide
+ */
+ default void onPrepare(int types) {
+ }
+
+ /**
* Called when the animation is ready to be controlled. This may be delayed when the IME needs
* to redraw because of an {@link EditorInfo} change, or when the window is starting up.
*
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index 6de56be2f3c5..9d7f292dbdf5 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -149,7 +149,8 @@ public interface WindowInsetsController {
*
* @param types The {@link InsetsType}s the application has requested to control.
* @param durationMillis duration of animation in
- * {@link java.util.concurrent.TimeUnit#MILLISECONDS}
+ * {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or -1 if the
+ * animation doesn't have a predetermined duration.
* @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
* windows are ready to be controlled, among other callbacks.
* @hide
@@ -162,7 +163,8 @@ public interface WindowInsetsController {
* modifying the position of the IME when it's causing insets.
*
* @param durationMillis duration of the animation in
- * {@link java.util.concurrent.TimeUnit#MILLISECONDS}
+ * {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or -1 if the
+ * animation doesn't have a predetermined duration.
* @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
* IME are ready to be controlled, among other callbacks.
*/
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 95780023563d..7d5564e1c8be 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -57,6 +57,12 @@ public final class WindowManagerGlobal {
private static final String TAG = "WindowManager";
/**
+ * This flag controls whether ViewRootImpl will utilize the Blast Adapter
+ * to send buffer updates to SurfaceFlinger
+ */
+ public static final boolean USE_BLAST_ADAPTER = false;
+
+ /**
* The user is navigating with keys (not the touch screen), so
* navigational focus should be shown.
*/
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index ff31bccfa648..2e5a4b57da18 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -31,6 +31,7 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
+import android.app.RemoteAction;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -1209,6 +1210,61 @@ public final class AccessibilityManager {
}
/**
+ * Register the provided {@link RemoteAction} with the given actionId
+ *
+ * @param action The remote action to be registered with the given actionId as system action.
+ * @param actionId The id uniquely identify the system action.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+ public void registerSystemAction(@NonNull RemoteAction action, int actionId) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return;
+ }
+ }
+ try {
+ service.registerSystemAction(action, actionId);
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "System action " + action.getTitle() + " is registered.");
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error registering system action " + action.getTitle() + " ", re);
+ }
+ }
+
+ /**
+ * Unregister a system action with the given actionId
+ *
+ * @param actionId The id uniquely identify the system action to be unregistered.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+ public void unregisterSystemAction(int actionId) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return;
+ }
+ }
+ try {
+ service.unregisterSystemAction(actionId);
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "System action with actionId " + actionId + " is unregistered.");
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error unregistering system action with actionId " + actionId + " ", re);
+ }
+ }
+
+ /**
* Notifies that the accessibility button in the system's navigation area has been clicked
*
* @param displayId The logical display id.
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 36515b3ba094..392db574d988 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -16,6 +16,7 @@
package android.view.accessibility;
+import android.app.RemoteAction;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.accessibilityservice.IAccessibilityServiceClient;
@@ -82,4 +83,7 @@ interface IAccessibilityManager {
int getAccessibilityWindowId(IBinder windowToken);
long getRecommendedTimeoutMillis();
+
+ oneway void registerSystemAction(in RemoteAction action, int actionId);
+ oneway void unregisterSystemAction(int actionId);
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 67ce8d2e49b5..f3007a794344 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -93,9 +93,12 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CancellationException;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
@@ -429,7 +432,10 @@ public final class InputMethodManager {
* in a background thread. Later, if there is an actual startInput it will wait on
* main thread till the background thread completes.
*/
- private CompletableFuture<Void> mWindowFocusGainFuture;
+ private Future<?> mWindowFocusGainFuture;
+
+ private ExecutorService mStartInputWorker = Executors.newSingleThreadExecutor(
+ new ImeThreadFactory("StartInputWorker"));
/**
* The instance that has previously been sent to the input method.
@@ -790,6 +796,19 @@ public final class InputMethodManager {
}
}
+ private static class ImeThreadFactory implements ThreadFactory {
+ private final String mThreadName;
+
+ ImeThreadFactory(String name) {
+ mThreadName = name;
+ }
+
+ @Override
+ public Thread newThread(Runnable r) {
+ return new Thread(r, mThreadName);
+ }
+ }
+
final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
@Override
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
@@ -1978,7 +1997,7 @@ public final class InputMethodManager {
if (mWindowFocusGainFuture != null) {
mWindowFocusGainFuture.cancel(false/* mayInterruptIfRunning */);
}
- mWindowFocusGainFuture = CompletableFuture.runAsync(() -> {
+ mWindowFocusGainFuture = mStartInputWorker.submit(() -> {
if (checkFocusNoStartInput(forceNewFocus1)) {
// We need to restart input on the current focus view. This
// should be done in conjunction with telling the system service
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index a0cf53437a50..20af76b0d5ca 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -5921,8 +5921,6 @@ public class Editor {
// The offsets of that last touch down event. Remembered to start selection there.
private int mMinTouchOffset, mMaxTouchOffset;
- private boolean mGestureStayedInTapRegion;
-
// Where the user first starts the drag motion.
private int mStartOffset = -1;
@@ -6029,8 +6027,7 @@ public class Editor {
eventX, eventY);
// Double tap detection
- if (mGestureStayedInTapRegion
- && mTouchState.isMultiTapInSameArea()
+ if (mTouchState.isMultiTapInSameArea()
&& (isMouse || isPositionOnText(eventX, eventY))) {
if (TextView.DEBUG_CURSOR) {
logCursor("SelectionModifierCursorController: onTouchEvent",
@@ -6043,7 +6040,6 @@ public class Editor {
}
mDiscardNextActionUp = true;
}
- mGestureStayedInTapRegion = true;
mHaventMovedEnoughToStartDrag = true;
}
break;
@@ -6059,25 +6055,8 @@ public class Editor {
break;
case MotionEvent.ACTION_MOVE:
- final ViewConfiguration viewConfig = ViewConfiguration.get(
- mTextView.getContext());
-
- if (mGestureStayedInTapRegion || mHaventMovedEnoughToStartDrag) {
- final float deltaX = eventX - mTouchState.getLastDownX();
- final float deltaY = eventY - mTouchState.getLastDownY();
- final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
-
- if (mGestureStayedInTapRegion) {
- int doubleTapTouchSlop = viewConfig.getScaledDoubleTapTouchSlop();
- mGestureStayedInTapRegion =
- distanceSquared <= doubleTapTouchSlop * doubleTapTouchSlop;
- }
- if (mHaventMovedEnoughToStartDrag) {
- // We don't start dragging until the user has moved enough.
- int touchSlop = viewConfig.getScaledTouchSlop();
- mHaventMovedEnoughToStartDrag =
- distanceSquared <= touchSlop * touchSlop;
- }
+ if (mHaventMovedEnoughToStartDrag) {
+ mHaventMovedEnoughToStartDrag = !mTouchState.isMovedEnoughForDrag();
}
if (isMouse && !isDragAcceleratorActive()) {
diff --git a/core/java/android/widget/EditorTouchState.java b/core/java/android/widget/EditorTouchState.java
index d53099d44f6f..6277afe2f613 100644
--- a/core/java/android/widget/EditorTouchState.java
+++ b/core/java/android/widget/EditorTouchState.java
@@ -31,13 +31,15 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Helper class used by {@link Editor} to track state for touch events.
+ * Helper class used by {@link Editor} to track state for touch events. Ideally the logic here
+ * should be replaced with {@link android.view.GestureDetector}.
*
* @hide
*/
@VisibleForTesting(visibility = PACKAGE)
public class EditorTouchState {
private float mLastDownX, mLastDownY;
+ private long mLastDownMillis;
private float mLastUpX, mLastUpY;
private long mLastUpMillis;
@@ -106,9 +108,18 @@ public class EditorTouchState {
final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
final boolean isMouse = event.isFromSource(InputDevice.SOURCE_MOUSE);
+
+ // We check both the time between the last up and current down event, as well as the
+ // time between the first down and up events. The latter check is necessary to handle
+ // the case when the user taps, drags/holds for some time, and then lifts up and
+ // quickly taps in the same area. This scenario should not be treated as a double-tap.
+ // This follows the behavior in GestureDetector.
final long millisSinceLastUp = event.getEventTime() - mLastUpMillis;
+ final long millisBetweenLastDownAndLastUp = mLastUpMillis - mLastDownMillis;
+
// Detect double tap and triple click.
if (millisSinceLastUp <= ViewConfiguration.getDoubleTapTimeout()
+ && millisBetweenLastDownAndLastUp <= ViewConfiguration.getDoubleTapTimeout()
&& (mMultiTapStatus == MultiTapStatus.FIRST_TAP
|| (mMultiTapStatus == MultiTapStatus.DOUBLE_TAP && isMouse))) {
if (mMultiTapStatus == MultiTapStatus.FIRST_TAP) {
@@ -133,6 +144,7 @@ public class EditorTouchState {
}
mLastDownX = event.getX();
mLastDownY = event.getY();
+ mLastDownMillis = event.getEventTime();
mMovedEnoughForDrag = false;
mIsDragCloseToVertical = false;
} else if (action == MotionEvent.ACTION_UP) {
diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
index f9ba34ed1c3a..de204badfd0d 100644
--- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
@@ -16,6 +16,7 @@
package com.android.internal.app;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static android.view.accessibility.AccessibilityManager.ShortcutType;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -24,13 +25,17 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.AlertDialog;
+import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
+import android.os.UserHandle;
import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -49,7 +54,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
+import java.util.StringJoiner;
/**
* Activity used to display and persist a service or feature target for the Accessibility button.
@@ -59,13 +67,46 @@ public class AccessibilityButtonChooserActivity extends Activity {
private static final String MAGNIFICATION_COMPONENT_ID =
"com.android.server.accessibility.MagnificationController";
+ private static final char SERVICES_SEPARATOR = ':';
+ private static final TextUtils.SimpleStringSplitter sStringColonSplitter =
+ new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR);
+ private static final int ACCESSIBILITY_BUTTON_USER_TYPE = convertToUserType(
+ ACCESSIBILITY_BUTTON);
+ private static final int ACCESSIBILITY_SHORTCUT_KEY_USER_TYPE = convertToUserType(
+ ACCESSIBILITY_SHORTCUT_KEY);
+
private int mShortcutType;
private List<AccessibilityButtonTarget> mTargets = new ArrayList<>();
- private List<AccessibilityButtonTarget> mReadyToBeDisabledTargets = new ArrayList<>();
private AlertDialog mAlertDialog;
private TargetAdapter mTargetAdapter;
/**
+ * Annotation for different user shortcut type UI type.
+ *
+ * {@code DEFAULT} for displaying default value.
+ * {@code SOFTWARE} for displaying specifying the accessibility services or features which
+ * choose accessibility button in the navigation bar as preferred shortcut.
+ * {@code HARDWARE} for displaying specifying the accessibility services or features which
+ * choose accessibility shortcut as preferred shortcut.
+ * {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly
+ * tapping screen 3 times as preferred shortcut.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ UserShortcutType.DEFAULT,
+ UserShortcutType.SOFTWARE,
+ UserShortcutType.HARDWARE,
+ UserShortcutType.TRIPLETAP,
+ })
+ /** Denotes the user shortcut type. */
+ public @interface UserShortcutType {
+ int DEFAULT = 0;
+ int SOFTWARE = 1; // 1 << 0
+ int HARDWARE = 2; // 1 << 1
+ int TRIPLETAP = 4; // 1 << 2
+ }
+
+ /**
* Annotation for different accessibilityService fragment UI type.
*
* {@code LEGACY} for displaying appearance aligned with sdk version Q accessibility service
@@ -117,7 +158,6 @@ public class AccessibilityButtonChooserActivity extends Activity {
ACCESSIBILITY_BUTTON);
mTargets.addAll(getServiceTargets(this, mShortcutType));
- // TODO(b/146815548): Will add title to separate which one type
mTargetAdapter = new TargetAdapter(mTargets);
mAlertDialog = new AlertDialog.Builder(this)
.setAdapter(mTargetAdapter, /* listener= */ null)
@@ -269,8 +309,10 @@ public class AccessibilityButtonChooserActivity extends Activity {
switch (target.getFragmentType()) {
case AccessibilityServiceFragmentType.LEGACY:
+ updateLegacyActionItemVisibility(context, holder);
+ break;
case AccessibilityServiceFragmentType.INVISIBLE:
- updateLegacyOrInvisibleActionItemVisibility(context, holder);
+ updateInvisibleActionItemVisibility(context, holder);
break;
case AccessibilityServiceFragmentType.INTUITIVE:
updateIntuitiveActionItemVisibility(context, holder, target);
@@ -283,9 +325,21 @@ public class AccessibilityButtonChooserActivity extends Activity {
}
}
- private void updateLegacyOrInvisibleActionItemVisibility(@NonNull Context context,
+ private void updateLegacyActionItemVisibility(@NonNull Context context,
@NonNull ViewHolder holder) {
- final boolean isEditMenuMode = mShortcutMenuMode == ShortcutMenuMode.EDIT;
+ final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT);
+
+ holder.mLabelView.setEnabled(!isEditMenuMode);
+ holder.mViewItem.setEnabled(!isEditMenuMode);
+ holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
+ holder.mViewItem.setVisibility(View.VISIBLE);
+ holder.mSwitchItem.setVisibility(View.GONE);
+ holder.mItemContainer.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+ }
+
+ private void updateInvisibleActionItemVisibility(@NonNull Context context,
+ @NonNull ViewHolder holder) {
+ final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT);
holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
holder.mViewItem.setVisibility(View.VISIBLE);
@@ -295,7 +349,7 @@ public class AccessibilityButtonChooserActivity extends Activity {
private void updateIntuitiveActionItemVisibility(@NonNull Context context,
@NonNull ViewHolder holder, AccessibilityButtonTarget target) {
- final boolean isEditMenuMode = mShortcutMenuMode == ShortcutMenuMode.EDIT;
+ final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT);
holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
holder.mViewItem.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
@@ -306,7 +360,7 @@ public class AccessibilityButtonChooserActivity extends Activity {
private void updateBounceActionItemVisibility(@NonNull Context context,
@NonNull ViewHolder holder) {
- final boolean isEditMenuMode = mShortcutMenuMode == ShortcutMenuMode.EDIT;
+ final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT);
holder.mViewItem.setImageDrawable(
isEditMenuMode ? context.getDrawable(R.drawable.ic_delete_item)
@@ -383,73 +437,252 @@ public class AccessibilityButtonChooserActivity extends Activity {
}
private void onTargetDeleted(AdapterView<?> parent, View view, int position, long id) {
- // TODO(b/147027236): Will discuss with UX designer what UX behavior about deleting item
- // is good for user.
- mReadyToBeDisabledTargets.add(mTargets.get(position));
+ final AccessibilityButtonTarget target = mTargets.get(position);
+ final ComponentName targetComponentName =
+ ComponentName.unflattenFromString(target.getId());
+
+ switch (target.getFragmentType()) {
+ case AccessibilityServiceFragmentType.INVISIBLE:
+ onInvisibleTargetDeleted(targetComponentName);
+ break;
+ case AccessibilityServiceFragmentType.INTUITIVE:
+ onIntuitiveTargetDeleted(targetComponentName);
+ break;
+ case AccessibilityServiceFragmentType.LEGACY:
+ case AccessibilityServiceFragmentType.BOUNCE:
+ // Do nothing
+ break;
+ default:
+ throw new IllegalStateException("Unexpected fragment type");
+ }
+
mTargets.remove(position);
mTargetAdapter.notifyDataSetChanged();
+
+ if (mTargets.isEmpty()) {
+ mAlertDialog.dismiss();
+ }
}
- private void onCancelButtonClicked() {
- resetAndUpdateTargets();
+ private void onInvisibleTargetDeleted(ComponentName componentName) {
+ if (mShortcutType == ACCESSIBILITY_BUTTON) {
+ optOutValueFromSettings(this, ACCESSIBILITY_BUTTON_USER_TYPE, componentName);
- mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.LAUNCH);
- mTargetAdapter.notifyDataSetChanged();
+ if (!hasValueInSettings(this,
+ ACCESSIBILITY_SHORTCUT_KEY_USER_TYPE, componentName)) {
+ setAccessibilityServiceState(this, componentName, /* enabled= */ false);
+ }
+ } else if (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+ optOutValueFromSettings(this, ACCESSIBILITY_SHORTCUT_KEY_USER_TYPE, componentName);
- mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
- mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText(
- getString(R.string.edit_accessibility_shortcut_menu_button));
+ if (!hasValueInSettings(this,
+ ACCESSIBILITY_BUTTON_USER_TYPE, componentName)) {
+ setAccessibilityServiceState(this, componentName, /* enabled= */ false);
+ }
+ } else {
+ throw new IllegalArgumentException("Unsupported shortcut type:" + mShortcutType);
+ }
+ }
- updateDialogListeners();
+ private void onIntuitiveTargetDeleted(ComponentName componentName) {
+ if (mShortcutType == ACCESSIBILITY_BUTTON) {
+ optOutValueFromSettings(this, ACCESSIBILITY_BUTTON_USER_TYPE, componentName);
+ } else if (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+ optOutValueFromSettings(this, ACCESSIBILITY_SHORTCUT_KEY_USER_TYPE, componentName);
+ } else {
+ throw new IllegalArgumentException("Unsupported shortcut type:" + mShortcutType);
+ }
}
- private void onEditButtonClicked() {
- mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.EDIT);
+ private void onCancelButtonClicked() {
+ mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.LAUNCH);
mTargetAdapter.notifyDataSetChanged();
- mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setText(
- getString(R.string.cancel_accessibility_shortcut_menu_button));
- mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.VISIBLE);
mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText(
- getString(R.string.save_accessibility_shortcut_menu_button));
+ getString(R.string.edit_accessibility_shortcut_menu_button));
updateDialogListeners();
}
- private void onSaveButtonClicked() {
- disableTargets();
- resetAndUpdateTargets();
-
- mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.LAUNCH);
+ private void onEditButtonClicked() {
+ mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.EDIT);
mTargetAdapter.notifyDataSetChanged();
- mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText(
- getString(R.string.edit_accessibility_shortcut_menu_button));
+ getString(R.string.cancel_accessibility_shortcut_menu_button));
updateDialogListeners();
}
private void updateDialogListeners() {
final boolean isEditMenuMode =
- mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT;
+ (mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT);
- mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener(
- view -> onCancelButtonClicked());
mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(
- isEditMenuMode ? view -> onSaveButtonClicked() : view -> onEditButtonClicked());
+ isEditMenuMode ? view -> onCancelButtonClicked() : view -> onEditButtonClicked());
mAlertDialog.getListView().setOnItemClickListener(
isEditMenuMode ? this::onTargetDeleted : this::onTargetSelected);
}
- private void disableTargets() {
- for (AccessibilityButtonTarget service : mReadyToBeDisabledTargets) {
- // TODO(b/146967898): disable services.
+ /**
+ * @return the set of enabled accessibility services for {@param userId}. If there are no
+ * services, it returns the unmodifiable {@link Collections#emptySet()}.
+ */
+ private Set<ComponentName> getEnabledServicesFromSettings(Context context, int userId) {
+ final String enabledServicesSetting = Settings.Secure.getStringForUser(
+ context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userId);
+ if (TextUtils.isEmpty(enabledServicesSetting)) {
+ return Collections.emptySet();
}
+
+ final Set<ComponentName> enabledServices = new HashSet<>();
+ final TextUtils.StringSplitter colonSplitter =
+ new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR);
+ colonSplitter.setString(enabledServicesSetting);
+
+ for (String componentNameString : colonSplitter) {
+ final ComponentName enabledService = ComponentName.unflattenFromString(
+ componentNameString);
+ if (enabledService != null) {
+ enabledServices.add(enabledService);
+ }
+ }
+
+ return enabledServices;
}
- private void resetAndUpdateTargets() {
- mTargets.clear();
- mTargets.addAll(getServiceTargets(this, mShortcutType));
+ /**
+ * Changes an accessibility component's state.
+ */
+ private void setAccessibilityServiceState(Context context, ComponentName componentName,
+ boolean enabled) {
+ setAccessibilityServiceState(context, componentName, enabled, UserHandle.myUserId());
+ }
+
+ /**
+ * Changes an accessibility component's state for {@param userId}.
+ */
+ private void setAccessibilityServiceState(Context context, ComponentName componentName,
+ boolean enabled, int userId) {
+ Set<ComponentName> enabledServices = getEnabledServicesFromSettings(
+ context, userId);
+
+ if (enabledServices.isEmpty()) {
+ enabledServices = new ArraySet<>(/* capacity= */ 1);
+ }
+
+ if (enabled) {
+ enabledServices.add(componentName);
+ } else {
+ enabledServices.remove(componentName);
+ }
+
+ final StringBuilder enabledServicesBuilder = new StringBuilder();
+ for (ComponentName enabledService : enabledServices) {
+ enabledServicesBuilder.append(enabledService.flattenToString());
+ enabledServicesBuilder.append(
+ SERVICES_SEPARATOR);
+ }
+
+ final int enabledServicesBuilderLength = enabledServicesBuilder.length();
+ if (enabledServicesBuilderLength > 0) {
+ enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
+ }
+
+ Settings.Secure.putStringForUser(context.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ enabledServicesBuilder.toString(), userId);
+ }
+
+ /**
+ * Opts out component name into colon-separated {@code shortcutType} key's string in Settings.
+ *
+ * @param context The current context.
+ * @param shortcutType The preferred shortcut type user selected.
+ * @param componentName The component name that need to be opted out from Settings.
+ */
+ private void optOutValueFromSettings(
+ Context context, int shortcutType, ComponentName componentName) {
+ final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
+ final String targetsKey = convertToKey(shortcutType);
+ final String targetsValue = Settings.Secure.getString(context.getContentResolver(),
+ targetsKey);
+
+ if (TextUtils.isEmpty(targetsValue)) {
+ return;
+ }
+
+ sStringColonSplitter.setString(targetsValue);
+ while (sStringColonSplitter.hasNext()) {
+ final String name = sStringColonSplitter.next();
+ if (TextUtils.isEmpty(name) || (componentName.flattenToString()).equals(name)) {
+ continue;
+ }
+ joiner.add(name);
+ }
+
+ Settings.Secure.putString(context.getContentResolver(), targetsKey, joiner.toString());
+ }
+
+ /**
+ * Returns if component name existed in Settings.
+ *
+ * @param context The current context.
+ * @param shortcutType The preferred shortcut type user selected.
+ * @param componentName The component name that need to be checked existed in Settings.
+ * @return {@code true} if componentName existed in Settings.
+ */
+ private boolean hasValueInSettings(Context context, @UserShortcutType int shortcutType,
+ @NonNull ComponentName componentName) {
+ final String targetKey = convertToKey(shortcutType);
+ final String targetString = Settings.Secure.getString(context.getContentResolver(),
+ targetKey);
+
+ if (TextUtils.isEmpty(targetString)) {
+ return false;
+ }
+
+ sStringColonSplitter.setString(targetString);
+ while (sStringColonSplitter.hasNext()) {
+ final String name = sStringColonSplitter.next();
+ if ((componentName.flattenToString()).equals(name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Converts {@link UserShortcutType} to key in Settings.
+ *
+ * @param type The shortcut type.
+ * @return Mapping key in Settings.
+ */
+ private String convertToKey(@UserShortcutType int type) {
+ switch (type) {
+ case UserShortcutType.SOFTWARE:
+ return Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT;
+ case UserShortcutType.HARDWARE:
+ return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
+ case UserShortcutType.TRIPLETAP:
+ return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported user shortcut type: " + type);
+ }
+ }
+
+ private static @UserShortcutType int convertToUserType(@ShortcutType int type) {
+ switch (type) {
+ case ACCESSIBILITY_BUTTON:
+ return UserShortcutType.SOFTWARE;
+ case ACCESSIBILITY_SHORTCUT_KEY:
+ return UserShortcutType.HARDWARE;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported shortcut type:" + type);
+ }
}
}
diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl
index d94294f0aa22..74bfb963c6b0 100644
--- a/core/java/com/android/internal/app/ISoundTriggerService.aidl
+++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl
@@ -61,10 +61,6 @@ interface ISoundTriggerService {
int setParameter(in ParcelUuid soundModelId, in ModelParams modelParam,
int value);
- /**
- * @throws UnsupportedOperationException if hal or model do not support this API.
- * @throws IllegalArgumentException if invalid model handle or parameter is passed.
- */
int getParameter(in ParcelUuid soundModelId, in ModelParams modelParam);
@nullable SoundTrigger.ModelParamRange queryParameter(in ParcelUuid soundModelId,
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index f462f5d2571d..be2d1d60e9a2 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -26,6 +26,7 @@ import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.IVoiceInteractionSessionListener;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
@@ -91,6 +92,49 @@ interface IVoiceInteractionManagerService {
*/
int stopRecognition(in IVoiceInteractionService service, int keyphraseId,
in IRecognitionStatusCallback callback);
+ /**
+ * Set a model specific ModelParams with the given value. This
+ * parameter will keep its value for the duration the model is loaded regardless of starting and
+ * stopping recognition. Once the model is unloaded, the value will be lost.
+ * queryParameter should be checked first before calling this method.
+ *
+ * @param service The current VoiceInteractionService.
+ * @param keyphraseId The unique identifier for the keyphrase.
+ * @param modelParam ModelParams
+ * @param value Value to set
+ * @return - {@link SoundTrigger#STATUS_OK} in case of success
+ * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
+ * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
+ * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
+ * if API is not supported by HAL
+ */
+ int setParameter(in IVoiceInteractionService service, int keyphraseId,
+ in ModelParams modelParam, int value);
+ /**
+ * Get a model specific ModelParams. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See ModelParams for parameter default values.
+ * queryParameter should be checked first before calling this method.
+ *
+ * @param service The current VoiceInteractionService.
+ * @param keyphraseId The unique identifier for the keyphrase.
+ * @param modelParam ModelParams
+ * @return value of parameter
+ */
+ int getParameter(in IVoiceInteractionService service, int keyphraseId,
+ in ModelParams modelParam);
+ /**
+ * Determine if parameter control is supported for the given model handle.
+ * This method should be checked prior to calling setParameter or getParameter.
+ *
+ * @param service The current VoiceInteractionService.
+ * @param keyphraseId The unique identifier for the keyphrase.
+ * @param modelParam ModelParams
+ * @return supported range of parameter, null if not supported
+ */
+ @nullable SoundTrigger.ModelParamRange queryParameter(in IVoiceInteractionService service,
+ int keyphraseId, in ModelParams modelParam);
/**
* @return the component name for the currently active voice interaction service
diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
new file mode 100644
index 000000000000..0b937fad7df1
--- /dev/null
+++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
@@ -0,0 +1,34 @@
+/*
+ * 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 com.android.internal.compat;
+
+import android.os.Build;
+
+/**
+ * Platform private class for determining the type of Android build installed.
+ *
+ */
+public class AndroidBuildClassifier {
+
+ public boolean isDebuggableBuild() {
+ return Build.IS_DEBUGGABLE;
+ }
+
+ public boolean isFinalBuild() {
+ return "REL".equals(Build.VERSION.CODENAME);
+ }
+}
diff --git a/core/java/com/android/internal/compat/IOverrideValidator.aidl b/core/java/com/android/internal/compat/IOverrideValidator.aidl
new file mode 100644
index 000000000000..add4708863aa
--- /dev/null
+++ b/core/java/com/android/internal/compat/IOverrideValidator.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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 com.android.internal.compat;
+
+import android.content.pm.ApplicationInfo;
+
+import com.android.internal.compat.OverrideAllowedState;
+
+/**
+ * Platform private API for determining whether a changeId can be overridden.
+ *
+ * {@hide}
+ */
+interface IOverrideValidator
+{
+ /**
+ * Validation function.
+ * @param changeId id of the change to be toggled on or off.
+ * @param packageName package of the app for which the change should be overridden.
+ * @return {@link OverrideAllowedState} specifying whether the change can be overridden for
+ * the given package or a reason why not.
+ */
+ OverrideAllowedState getOverrideAllowedState(long changeId, String packageName);
+}
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 7dcb12c9e72b..4c203d394759 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -17,6 +17,7 @@
package com.android.internal.compat;
import android.content.pm.ApplicationInfo;
+import com.android.internal.compat.IOverrideValidator;
import java.util.Map;
parcelable CompatibilityChangeConfig;
@@ -195,4 +196,9 @@ interface IPlatformCompat
* @return An array of {@link CompatChangeInfo} known to the service.
*/
CompatibilityChangeInfo[] listAllChanges();
+
+ /**
+ * Get an instance that can determine whether a changeid can be overridden for a package name.
+ */
+ IOverrideValidator getOverrideValidator();
}
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.aidl b/core/java/com/android/internal/compat/OverrideAllowedState.aidl
new file mode 100644
index 000000000000..10ceac786841
--- /dev/null
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 com.android.internal.compat;
+
+parcelable OverrideAllowedState; \ No newline at end of file
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
new file mode 100644
index 000000000000..56216c251070
--- /dev/null
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -0,0 +1,153 @@
+/*
+ * 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 com.android.internal.compat;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class contains all the possible override allowed states.
+ */
+public final class OverrideAllowedState implements Parcelable {
+ @IntDef({
+ ALLOWED,
+ DISABLED_NOT_DEBUGGABLE,
+ DISABLED_NON_TARGET_SDK,
+ DISABLED_TARGET_SDK_TOO_HIGH,
+ PACKAGE_DOES_NOT_EXIST
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {
+ }
+
+ /**
+ * Change can be overridden.
+ */
+ public static final int ALLOWED = 0;
+ /**
+ * Change cannot be overridden, due to the app not being debuggable.
+ */
+ public static final int DISABLED_NOT_DEBUGGABLE = 1;
+ /**
+ * Change cannot be overridden, due to the build being non-debuggable and the change being
+ * non-targetSdk.
+ */
+ public static final int DISABLED_NON_TARGET_SDK = 2;
+ /**
+ * Change cannot be overridden, due to the app's targetSdk being above the change's targetSdk.
+ */
+ public static final int DISABLED_TARGET_SDK_TOO_HIGH = 3;
+ /**
+ * Package does not exist.
+ */
+ public static final int PACKAGE_DOES_NOT_EXIST = 4;
+
+ @State
+ public final int state;
+ public final int appTargetSdk;
+ public final int changeIdTargetSdk;
+
+ private OverrideAllowedState(Parcel parcel) {
+ state = parcel.readInt();
+ appTargetSdk = parcel.readInt();
+ changeIdTargetSdk = parcel.readInt();
+ }
+
+ public OverrideAllowedState(@State int state, int appTargetSdk, int changeIdTargetSdk) {
+ this.state = state;
+ this.appTargetSdk = appTargetSdk;
+ this.changeIdTargetSdk = changeIdTargetSdk;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(state);
+ out.writeInt(appTargetSdk);
+ out.writeInt(changeIdTargetSdk);
+ }
+
+ /**
+ * Enforces the policy for overriding compat changes.
+ *
+ * @param changeId the change id that was attempted to be overridden.
+ * @param packageName the package for which the attempt was made.
+ * @throws SecurityException if the policy forbids this operation.
+ */
+ public void enforce(long changeId, String packageName)
+ throws SecurityException {
+ switch (state) {
+ case ALLOWED:
+ return;
+ case DISABLED_NOT_DEBUGGABLE:
+ throw new SecurityException(
+ "Cannot override a change on a non-debuggable app and user build.");
+ case DISABLED_NON_TARGET_SDK:
+ throw new SecurityException(
+ "Cannot override a default enabled/disabled change on a user build.");
+ case DISABLED_TARGET_SDK_TOO_HIGH:
+ throw new SecurityException(String.format(
+ "Cannot override %1$d for %2$s because the app's targetSdk (%3$d) is "
+ + "above the change's targetSdk threshold (%4$d)",
+ changeId, packageName, appTargetSdk, changeIdTargetSdk));
+ case PACKAGE_DOES_NOT_EXIST:
+ throw new SecurityException(String.format(
+ "Cannot override %1$d for %2$s because the package does not exist, and "
+ + "the change is targetSdk gated.",
+ changeId, packageName));
+ }
+ }
+
+ public static final @NonNull
+ Parcelable.Creator<OverrideAllowedState> CREATOR =
+ new Parcelable.Creator<OverrideAllowedState>() {
+ public OverrideAllowedState createFromParcel(Parcel parcel) {
+ OverrideAllowedState info = new OverrideAllowedState(parcel);
+ return info;
+ }
+
+ public OverrideAllowedState[] newArray(int size) {
+ return new OverrideAllowedState[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof OverrideAllowedState)) {
+ return false;
+ }
+ OverrideAllowedState otherState = (OverrideAllowedState) obj;
+ return state == otherState.state
+ && appTargetSdk == otherState.appTargetSdk
+ && changeIdTargetSdk == otherState.changeIdTargetSdk;
+ }
+}
diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java
index b250578c8454..9f15d8991fa7 100644
--- a/core/java/com/android/internal/infra/AndroidFuture.java
+++ b/core/java/com/android/internal/infra/AndroidFuture.java
@@ -75,6 +75,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable
private static final boolean DEBUG = false;
private static final String LOG_TAG = AndroidFuture.class.getSimpleName();
+ private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
private final @NonNull Object mLock = new Object();
@GuardedBy("mLock")
@@ -95,15 +96,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable
// Done
if (in.readBoolean()) {
// Failed
- try {
- in.readException();
- } catch (Throwable e) {
- completeExceptionally(e);
- }
- if (!isCompletedExceptionally()) {
- throw new IllegalStateException(
- "Error unparceling AndroidFuture: exception expected");
- }
+ completeExceptionally(unparcelException(in));
} else {
// Success
complete((T) in.readValue(null));
@@ -512,14 +505,9 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable
T result;
try {
result = get();
- } catch (Exception t) {
- // Exceptions coming out of get() are wrapped in ExecutionException, which is not
- // handled by Parcel.
- if (t instanceof ExecutionException && t.getCause() instanceof Exception) {
- t = (Exception) t.getCause();
- }
+ } catch (Throwable t) {
dest.writeBoolean(true);
- dest.writeException(t);
+ parcelException(dest, unwrapExecutionException(t));
return;
}
dest.writeBoolean(false);
@@ -528,22 +516,76 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable
dest.writeStrongBinder(new IAndroidFuture.Stub() {
@Override
public void complete(AndroidFuture resultContainer) {
+ boolean changed;
try {
- AndroidFuture.this.complete((T) resultContainer.get());
+ changed = AndroidFuture.this.complete((T) resultContainer.get());
} catch (Throwable t) {
- // If resultContainer was completed exceptionally, get() wraps the
- // underlying exception in an ExecutionException. Unwrap it now to avoid
- // double-layering ExecutionExceptions.
- if (t instanceof ExecutionException && t.getCause() != null) {
- t = t.getCause();
- }
- completeExceptionally(t);
+ changed = completeExceptionally(unwrapExecutionException(t));
+ }
+ if (!changed) {
+ Log.w(LOG_TAG, "Remote result " + resultContainer
+ + " ignored, as local future is already completed: "
+ + AndroidFuture.this);
}
}
}.asBinder());
}
}
+ /**
+ * Exceptions coming out of {@link #get} are wrapped in {@link ExecutionException}
+ */
+ Throwable unwrapExecutionException(Throwable t) {
+ return t instanceof ExecutionException
+ ? t.getCause()
+ : t;
+ }
+
+ /**
+ * Alternative to {@link Parcel#writeException} that stores the stack trace, in a
+ * way consistent with the binder IPC exception propagation behavior.
+ */
+ private static void parcelException(Parcel p, @Nullable Throwable t) {
+ p.writeBoolean(t == null);
+ if (t == null) {
+ return;
+ }
+
+ p.writeInt(Parcel.getExceptionCode(t));
+ p.writeString(t.getClass().getName());
+ p.writeString(t.getMessage());
+ p.writeStackTrace(t);
+ parcelException(p, t.getCause());
+ }
+
+ /**
+ * @see #parcelException
+ */
+ private static @Nullable Throwable unparcelException(Parcel p) {
+ if (p.readBoolean()) {
+ return null;
+ }
+
+ int exCode = p.readInt();
+ String cls = p.readString();
+ String msg = p.readString();
+ String stackTrace = p.readInt() > 0 ? p.readString() : "\t<stack trace unavailable>";
+ msg += "\n" + stackTrace;
+
+ Exception ex = p.createExceptionOrNull(exCode, msg);
+ if (ex == null) {
+ ex = new RuntimeException(cls + ": " + msg);
+ }
+ ex.setStackTrace(EMPTY_STACK_TRACE);
+
+ Throwable cause = unparcelException(p);
+ if (cause != null) {
+ ex.initCause(ex);
+ }
+
+ return ex;
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index a86d702ba323..179828c4b456 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -35,7 +35,6 @@ import com.android.internal.logging.AndroidConfig;
import com.android.server.NetworkManagementSocketTagger;
import dalvik.system.RuntimeHooks;
-import dalvik.system.ThreadPrioritySetter;
import dalvik.system.VMRuntime;
import libcore.content.type.MimeMap;
@@ -205,7 +204,6 @@ public class RuntimeInit {
*/
public static void preForkInit() {
if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
- RuntimeHooks.setThreadPrioritySetter(new RuntimeThreadPrioritySetter());
RuntimeInit.enableDdms();
// TODO(b/142019040#comment13): Decide whether to load the default instance eagerly, i.e.
// MimeMap.setDefault(DefaultMimeMapFactory.create());
@@ -218,35 +216,6 @@ public class RuntimeInit {
MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create);
}
- private static class RuntimeThreadPrioritySetter implements ThreadPrioritySetter {
- // Should remain consistent with kNiceValues[] in system/libartpalette/palette_android.cc
- private static final int[] NICE_VALUES = {
- Process.THREAD_PRIORITY_LOWEST, // 1 (MIN_PRIORITY)
- Process.THREAD_PRIORITY_BACKGROUND + 6,
- Process.THREAD_PRIORITY_BACKGROUND + 3,
- Process.THREAD_PRIORITY_BACKGROUND,
- Process.THREAD_PRIORITY_DEFAULT, // 5 (NORM_PRIORITY)
- Process.THREAD_PRIORITY_DEFAULT - 2,
- Process.THREAD_PRIORITY_DEFAULT - 4,
- Process.THREAD_PRIORITY_URGENT_DISPLAY + 3,
- Process.THREAD_PRIORITY_URGENT_DISPLAY + 2,
- Process.THREAD_PRIORITY_URGENT_DISPLAY // 10 (MAX_PRIORITY)
- };
-
- @Override
- public void setPriority(int priority) {
- // Check NICE_VALUES[] length first.
- if (NICE_VALUES.length != (1 + Thread.MAX_PRIORITY - Thread.MIN_PRIORITY)) {
- throw new AssertionError("Unexpected NICE_VALUES.length=" + NICE_VALUES.length);
- }
- // Priority should be in the range of MIN_PRIORITY (1) to MAX_PRIORITY (10).
- if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
- throw new IllegalArgumentException("Priority out of range: " + priority);
- }
- Process.setThreadPriority(NICE_VALUES[priority - Thread.MIN_PRIORITY]);
- }
- }
-
@UnsupportedAppUsage
protected static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 2248b8853f8c..f0a346ab25fd 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -145,6 +145,11 @@ public final class Zygote {
/** The lower file system should be bind mounted directly on external storage */
public static final int MOUNT_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH;
+ /** Use the regular scoped storage filesystem, but Android/ should be writable.
+ * Used to support the applications hosting DownloadManager and the MTP server.
+ */
+ public static final int MOUNT_EXTERNAL_ANDROID_WRITABLE = IVold.REMOUNT_MODE_ANDROID_WRITABLE;
+
/** Number of bytes sent to the Zygote over USAP pipes or the pool event FD */
static final int USAP_MANAGEMENT_MESSAGE_BYTES = 8;
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index d3499541a3a3..37f570bba238 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -376,6 +376,8 @@ class ZygoteArguments {
mMountExternal = Zygote.MOUNT_EXTERNAL_LEGACY;
} else if (arg.equals("--mount-external-pass-through")) {
mMountExternal = Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
+ } else if (arg.equals("--mount-external-android-writable")) {
+ mMountExternal = Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE;
} else if (arg.equals("--query-abi-list")) {
mAbiListQuery = true;
} else if (arg.equals("--get-pid")) {
diff --git a/telephony/java/com/android/internal/telephony/IWapPushManager.aidl b/core/java/com/android/internal/telephony/IWapPushManager.aidl
index 1c3df65336f8..9f6851b8c254 100644
--- a/telephony/java/com/android/internal/telephony/IWapPushManager.aidl
+++ b/core/java/com/android/internal/telephony/IWapPushManager.aidl
@@ -18,6 +18,7 @@ package com.android.internal.telephony;
import android.content.Intent;
+/** @hide */
interface IWapPushManager {
/**
* Processes WAP push message and triggers the receiver application registered
@@ -26,11 +27,10 @@ interface IWapPushManager {
int processMessage(String app_id, String content_type, in Intent intent);
/**
- * Add receiver application into the application ID table.
- * Returns true if inserting the information is successfull. Inserting the duplicated
+ * Adds receiver application into the application ID table.
+ * Returns true if inserting the information is successful. Inserting duplicated
* record in the application ID table is not allowed. Use update/delete method.
*/
- @UnsupportedAppUsage
boolean addPackage(String x_app_id, String content_type,
String package_name, String class_name,
int app_type, boolean need_signature, boolean further_processing);
@@ -39,17 +39,14 @@ interface IWapPushManager {
* Updates receiver application that is last added.
* Returns true if updating the information is successfull.
*/
- @UnsupportedAppUsage
boolean updatePackage(String x_app_id, String content_type,
String package_name, String class_name,
int app_type, boolean need_signature, boolean further_processing);
/**
- * Delites receiver application information.
+ * Deletes receiver application information.
* Returns true if deleting is successfull.
*/
- @UnsupportedAppUsage
boolean deletePackage(String x_app_id, String content_type,
- String package_name, String class_name);
+ String package_name, String class_name);
}
-
diff --git a/core/java/com/android/internal/telephony/WapPushManagerParams.java b/core/java/com/android/internal/telephony/WapPushManagerParams.java
new file mode 100644
index 000000000000..eafb8f1b423f
--- /dev/null
+++ b/core/java/com/android/internal/telephony/WapPushManagerParams.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 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 com.android.internal.telephony;
+
+import android.telephony.WapPushManagerConnector;
+
+/**
+ * WapPushManager constant value definitions.
+ * @hide
+ */
+public class WapPushManagerParams {
+ /**
+ * Application type activity
+ */
+ public static final int APP_TYPE_ACTIVITY = 0;
+
+ /**
+ * Application type service
+ */
+ public static final int APP_TYPE_SERVICE = 1;
+
+ /**
+ * Process Message return value
+ * Message is handled
+ */
+ public static final int MESSAGE_HANDLED = WapPushManagerConnector.RESULT_MESSAGE_HANDLED;
+
+ /**
+ * Process Message return value
+ * Application ID or content type was not found in the application ID table
+ */
+ public static final int APP_QUERY_FAILED = WapPushManagerConnector.RESULT_APP_QUERY_FAILED;
+
+ /**
+ * Process Message return value
+ * Receiver application signature check failed
+ */
+ public static final int SIGNATURE_NO_MATCH = WapPushManagerConnector.RESULT_SIGNATURE_NO_MATCH;
+
+ /**
+ * Process Message return value
+ * Receiver application was not found
+ */
+ public static final int INVALID_RECEIVER_NAME =
+ WapPushManagerConnector.RESULT_INVALID_RECEIVER_NAME;
+
+ /**
+ * Process Message return value
+ * Unknown exception
+ */
+ public static final int EXCEPTION_CAUGHT = WapPushManagerConnector.RESULT_EXCEPTION_CAUGHT;
+
+ /**
+ * Process Message return value
+ * Need further processing after WapPushManager message processing
+ */
+ public static final int FURTHER_PROCESSING = WapPushManagerConnector.RESULT_FURTHER_PROCESSING;
+}
diff --git a/core/java/com/android/internal/util/GrowingArrayUtils.java b/core/java/com/android/internal/util/GrowingArrayUtils.java
index 9f563667e019..597fe6b53d11 100644
--- a/core/java/com/android/internal/util/GrowingArrayUtils.java
+++ b/core/java/com/android/internal/util/GrowingArrayUtils.java
@@ -16,7 +16,7 @@
package com.android.internal.util;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* A helper class that aims to provide comparable growth performance to ArrayList, but on primitive
diff --git a/core/java/com/android/internal/util/HexDump.java b/core/java/com/android/internal/util/HexDump.java
index 6ffc92853b08..ad88dd6deec6 100644
--- a/core/java/com/android/internal/util/HexDump.java
+++ b/core/java/com/android/internal/util/HexDump.java
@@ -17,7 +17,7 @@
package com.android.internal.util;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
public class HexDump
{
diff --git a/core/java/com/android/internal/util/IState.java b/core/java/com/android/internal/util/IState.java
index eb66e2ce94d7..07837bf8f587 100644
--- a/core/java/com/android/internal/util/IState.java
+++ b/core/java/com/android/internal/util/IState.java
@@ -16,7 +16,7 @@
package com.android.internal.util;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Message;
/**
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
index 03a555edf4a8..34c6a055d5bd 100644
--- a/core/java/com/android/internal/util/IndentingPrintWriter.java
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -16,7 +16,8 @@
package com.android.internal.util;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Arrays;
diff --git a/core/java/com/android/internal/util/JournaledFile.java b/core/java/com/android/internal/util/JournaledFile.java
index 065cc5b2416b..a9d8f7239d03 100644
--- a/core/java/com/android/internal/util/JournaledFile.java
+++ b/core/java/com/android/internal/util/JournaledFile.java
@@ -16,7 +16,7 @@
package com.android.internal.util;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import java.io.File;
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 580c2fa66de2..5de77d9b0545 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -16,7 +16,7 @@
package com.android.internal.util;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Debug;
import android.os.StrictMode;
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 3fff5c233890..5bc96d8ee1d3 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -18,7 +18,7 @@ package com.android.internal.util;
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.text.TextUtils;
import java.util.Collection;
diff --git a/core/java/com/android/internal/util/State.java b/core/java/com/android/internal/util/State.java
index 3c61e035e886..636378e32091 100644
--- a/core/java/com/android/internal/util/State.java
+++ b/core/java/com/android/internal/util/State.java
@@ -16,7 +16,7 @@
package com.android.internal.util;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Message;
/**
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 6c217e5a37bf..0c2406559dcc 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -16,7 +16,7 @@
package com.android.internal.util;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 8799e3d4c6bf..c1be33a215b8 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -16,10 +16,10 @@
package com.android.internal.util;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
import android.net.Uri;
import android.text.TextUtils;
import android.util.ArrayMap;
diff --git a/core/java/com/android/internal/view/ActionBarPolicy.java b/core/java/com/android/internal/view/ActionBarPolicy.java
index d18c35e703da..d16cb4362f1b 100644
--- a/core/java/com/android/internal/view/ActionBarPolicy.java
+++ b/core/java/com/android/internal/view/ActionBarPolicy.java
@@ -16,15 +16,15 @@
package com.android.internal.view;
-import com.android.internal.R;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build;
+import com.android.internal.R;
+
/**
* Allows components to query for various configuration policy decisions
* about how the action bar should lay out and behave on the current device.
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 2ac2975d0a44..5dd3389b5d4c 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -16,6 +16,7 @@
package com.android.internal.view;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.input.InputManager;
@@ -34,8 +35,6 @@ import android.view.WindowInsets.Type.InsetsType;
import com.android.internal.os.IResultReceiver;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.io.IOException;
public class BaseIWindow extends IWindow.Stub {
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index ececba13c760..6278d4a35329 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -18,7 +18,7 @@ package com.android.internal.view;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index 1b133d2a8393..a5964b509b3c 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -20,7 +20,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 0c057ea6df59..a41048c0f426 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -19,7 +19,7 @@ package com.android.internal.view;
import android.annotation.AnyThread;
import android.annotation.BinderThread;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.inputmethodservice.AbstractInputMethodService;
import android.os.Bundle;
import android.os.Handler;
diff --git a/core/java/com/android/internal/view/WindowManagerPolicyThread.java b/core/java/com/android/internal/view/WindowManagerPolicyThread.java
index b009a2d8ca30..6d691fce4fb0 100644
--- a/core/java/com/android/internal/view/WindowManagerPolicyThread.java
+++ b/core/java/com/android/internal/view/WindowManagerPolicyThread.java
@@ -16,7 +16,7 @@
package com.android.internal.view;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Looper;
/**
diff --git a/core/java/com/android/internal/view/menu/ActionMenu.java b/core/java/com/android/internal/view/menu/ActionMenu.java
index 977c1f6fda7b..648262965ab1 100644
--- a/core/java/com/android/internal/view/menu/ActionMenu.java
+++ b/core/java/com/android/internal/view/menu/ActionMenu.java
@@ -16,10 +16,7 @@
package com.android.internal.view.menu;
-import java.util.ArrayList;
-import java.util.List;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -30,6 +27,9 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* @hide
*/
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index ed253d58fb82..bd8bcb9cf81e 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -17,7 +17,7 @@
package com.android.internal.view.menu;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index eb94db33ba1a..7622b939b6eb 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -16,7 +16,7 @@
package com.android.internal.view.menu;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
diff --git a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
index 3d3aceb4a85f..a9f5e47fc83f 100644
--- a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
@@ -16,7 +16,7 @@
package com.android.internal.view.menu;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.IBinder;
diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java
index 3d888d347d65..539c71e5c473 100644
--- a/core/java/com/android/internal/view/menu/IconMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java
@@ -16,13 +16,12 @@
package com.android.internal.view.menu;
-import com.android.internal.view.menu.MenuBuilder.ItemInvoker;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.text.Layout;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
@@ -30,7 +29,8 @@ import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewDebug;
import android.widget.TextView;
-import android.text.Layout;
+
+import com.android.internal.view.menu.MenuBuilder.ItemInvoker;
/**
* The item view for each item in the {@link IconMenuView}.
diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java
index 6f264341f7b4..9e240dbd8a21 100644
--- a/core/java/com/android/internal/view/menu/IconMenuView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuView.java
@@ -16,9 +16,7 @@
package com.android.internal.view.menu;
-import com.android.internal.view.menu.MenuBuilder.ItemInvoker;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -29,10 +27,12 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
-import android.view.LayoutInflater;
+
+import com.android.internal.view.menu.MenuBuilder.ItemInvoker;
import java.util.ArrayList;
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 0e07ca79faf7..b31ae38b4566 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -18,7 +18,7 @@ package com.android.internal.view.menu;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
diff --git a/core/java/com/android/internal/view/menu/MenuDialogHelper.java b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
index 88d0a03bd55f..d02b8f6ceb63 100644
--- a/core/java/com/android/internal/view/menu/MenuDialogHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
@@ -16,9 +16,9 @@
package com.android.internal.view.menu;
-import android.annotation.UnsupportedAppUsage;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.DialogInterface;
import android.os.IBinder;
import android.view.KeyEvent;
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 994a9c117ce9..218f5185ec47 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -16,10 +16,8 @@
package com.android.internal.view.menu;
-import com.android.internal.view.menu.MenuView.ItemView;
-
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
@@ -39,6 +37,8 @@ import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.widget.LinearLayout;
+import com.android.internal.view.menu.MenuView.ItemView;
+
/**
* @hide
*/
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index d00108edefd0..bac602509148 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -20,7 +20,7 @@ import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
diff --git a/core/java/com/android/internal/view/menu/MenuPresenter.java b/core/java/com/android/internal/view/menu/MenuPresenter.java
index c5df8ad6edc6..35b8fefe75ab 100644
--- a/core/java/com/android/internal/view/menu/MenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/MenuPresenter.java
@@ -18,7 +18,7 @@ package com.android.internal.view.menu;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Parcelable;
import android.view.ViewGroup;
diff --git a/core/java/com/android/internal/view/menu/MenuView.java b/core/java/com/android/internal/view/menu/MenuView.java
index 67a55308938d..a31c820cd2a6 100644
--- a/core/java/com/android/internal/view/menu/MenuView.java
+++ b/core/java/com/android/internal/view/menu/MenuView.java
@@ -16,10 +16,7 @@
package com.android.internal.view.menu;
-import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.view.menu.MenuItemImpl;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.drawable.Drawable;
/**
diff --git a/core/java/com/android/internal/view/menu/SubMenuBuilder.java b/core/java/com/android/internal/view/menu/SubMenuBuilder.java
index cf6d9746bb93..6eb215e94093 100644
--- a/core/java/com/android/internal/view/menu/SubMenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/SubMenuBuilder.java
@@ -16,7 +16,7 @@
package com.android.internal.view.menu;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.Menu;
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index 9ccee7fc32ff..0f0c1a3de3a2 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -15,26 +15,25 @@
*/
package com.android.internal.widget;
-import com.android.internal.R;
-
-import android.util.TypedValue;
-import android.view.ContextThemeWrapper;
-import android.view.MotionEvent;
-import android.widget.ActionMenuPresenter;
-import android.widget.ActionMenuView;
-
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
+import android.widget.ActionMenuPresenter;
+import android.widget.ActionMenuView;
+
+import com.android.internal.R;
public abstract class AbsActionBarView extends ViewGroup {
private static final TimeInterpolator sAlphaInterpolator = new DecelerateInterpolator();
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 78ed53fa918c..051526ef2da7 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -15,13 +15,7 @@
*/
package com.android.internal.widget;
-import com.android.internal.R;
-
-import android.widget.ActionMenuPresenter;
-import android.widget.ActionMenuView;
-import com.android.internal.view.menu.MenuBuilder;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
@@ -32,9 +26,14 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
+import android.widget.ActionMenuPresenter;
+import android.widget.ActionMenuView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.internal.R;
+import com.android.internal.view.menu.MenuBuilder;
+
/**
* @hide
*/
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index e9e3cdab7a10..aca0b713686f 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -18,7 +18,7 @@ package com.android.internal.widget;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -41,6 +41,7 @@ import android.view.Window;
import android.view.WindowInsets;
import android.widget.OverScroller;
import android.widget.Toolbar;
+
import com.android.internal.view.menu.MenuPresenter;
/**
diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java
index 7a0174946671..d879b6d569f3 100644
--- a/core/java/com/android/internal/widget/AlertDialogLayout.java
+++ b/core/java/com/android/internal/widget/AlertDialogLayout.java
@@ -18,8 +18,8 @@ package com.android.internal.widget;
import android.annotation.AttrRes;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
import android.annotation.StyleRes;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
index 0ca67438c5c3..ff131071efef 100644
--- a/core/java/com/android/internal/widget/ButtonBarLayout.java
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index 35bff6d7c430..74ad81566ef4 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -18,7 +18,7 @@ package com.android.internal.widget;
import android.annotation.DrawableRes;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java
index 405436c53ff0..0bfd684317fd 100644
--- a/core/java/com/android/internal/widget/DialogTitle.java
+++ b/core/java/com/android/internal/widget/DialogTitle.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Layout;
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 2b648e90f7dd..ff3543c837eb 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.text.Editable;
import android.text.method.KeyListener;
diff --git a/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java b/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java
index cc7911da0b96..9ef9f697c46c 100644
--- a/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java
+++ b/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java
@@ -16,12 +16,12 @@
package com.android.internal.widget;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.view.View;
import android.view.MotionEvent;
+import android.view.View;
import android.widget.LinearLayout;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 540c43892935..f37a46811b81 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -25,11 +25,11 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
import android.app.admin.DevicePolicyManager;
import android.app.admin.PasswordMetrics;
import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -55,10 +55,10 @@ import android.util.SparseLongArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
-import com.google.android.collect.Lists;
-
import libcore.util.HexEncoding;
+import com.google.android.collect.Lists;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.MessageDigest;
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 74a0aa37dafb..4ddc782aacb4 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -19,7 +19,7 @@ package com.android.internal.widget;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
diff --git a/core/java/com/android/internal/widget/NumericTextView.java b/core/java/com/android/internal/widget/NumericTextView.java
index d2156704a655..c8f901133be6 100644
--- a/core/java/com/android/internal/widget/NumericTextView.java
+++ b/core/java/com/android/internal/widget/NumericTextView.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 37046afaaa85..dc8d57ab709e 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
diff --git a/core/java/com/android/internal/widget/PreferenceImageView.java b/core/java/com/android/internal/widget/PreferenceImageView.java
index 02a0b8d436b9..43b6b5a169c5 100644
--- a/core/java/com/android/internal/widget/PreferenceImageView.java
+++ b/core/java/com/android/internal/widget/PreferenceImageView.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
diff --git a/core/java/com/android/internal/widget/RecyclerView.java b/core/java/com/android/internal/widget/RecyclerView.java
index b66a7b44f05d..43a227a32346 100644
--- a/core/java/com/android/internal/widget/RecyclerView.java
+++ b/core/java/com/android/internal/widget/RecyclerView.java
@@ -20,7 +20,7 @@ import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.Observable;
diff --git a/core/java/com/android/internal/widget/ScrollBarUtils.java b/core/java/com/android/internal/widget/ScrollBarUtils.java
index 982e3152fc7c..3e9d697a0ace 100644
--- a/core/java/com/android/internal/widget/ScrollBarUtils.java
+++ b/core/java/com/android/internal/widget/ScrollBarUtils.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
public class ScrollBarUtils {
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 5d48ab910439..aa0b0bbd4c19 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -15,13 +15,11 @@
*/
package com.android.internal.widget;
-import com.android.internal.view.ActionBarPolicy;
-
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
-import android.annotation.UnsupportedAppUsage;
import android.app.ActionBar;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
@@ -42,6 +40,8 @@ import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
+import com.android.internal.view.ActionBarPolicy;
+
/**
* This widget implements the dynamic action bar tab behavior that can change
* across different configurations or circumstances.
diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java
index 4b5d62467af0..5e6f3a46de7d 100644
--- a/core/java/com/android/internal/widget/SlidingTab.java
+++ b/core/java/com/android/internal/widget/SlidingTab.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -34,12 +34,12 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
import android.view.animation.LinearInterpolator;
import android.view.animation.TranslateAnimation;
-import android.view.animation.Animation.AnimationListener;
import android.widget.ImageView;
-import android.widget.TextView;
import android.widget.ImageView.ScaleType;
+import android.widget.TextView;
import com.android.internal.R;
diff --git a/core/java/com/android/internal/widget/TextViewInputDisabler.java b/core/java/com/android/internal/widget/TextViewInputDisabler.java
index 8d8f0fe52d64..57806eb21dcf 100644
--- a/core/java/com/android/internal/widget/TextViewInputDisabler.java
+++ b/core/java/com/android/internal/widget/TextViewInputDisabler.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.text.InputFilter;
import android.text.Spanned;
import android.widget.TextView;
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
index 7d36b02d4157..c8a86d108134 100644
--- a/core/java/com/android/internal/widget/ViewPager.java
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -18,7 +18,7 @@ package com.android.internal.widget;
import android.annotation.DrawableRes;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
diff --git a/core/java/com/android/server/ResettableTimeout.java b/core/java/com/android/server/ResettableTimeout.java
index 64083f72aff5..511af941bf76 100644
--- a/core/java/com/android/server/ResettableTimeout.java
+++ b/core/java/com/android/server/ResettableTimeout.java
@@ -16,10 +16,9 @@
package com.android.server;
-import android.os.SystemClock;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.ConditionVariable;
+import android.os.SystemClock;
/**
* Utility class that you can call on with a timeout, and get called back
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 8a59c998dacb..74b481c938c3 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -218,6 +218,7 @@ public class SystemConfig {
final ArrayMap<String, ArraySet<String>> mAllowedAssociations = new ArrayMap<>();
private final ArraySet<String> mBugreportWhitelistedPackages = new ArraySet<>();
+ private final ArraySet<String> mAppDataIsolationWhitelistedApps = new ArraySet<>();
// Map of packagesNames to userTypes. Stored temporarily until cleared by UserManagerService().
private ArrayMap<String, Set<String>> mPackageToUserTypeWhitelist = new ArrayMap<>();
@@ -389,6 +390,10 @@ public class SystemConfig {
return mRollbackWhitelistedPackages;
}
+ public ArraySet<String> getAppDataIsolationWhitelistedApps() {
+ return mAppDataIsolationWhitelistedApps;
+ }
+
/**
* Gets map of packagesNames to userTypes, dictating on which user types each package should be
* initially installed, and then removes this map from SystemConfig.
@@ -1045,6 +1050,16 @@ public class SystemConfig {
}
XmlUtils.skipCurrentTag(parser);
} break;
+ case "app-data-isolation-whitelisted-app": {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mAppDataIsolationWhitelistedApps.add(pkgname);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
case "bugreport-whitelisted": {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
index e1a10a5805f5..2a9c0b44b45e 100644
--- a/core/java/com/android/server/net/BaseNetworkObserver.java
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -16,7 +16,7 @@
package com.android.server.net;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.net.INetworkManagementEventObserver;
import android.net.LinkAddress;
import android.net.RouteInfo;
diff --git a/core/java/com/android/server/net/NetlinkTracker.java b/core/java/com/android/server/net/NetlinkTracker.java
index 647fb5b9d079..b57397f46a7e 100644
--- a/core/java/com/android/server/net/NetlinkTracker.java
+++ b/core/java/com/android/server/net/NetlinkTracker.java
@@ -16,7 +16,7 @@
package com.android.server.net;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
diff --git a/core/java/com/google/android/collect/Lists.java b/core/java/com/google/android/collect/Lists.java
index 8f6594aefb0a..585847da566c 100644
--- a/core/java/com/google/android/collect/Lists.java
+++ b/core/java/com/google/android/collect/Lists.java
@@ -16,7 +16,8 @@
package com.google.android.collect;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import java.util.ArrayList;
import java.util.Collections;
diff --git a/core/java/com/google/android/collect/Maps.java b/core/java/com/google/android/collect/Maps.java
index 6ba33207631a..cd4c1280545e 100644
--- a/core/java/com/google/android/collect/Maps.java
+++ b/core/java/com/google/android/collect/Maps.java
@@ -16,7 +16,7 @@
package com.google.android.collect;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import java.util.HashMap;
diff --git a/core/java/com/google/android/collect/Sets.java b/core/java/com/google/android/collect/Sets.java
index 09b5e51ae2c6..c67a88a19080 100644
--- a/core/java/com/google/android/collect/Sets.java
+++ b/core/java/com/google/android/collect/Sets.java
@@ -16,7 +16,7 @@
package com.google.android.collect;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.ArraySet;
import java.util.Collections;
diff --git a/core/java/com/google/android/util/AbstractMessageParser.java b/core/java/com/google/android/util/AbstractMessageParser.java
index f11e6b2342b7..0da7607cba6e 100644
--- a/core/java/com/google/android/util/AbstractMessageParser.java
+++ b/core/java/com/google/android/util/AbstractMessageParser.java
@@ -16,7 +16,7 @@
package com.google.android.util;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/core/java/org/apache/http/conn/ssl/AbstractVerifier.java b/core/java/org/apache/http/conn/ssl/AbstractVerifier.java
index 36d6e22ca847..2848ad7796af 100644
--- a/core/java/org/apache/http/conn/ssl/AbstractVerifier.java
+++ b/core/java/org/apache/http/conn/ssl/AbstractVerifier.java
@@ -31,7 +31,7 @@
package org.apache.http.conn.ssl;
-import java.util.regex.Pattern;
+import android.compat.annotation.UnsupportedAppUsage;
import java.io.IOException;
import java.security.cert.Certificate;
@@ -43,10 +43,10 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
-import java.util.logging.Logger;
import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
-import android.annotation.UnsupportedAppUsage;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
diff --git a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
index b2e8b5e7af05..ffae7570ea79 100644
--- a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
+++ b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
@@ -31,20 +31,14 @@
package org.apache.http.conn.ssl;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Build;
+
import org.apache.http.conn.scheme.HostNameResolver;
import org.apache.http.conn.scheme.LayeredSocketFactory;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
-import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -57,6 +51,14 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+
/**
* Layered socket factory for TLS/SSL connections, based on JSSE.
*.
diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/core/jni/android/graphics/apex/android_bitmap.cpp
index 90cc98699827..0f56779135b8 100644
--- a/core/jni/android/graphics/apex/android_bitmap.cpp
+++ b/core/jni/android/graphics/apex/android_bitmap.cpp
@@ -122,6 +122,99 @@ AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmapHandle) {
return getInfo(bitmap->info(), bitmap->rowBytes());
}
+static bool nearlyEqual(float a, float b) {
+ // By trial and error, this is close enough to match for the ADataSpaces we
+ // compare for.
+ return ::fabs(a-b) < .002f;
+}
+
+static bool nearlyEqual(const skcms_TransferFunction& x, const skcms_TransferFunction& y) {
+ return nearlyEqual(x.g, y.g)
+ && nearlyEqual(x.a, y.a)
+ && nearlyEqual(x.b, y.b)
+ && nearlyEqual(x.c, y.c)
+ && nearlyEqual(x.d, y.d)
+ && nearlyEqual(x.e, y.e)
+ && nearlyEqual(x.f, y.f);
+}
+
+static bool nearlyEqual(const skcms_Matrix3x3& x, const skcms_Matrix3x3& y) {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (!nearlyEqual(x.vals[i][j], y.vals[i][j])) return false;
+ }
+ }
+ return true;
+}
+
+static constexpr skcms_TransferFunction k2Dot6 =
+ { 2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+
+// Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut
+// matches the white point used by ColorSpace.Named.DCIP3.
+static constexpr skcms_Matrix3x3 kDCIP3 = {{
+ { 0.486143, 0.323835, 0.154234 },
+ { 0.226676, 0.710327, 0.0629966 },
+ { 0.000800549, 0.0432385, 0.78275 },
+}};
+
+ADataSpace ABitmap_getDataSpace(ABitmap* bitmapHandle) {
+ Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle);
+ const SkImageInfo& info = bitmap->info();
+ SkColorSpace* colorSpace = info.colorSpace();
+ if (!colorSpace) {
+ return ADATASPACE_UNKNOWN;
+ }
+
+ if (colorSpace->isSRGB()) {
+ if (info.colorType() == kRGBA_F16_SkColorType) {
+ return ADATASPACE_SCRGB;
+ }
+ return ADATASPACE_SRGB;
+ }
+
+ skcms_TransferFunction fn;
+ LOG_ALWAYS_FATAL_IF(!colorSpace->isNumericalTransferFn(&fn));
+
+ skcms_Matrix3x3 gamut;
+ LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&gamut));
+
+ if (nearlyEqual(gamut, SkNamedGamut::kSRGB)) {
+ if (nearlyEqual(fn, SkNamedTransferFn::kLinear)) {
+ // Skia doesn't differentiate amongst the RANGES. In Java, we associate
+ // LINEAR_EXTENDED_SRGB with F16, and LINEAR_SRGB with other Configs.
+ // Make the same association here.
+ if (info.colorType() == kRGBA_F16_SkColorType) {
+ return ADATASPACE_SCRGB_LINEAR;
+ }
+ return ADATASPACE_SRGB_LINEAR;
+ }
+
+ if (nearlyEqual(fn, SkNamedTransferFn::kRec2020)) {
+ return ADATASPACE_BT709;
+ }
+ }
+
+ if (nearlyEqual(fn, SkNamedTransferFn::kSRGB) && nearlyEqual(gamut, SkNamedGamut::kDCIP3)) {
+ return ADATASPACE_DISPLAY_P3;
+ }
+
+ if (nearlyEqual(fn, SkNamedTransferFn::k2Dot2) && nearlyEqual(gamut, SkNamedGamut::kAdobeRGB)) {
+ return ADATASPACE_ADOBE_RGB;
+ }
+
+ if (nearlyEqual(fn, SkNamedTransferFn::kRec2020)
+ && nearlyEqual(gamut, SkNamedGamut::kRec2020)) {
+ return ADATASPACE_BT2020;
+ }
+
+ if (nearlyEqual(fn, k2Dot6) && nearlyEqual(gamut, kDCIP3)) {
+ return ADATASPACE_DCI_P3;
+ }
+
+ return ADATASPACE_UNKNOWN;
+}
+
AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj) {
uint32_t rowBytes = 0;
SkImageInfo imageInfo = GraphicsJNI::getBitmapInfo(env, bitmapObj, &rowBytes);
diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
index f231eeddb7e2..32b8a450e147 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
+++ b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
@@ -17,6 +17,7 @@
#define ANDROID_GRAPHICS_BITMAP_H
#include <android/bitmap.h>
+#include <android/data_space.h>
#include <jni.h>
#include <sys/cdefs.h>
@@ -49,6 +50,7 @@ void ABitmap_acquireRef(ABitmap* bitmap);
void ABitmap_releaseRef(ABitmap* bitmap);
AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmap);
+ADataSpace ABitmap_getDataSpace(ABitmap* bitmap);
void* ABitmap_getPixels(ABitmap* bitmap);
void ABitmap_notifyPixelsChanged(ABitmap* bitmap);
@@ -106,6 +108,7 @@ namespace graphics {
ABitmap* get() const { return mBitmap; }
AndroidBitmapInfo getInfo() const { return ABitmap_getInfo(mBitmap); }
+ ADataSpace getDataSpace() const { return ABitmap_getDataSpace(mBitmap); }
void* getPixels() const { return ABitmap_getPixels(mBitmap); }
void notifyPixelsChanged() const { ABitmap_notifyPixelsChanged(mBitmap); }
@@ -119,4 +122,4 @@ namespace graphics {
}; // namespace android
#endif // __cplusplus
-#endif // ANDROID_GRAPHICS_BITMAP_H \ No newline at end of file
+#endif // ANDROID_GRAPHICS_BITMAP_H
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d17d0a4ebbe2..5039213954d7 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -319,7 +319,8 @@ enum MountExternalKind {
MOUNT_EXTERNAL_INSTALLER = 5,
MOUNT_EXTERNAL_FULL = 6,
MOUNT_EXTERNAL_PASS_THROUGH = 7,
- MOUNT_EXTERNAL_COUNT = 8
+ MOUNT_EXTERNAL_ANDROID_WRITABLE = 8,
+ MOUNT_EXTERNAL_COUNT = 9
};
// The order of entries here must be kept in sync with MountExternalKind enum values.
@@ -331,6 +332,8 @@ static const std::array<const std::string, MOUNT_EXTERNAL_COUNT> ExternalStorage
"/mnt/runtime/write", // MOUNT_EXTERNAL_LEGACY
"/mnt/runtime/write", // MOUNT_EXTERNAL_INSTALLER
"/mnt/runtime/full", // MOUNT_EXTERNAL_FULL
+ "/mnt/runtime/full", // MOUNT_EXTERNAL_PASS_THROUGH (only used w/ FUSE)
+ "/mnt/runtime/full", // MOUNT_EXTERNAL_ANDROID_WRITABLE (only used w/ FUSE)
};
// Must match values in com.android.internal.os.Zygote.
@@ -755,12 +758,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode,
multiuser_get_uid(user_id, AID_EVERYBODY), fail_fn);
if (isFuse) {
- if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH || mount_mode ==
- MOUNT_EXTERNAL_INSTALLER || mount_mode == MOUNT_EXTERNAL_FULL) {
- // For now, MediaProvider, installers and "full" get the pass_through mount
- // view, which is currently identical to the sdcardfs write view.
- //
- // TODO(b/146189163): scope down MOUNT_EXTERNAL_INSTALLER
+ if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
BindMount(pass_through_source, "/storage", fail_fn);
} else {
BindMount(user_source, "/storage", fail_fn);
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 5624f457a9b2..082a2892e34b 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -33,27 +33,27 @@
// Static whitelist of open paths that the zygote is allowed to keep open.
static const char* kPathWhitelist[] = {
- "/apex/com.android.appsearch/javalib/framework-appsearch.jar",
- "/apex/com.android.conscrypt/javalib/conscrypt.jar",
- "/apex/com.android.ipsec/javalib/ike.jar",
- "/apex/com.android.media/javalib/updatable-media.jar",
- "/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar",
- "/apex/com.android.os.statsd/javalib/framework-statsd.jar",
- "/apex/com.android.sdkext/javalib/framework-sdkext.jar",
- "/apex/com.android.wifi/javalib/framework-wifi.jar",
- "/apex/com.android.tethering/javalib/framework-tethering.jar",
- "/dev/null",
- "/dev/socket/zygote",
- "/dev/socket/zygote_secondary",
- "/dev/socket/usap_pool_primary",
- "/dev/socket/usap_pool_secondary",
- "/dev/socket/webview_zygote",
- "/dev/socket/heapprofd",
- "/sys/kernel/debug/tracing/trace_marker",
- "/system/framework/framework-res.apk",
- "/dev/urandom",
- "/dev/ion",
- "/dev/dri/renderD129", // Fixes b/31172436
+ "/apex/com.android.appsearch/javalib/framework-appsearch.jar",
+ "/apex/com.android.conscrypt/javalib/conscrypt.jar",
+ "/apex/com.android.ipsec/javalib/ike.jar",
+ "/apex/com.android.media/javalib/updatable-media.jar",
+ "/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar",
+ "/apex/com.android.os.statsd/javalib/framework-statsd.jar",
+ "/apex/com.android.sdkext/javalib/framework-sdkextensions.jar",
+ "/apex/com.android.wifi/javalib/framework-wifi.jar",
+ "/apex/com.android.tethering/javalib/framework-tethering.jar",
+ "/dev/null",
+ "/dev/socket/zygote",
+ "/dev/socket/zygote_secondary",
+ "/dev/socket/usap_pool_primary",
+ "/dev/socket/usap_pool_secondary",
+ "/dev/socket/webview_zygote",
+ "/dev/socket/heapprofd",
+ "/sys/kernel/debug/tracing/trace_marker",
+ "/system/framework/framework-res.apk",
+ "/dev/urandom",
+ "/dev/ion",
+ "/dev/dri/renderD129", // Fixes b/31172436
};
static const char kFdPath[] = "/proc/self/fd";
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index d5a3b5e91151..b83b31c1303a 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -702,6 +702,12 @@ enum Action {
// CATEGORY: SETTINGS
// OS: R
ACTION_DASHBOARD_VISIBLE_TIME = 1729;
+
+ // ACTION: Allow "Access all files" for an app
+ APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_ALLOW = 1730;
+
+ // ACTION: Deny "Access all files" for an app
+ APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_DENY = 1731;
}
/**
@@ -2542,4 +2548,9 @@ enum PageId {
// OS: R
FUELGAUGE_BATTERY_SHARE = 1821;
+ // OPEN: Settings -> Apps & Notifications -> Special App Access
+ // CATEGORY: SETTINGS
+ // OS: R
+ MANAGE_EXTERNAL_STORAGE = 1822;
+
}
diff --git a/core/proto/android/server/animationadapter.proto b/core/proto/android/server/animationadapter.proto
index 70627edf2cb3..c6925f448a58 100644
--- a/core/proto/android/server/animationadapter.proto
+++ b/core/proto/android/server/animationadapter.proto
@@ -50,6 +50,7 @@ message AnimationSpecProto {
optional WindowAnimationSpecProto window = 1;
optional MoveAnimationSpecProto move = 2;
optional AlphaAnimationSpecProto alpha = 3;
+ optional RotationAnimationSpecProto rotate = 4;
}
/* represents WindowAnimationSpec */
@@ -76,3 +77,12 @@ message AlphaAnimationSpecProto {
optional float to = 2;
optional int64 duration_ms = 3;
}
+
+/* represents RotationAnimationSpec */
+message RotationAnimationSpecProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional float start_luma = 1;
+ optional float end_luma = 2;
+ optional int64 duration_ms = 3;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 31faff6bd314..03d34b595e4a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -456,7 +456,6 @@
<protected-broadcast android:name="android.intent.action.internal_sim_state_changed" />
<protected-broadcast android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<protected-broadcast android:name="android.intent.action.PRECISE_CALL_STATE" />
- <protected-broadcast android:name="android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.intent.action.SUBSCRIPTION_PHONE_STATE" />
<protected-broadcast android:name="android.intent.action.USER_INFO_CHANGED" />
<protected-broadcast android:name="android.intent.action.USER_UNLOCKED" />
@@ -934,11 +933,10 @@
<!-- Allows an application a broad access to external storage in scoped storage.
Intended to be used by few apps that need to manage files on behalf of the users.
- <p>Protection level: signature|appop
- <p>This protection level is temporary and will most likely be changed to |preinstalled -->
+ <p>Protection level: signature|appop|preinstalled -->
<permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
android:permissionGroup="android.permission-group.UNDEFINED"
- android:protectionLevel="signature|appop" />
+ android:protectionLevel="signature|appop|preinstalled" />
<!-- ====================================================================== -->
<!-- Permissions for accessing the device location -->
@@ -1656,6 +1654,7 @@
<!-- Allows holder to request bluetooth/wifi scan bypassing global "use location" setting and
location permissions.
<p>Not for use by third-party or privileged applications.
+ @SystemApi
@hide
-->
<permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"
@@ -4757,6 +4756,10 @@
<!-- Allows input events to be monitored. Very dangerous! @hide -->
<permission android:name="android.permission.MONITOR_INPUT"
android:protectionLevel="signature" />
+ <!-- Allows the caller to change the associations between input devices and displays.
+ Very dangerous! @hide -->
+ <permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT"
+ android:protectionLevel="signature" />
<!-- Allows query of any normal app on the device, regardless of manifest declarations. -->
<permission android:name="android.permission.QUERY_ALL_PACKAGES"
diff --git a/core/res/res/anim/screen_rotate_0_enter.xml b/core/res/res/anim/screen_rotate_0_enter.xml
index 93cf3652d185..629be7ea2d30 100644
--- a/core/res/res/anim/screen_rotate_0_enter.xml
+++ b/core/res/res/anim/screen_rotate_0_enter.xml
@@ -1,25 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/*
-** Copyright 2010, 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.
-*/
--->
+ ~ 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.
+ -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_shortAnimTime" />
+ android:shareInterpolator="false">
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:interpolator="@interpolator/screen_rotation_alpha_in"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_screen_rotation_fade_in" />
</set>
diff --git a/core/res/res/anim/screen_rotate_0_exit.xml b/core/res/res/anim/screen_rotate_0_exit.xml
index 37d5a4115621..fa046a036855 100644
--- a/core/res/res/anim/screen_rotate_0_exit.xml
+++ b/core/res/res/anim/screen_rotate_0_exit.xml
@@ -1,22 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/*
-** Copyright 2010, 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.
-*/
--->
+ ~ 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.
+ -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
+ android:shareInterpolator="false">
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/anim/screen_rotate_0_frame.xml b/core/res/res/anim/screen_rotate_0_frame.xml
deleted file mode 100644
index 5ea9bf8205e3..000000000000
--- a/core/res/res/anim/screen_rotate_0_frame.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_shortAnimTime" />
-</set>
diff --git a/core/res/res/anim/screen_rotate_180_enter.xml b/core/res/res/anim/screen_rotate_180_enter.xml
index 688a8d5bb2aa..889a615e07f4 100644
--- a/core/res/res/anim/screen_rotate_180_enter.xml
+++ b/core/res/res/anim/screen_rotate_180_enter.xml
@@ -18,11 +18,11 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
+ android:shareInterpolator="false">
<rotate android:fromDegrees="180" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_180" />
</set>
diff --git a/core/res/res/anim/screen_rotate_180_exit.xml b/core/res/res/anim/screen_rotate_180_exit.xml
index 58a1868bd398..766fcfae1f91 100644
--- a/core/res/res/anim/screen_rotate_180_exit.xml
+++ b/core/res/res/anim/screen_rotate_180_exit.xml
@@ -18,11 +18,11 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
+ android:shareInterpolator="false">
<rotate android:fromDegrees="0" android:toDegrees="-180"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_180" />
</set> \ No newline at end of file
diff --git a/core/res/res/anim/screen_rotate_alpha.xml b/core/res/res/anim/screen_rotate_alpha.xml
index c49ef9cafd39..2cac982e24b4 100644
--- a/core/res/res/anim/screen_rotate_alpha.xml
+++ b/core/res/res/anim/screen_rotate_alpha.xml
@@ -20,8 +20,8 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:interpolator="@interpolator/decelerate_quint"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_enter.xml b/core/res/res/anim/screen_rotate_minus_90_enter.xml
index b16d5fc761ee..87fd25ea4603 100644
--- a/core/res/res/anim/screen_rotate_minus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_enter.xml
@@ -18,19 +18,17 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase anim
+ android:shareInterpolator="false">
<rotate android:fromDegrees="-90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <rotate android:fromDegrees="-90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/screen_rotation_alpha_in"
+ android:startOffset="@android:integer/config_screen_rotation_fade_in_delay"
+ android:duration="@android:integer/config_screen_rotation_fade_in" />
</set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_exit.xml b/core/res/res/anim/screen_rotate_minus_90_exit.xml
index 0927dd30ceb3..c3aee14dc235 100644
--- a/core/res/res/anim/screen_rotate_minus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_exit.xml
@@ -18,26 +18,16 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase animation
+ android:shareInterpolator="false">
<rotate android:fromDegrees="0" android:toDegrees="90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <scale android:fromXScale="100%" android:toXScale="100%p"
- android:fromYScale="100%" android:toYScale="100%p"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
- <rotate android:fromDegrees="0" android:toDegrees="90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_enter.xml b/core/res/res/anim/screen_rotate_plus_90_enter.xml
index 86a8d24cbbcc..8849db421e75 100644
--- a/core/res/res/anim/screen_rotate_plus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_enter.xml
@@ -18,19 +18,16 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase animation
+ android:shareInterpolator="false">
<rotate android:fromDegrees="90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <rotate android:fromDegrees="90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:interpolator="@interpolator/screen_rotation_alpha_in"
+ android:startOffset="@android:integer/config_screen_rotation_fade_in_delay"
+ android:duration="@android:integer/config_screen_rotation_fade_in" />
</set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_exit.xml b/core/res/res/anim/screen_rotate_plus_90_exit.xml
index fd786f9afce0..de84c3bd08fc 100644
--- a/core/res/res/anim/screen_rotate_plus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_exit.xml
@@ -18,26 +18,16 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase animation
+ android:shareInterpolator="false">
<rotate android:fromDegrees="0" android:toDegrees="-90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <scale android:fromXScale="100%" android:toXScale="100%p"
- android:fromYScale="100%" android:toYScale="100%p"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
- <rotate android:fromDegrees="0" android:toDegrees="-90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/interpolator/screen_rotation_alpha_in.xml b/core/res/res/interpolator/screen_rotation_alpha_in.xml
new file mode 100644
index 000000000000..9c566a7c8f23
--- /dev/null
+++ b/core/res/res/interpolator/screen_rotation_alpha_in.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.15"
+ android:controlY1="0.45"
+ android:controlX2="0.33"
+ android:controlY2="1"/>
diff --git a/core/res/res/interpolator/screen_rotation_alpha_out.xml b/core/res/res/interpolator/screen_rotation_alpha_out.xml
new file mode 100644
index 000000000000..73a37d4f1aa5
--- /dev/null
+++ b/core/res/res/interpolator/screen_rotation_alpha_out.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.57"
+ android:controlY1="0"
+ android:controlX2="0.71"
+ android:controlY2=".43"/>
diff --git a/core/res/res/layout/accessibility_button_chooser_item.xml b/core/res/res/layout/accessibility_button_chooser_item.xml
index 1edd2cdfcfe3..d19e313055ae 100644
--- a/core/res/res/layout/accessibility_button_chooser_item.xml
+++ b/core/res/res/layout/accessibility_button_chooser_item.xml
@@ -36,7 +36,7 @@
android:id="@+id/accessibility_button_target_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
+ android:layout_marginStart="14dp"
android:layout_weight="1"
android:textColor="?attr/textColorPrimary"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6691d4c5955b..245aed1484f7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -147,6 +147,24 @@
<integer name="config_activityShortDur">150</integer>
<integer name="config_activityDefaultDur">220</integer>
+ <!-- Fade out time for screen rotation -->
+ <integer name="config_screen_rotation_fade_out">116</integer>
+
+ <!-- Fade in time for screen rotation -->
+ <integer name="config_screen_rotation_fade_in">233</integer>
+
+ <!-- Fade in delay time for screen rotation -->
+ <integer name="config_screen_rotation_fade_in_delay">100</integer>
+
+ <!-- Total time for 90 degree screen rotation animations -->
+ <integer name="config_screen_rotation_total_90">333</integer>
+
+ <!-- Total time for 180 degree screen rotation animation -->
+ <integer name="config_screen_rotation_total_180">433</integer>
+
+ <!-- Total time for the rotation background color transition -->
+ <integer name="config_screen_rotation_color_transition">200</integer>
+
<!-- The duration (in milliseconds) of the tooltip show/hide animations. -->
<integer name="config_tooltipAnimTime">150</integer>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 66267d136e10..a0e40646ead9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4358,10 +4358,7 @@
<string name="accessibility_shortcut_menu_button">Empty</string>
<!-- Text in button that edit the accessibility shortcut menu. [CHAR LIMIT=100] -->
- <string name="edit_accessibility_shortcut_menu_button">Edit</string>
-
- <!-- Text in button that save the accessibility shortcut menu changed status. [CHAR LIMIT=100] -->
- <string name="save_accessibility_shortcut_menu_button">Save</string>
+ <string name="edit_accessibility_shortcut_menu_button">Edit shortcuts</string>
<!-- Text in button that cancel the accessibility shortcut menu changed status. [CHAR LIMIT=100] -->
<string name="cancel_accessibility_shortcut_menu_button">Cancel</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 01bd510dcf27..973d5f6392f4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1805,7 +1805,6 @@
<!-- From services -->
<java-symbol type="anim" name="screen_rotate_0_enter" />
<java-symbol type="anim" name="screen_rotate_0_exit" />
- <java-symbol type="anim" name="screen_rotate_0_frame" />
<java-symbol type="anim" name="screen_rotate_180_enter" />
<java-symbol type="anim" name="screen_rotate_180_exit" />
<java-symbol type="anim" name="screen_rotate_180_frame" />
@@ -1981,6 +1980,7 @@
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
<java-symbol type="integer" name="config_brightness_ramp_rate_fast" />
<java-symbol type="integer" name="config_brightness_ramp_rate_slow" />
+ <java-symbol type="integer" name="config_screen_rotation_color_transition" />
<java-symbol type="layout" name="am_compat_mode_dialog" />
<java-symbol type="layout" name="launch_warning" />
<java-symbol type="layout" name="safe_mode" />
@@ -3212,7 +3212,6 @@
<java-symbol type="id" name="accessibility_button_target_switch_item" />
<java-symbol type="string" name="accessibility_magnification_chooser_text" />
<java-symbol type="string" name="edit_accessibility_shortcut_menu_button" />
- <java-symbol type="string" name="save_accessibility_shortcut_menu_button" />
<java-symbol type="string" name="cancel_accessibility_shortcut_menu_button" />
<java-symbol type="drawable" name="ic_accessibility_magnification" />
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java
index f0a83678f70b..a296ca27e268 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java
@@ -16,6 +16,7 @@
package com.android.connectivitymanagertest;
+import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
import android.net.LinkAddress;
@@ -136,7 +137,7 @@ public class WifiConfigurationHelper {
config.enterpriseConfig.setPhase2Method(phase2);
config.enterpriseConfig.setIdentity(identity);
config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
- config.enterpriseConfig.setCaCertificateAlias(caCert);
+ config.enterpriseConfig.setCaCertificateAliases(new String[] {caCert});
config.enterpriseConfig.setClientCertificateAlias(clientCert);
return config;
}
@@ -147,8 +148,12 @@ public class WifiConfigurationHelper {
private static WifiConfiguration createGenericConfig(String ssid) {
WifiConfiguration config = new WifiConfiguration();
config.SSID = quotedString(ssid);
- config.setIpAssignment(IpAssignment.DHCP);
- config.setProxySettings(ProxySettings.NONE);
+
+ IpConfiguration ipConfiguration = config.getIpConfiguration();
+ ipConfiguration.setIpAssignment(IpAssignment.DHCP);
+ ipConfiguration.setProxySettings(ProxySettings.NONE);
+ config.setIpConfiguration(ipConfiguration);
+
return config;
}
@@ -237,6 +242,7 @@ public class WifiConfigurationHelper {
throw new IllegalArgumentException();
}
+ IpConfiguration ipConfiguration = config.getIpConfiguration();
if (jsonConfig.has("ip")) {
StaticIpConfiguration staticIpConfig = new StaticIpConfiguration();
@@ -247,13 +253,14 @@ public class WifiConfigurationHelper {
staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns1")));
staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns2")));
- config.setIpAssignment(IpAssignment.STATIC);
- config.setStaticIpConfiguration(staticIpConfig);
+ ipConfiguration.setIpAssignment(IpAssignment.STATIC);
+ ipConfiguration.setStaticIpConfiguration(staticIpConfig);
} else {
- config.setIpAssignment(IpAssignment.DHCP);
+ ipConfiguration.setIpAssignment(IpAssignment.DHCP);
}
+ ipConfiguration.setProxySettings(ProxySettings.NONE);
+ config.setIpConfiguration(ipConfiguration);
- config.setProxySettings(ProxySettings.NONE);
return config;
}
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index 2989df83866c..5d42915fc82b 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -268,7 +268,7 @@ public class BandwidthTest extends InstrumentationTestCase {
File snd_stat = new File (root_filepath + "tcp_snd");
int tx = BandwidthTestUtil.parseIntValueFromFile(snd_stat);
NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
- stats.addValues(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT,
+ stats.addEntry(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT,
NetworkStats.TAG_NONE, rx, 0, tx, 0, 0);
return stats;
}
diff --git a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java
index 707d7b30e09b..239f971664e9 100644
--- a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java
+++ b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java
@@ -54,7 +54,7 @@ public class NetworkStatsBenchmark {
recycle.txBytes = 150000;
recycle.txPackets = 1500;
recycle.operations = 0;
- mNetworkStats.addValues(recycle);
+ mNetworkStats.addEntry(recycle);
if (recycle.set == 1) {
uid++;
}
@@ -70,7 +70,7 @@ public class NetworkStatsBenchmark {
recycle.txBytes = 180000 * mSize;
recycle.txPackets = 1200 * mSize;
recycle.operations = 0;
- mNetworkStats.addValues(recycle);
+ mNetworkStats.addEntry(recycle);
}
}
diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
index 68b9b0079761..f4709ff0bc00 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
@@ -33,14 +33,15 @@ import android.os.ParcelFileDescriptor.AutoCloseInputStream;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.support.test.uiautomator.UiDevice;
import android.test.InstrumentationTestCase;
import android.util.Log;
-import libcore.io.Streams;
-
import com.google.mockwebserver.MockResponse;
import com.google.mockwebserver.MockWebServer;
+import libcore.io.Streams;
+
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
@@ -63,6 +64,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase {
private static final String TAG = "DownloadManagerBaseTest";
protected DownloadManager mDownloadManager = null;
private MockWebServer mServer = null;
+ private UiDevice mUiDevice = null;
protected String mFileType = "text/plain";
protected Context mContext = null;
protected MultipleDownloadsCompletedReceiver mReceiver = null;
@@ -234,6 +236,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase {
@Override
public void setUp() throws Exception {
mContext = getInstrumentation().getContext();
+ mUiDevice = UiDevice.getInstance(getInstrumentation());
mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE);
mServer = new MockWebServer();
mServer.play();
@@ -512,7 +515,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase {
Log.i(LOG_TAG, "Setting WiFi State to: " + enable);
WifiManager manager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
- manager.setWifiEnabled(enable);
+ mUiDevice.executeShellCommand("svc wifi " + (enable ? "enable" : "disable"));
String timeoutMessage = "Timed out waiting for Wifi to be "
+ (enable ? "enabled!" : "disabled!");
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index beaaa373b1a0..d8b527c8a11a 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -438,8 +438,7 @@ public class ActivityThreadTest {
}
private static ClientTransaction newStopTransaction(Activity activity) {
- final StopActivityItem stopStateRequest =
- StopActivityItem.obtain(false /* showWindow */, 0 /* configChanges */);
+ final StopActivityItem stopStateRequest = StopActivityItem.obtain(0 /* configChanges */);
final ClientTransaction transaction = newTransaction(activity);
transaction.setLifecycleStateRequest(stopStateRequest);
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 37d21f0928be..4b29d59de332 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -274,30 +274,15 @@ public class ObjectPoolTests {
@Test
public void testRecycleStopItem() {
- StopActivityItem emptyItem = StopActivityItem.obtain(false, 0);
- StopActivityItem item = StopActivityItem.obtain(true, 4);
+ StopActivityItem emptyItem = StopActivityItem.obtain(0);
+ StopActivityItem item = StopActivityItem.obtain(4);
assertNotSame(item, emptyItem);
assertFalse(item.equals(emptyItem));
item.recycle();
assertEquals(item, emptyItem);
- StopActivityItem item2 = StopActivityItem.obtain(true, 3);
- assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
- }
-
- @Test
- public void testRecycleWindowVisibleItem() {
- WindowVisibilityItem emptyItem = WindowVisibilityItem.obtain(false);
- WindowVisibilityItem item = WindowVisibilityItem.obtain(true);
- assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
-
- item.recycle();
- assertEquals(item, emptyItem);
-
- WindowVisibilityItem item2 = WindowVisibilityItem.obtain(true);
+ StopActivityItem item2 = StopActivityItem.obtain(3);
assertSame(item, item2);
assertFalse(item2.equals(emptyItem));
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 39bf7421b15e..ecea9011e704 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -61,6 +61,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -180,31 +181,6 @@ public class TransactionParcelTests {
}
@Test
- public void testWindowVisibilityChange() {
- // Write to parcel
- WindowVisibilityItem item = WindowVisibilityItem.obtain(true /* showWindow */);
- writeAndPrepareForReading(item);
-
- // Read from parcel and assert
- WindowVisibilityItem result = WindowVisibilityItem.CREATOR.createFromParcel(mParcel);
-
- assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
-
- // Check different value
- item = WindowVisibilityItem.obtain(false);
-
- mParcel = Parcel.obtain();
- writeAndPrepareForReading(item);
-
- // Read from parcel and assert
- result = WindowVisibilityItem.CREATOR.createFromParcel(mParcel);
-
- assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
- }
-
- @Test
public void testDestroy() {
DestroyActivityItem item = DestroyActivityItem.obtain(true /* finished */,
135 /* configChanges */);
@@ -299,8 +275,7 @@ public class TransactionParcelTests {
@Test
public void testStop() {
// Write to parcel
- StopActivityItem item = StopActivityItem.obtain(true /* showWindow */,
- 14 /* configChanges */);
+ StopActivityItem item = StopActivityItem.obtain(14 /* configChanges */);
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -311,14 +286,26 @@ public class TransactionParcelTests {
}
@Test
+ public void testStart() {
+ // Write to parcel
+ StartActivityItem item = StartActivityItem.obtain();
+ writeAndPrepareForReading(item);
+
+ // Read from parcel and assert
+ StartActivityItem result = StartActivityItem.CREATOR.createFromParcel(mParcel);
+
+ assertEquals(item.hashCode(), result.hashCode());
+ assertEquals(item, result);
+ }
+
+ @Test
public void testClientTransaction() {
// Write to parcel
- WindowVisibilityItem callback1 = WindowVisibilityItem.obtain(true);
+ NewIntentItem callback1 = NewIntentItem.obtain(new ArrayList<>(), true);
ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
config());
- StopActivityItem lifecycleRequest = StopActivityItem.obtain(true /* showWindow */,
- 78 /* configChanges */);
+ StopActivityItem lifecycleRequest = StopActivityItem.obtain(78 /* configChanges */);
IApplicationThread appThread = new StubAppThread();
Binder activityToken = new Binder();
@@ -340,7 +327,7 @@ public class TransactionParcelTests {
@Test
public void testClientTransactionCallbacksOnly() {
// Write to parcel
- WindowVisibilityItem callback1 = WindowVisibilityItem.obtain(true);
+ NewIntentItem callback1 = NewIntentItem.obtain(new ArrayList<>(), true);
ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
config());
@@ -363,8 +350,7 @@ public class TransactionParcelTests {
@Test
public void testClientTransactionLifecycleOnly() {
// Write to parcel
- StopActivityItem lifecycleRequest = StopActivityItem.obtain(true /* showWindow */,
- 78 /* configChanges */);
+ StopActivityItem lifecycleRequest = StopActivityItem.obtain(78 /* configChanges */);
IApplicationThread appThread = new StubAppThread();
Binder activityToken = new Binder();
diff --git a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
index de6f8f7231fa..750ffa1c9a54 100644
--- a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
@@ -22,7 +22,7 @@ import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcel
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
index 9b3d0c9eaff6..b88c36f20bc6 100644
--- a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
@@ -22,7 +22,7 @@ import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcel
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
index bee270e5f5c9..ba29a97b55ab 100644
--- a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
@@ -22,7 +22,7 @@ import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcel
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/util/TimestampedValueTest.java b/core/tests/coretests/src/android/os/TimestampedValueTest.java
index 6fc2400316c2..f36d9e6b1eff 100644
--- a/core/tests/coretests/src/android/util/TimestampedValueTest.java
+++ b/core/tests/coretests/src/android/os/TimestampedValueTest.java
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package android.util;
+package android.os;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
-import android.os.Parcel;
-
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 0e19ca84d433..d0fd92a838c9 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -90,12 +90,12 @@ public class ImeInsetsSourceConsumerTest {
mImeConsumer.onWindowFocusGained();
mImeConsumer.applyImeVisibility(true);
mController.cancelExistingAnimation();
- assertTrue(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test if setVisibility can hide IME
mImeConsumer.applyImeVisibility(false);
mController.cancelExistingAnimation();
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
});
}
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 179929f2aae0..fa61a0a0250b 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -16,11 +16,11 @@
package android.view;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowInsets.Type.systemBars;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -39,8 +39,6 @@ import android.view.SurfaceControl.Transaction;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.test.InsetsModeSession;
-import androidx.test.runner.AndroidJUnit4;
-
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -52,6 +50,8 @@ import org.mockito.MockitoAnnotations;
import java.util.List;
+import androidx.test.runner.AndroidJUnit4;
+
/**
* Tests for {@link InsetsAnimationControlImpl}.
*
@@ -116,7 +116,7 @@ public class InsetsAnimationControlImplTest {
mController = new InsetsAnimationControlImpl(controls,
new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
mMockController, 10 /* durationMs */,
- false /* fade */);
+ false /* fade */, LAYOUT_INSETS_DURING_ANIMATION_SHOWN);
}
@Test
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index a89fc1e6315f..1db96b15f83a 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -68,6 +68,7 @@ public class InsetsControllerTest {
private InsetsController mController;
private SurfaceSession mSession = new SurfaceSession();
private SurfaceControl mLeash;
+ private ViewRootImpl mViewRoot;
@Before
public void setup() {
@@ -77,13 +78,13 @@ public class InsetsControllerTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
Context context = InstrumentationRegistry.getTargetContext();
// cannot mock ViewRootImpl since it's final.
- ViewRootImpl viewRootImpl = new ViewRootImpl(context, context.getDisplay());
+ mViewRoot = new ViewRootImpl(context, context.getDisplay());
try {
- viewRootImpl.setView(new TextView(context), new LayoutParams(), null);
+ mViewRoot.setView(new TextView(context), new LayoutParams(), null);
} catch (BadTokenException e) {
// activity isn't running, we will ignore BadTokenException.
}
- mController = new InsetsController(viewRootImpl);
+ mController = new InsetsController(mViewRoot);
final Rect rect = new Rect(5, 5, 5, 5);
mController.calculateInsets(
false,
@@ -117,16 +118,22 @@ public class InsetsControllerTest {
@Test
public void testControlsRevoked_duringAnim() {
- InsetsSourceControl control =
- new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
- mController.onControlsChanged(new InsetsSourceControl[] { control });
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ InsetsSourceControl control =
+ new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
+ mController.onControlsChanged(new InsetsSourceControl[] { control });
- WindowInsetsAnimationControlListener mockListener =
- mock(WindowInsetsAnimationControlListener.class);
- mController.controlWindowInsetsAnimation(statusBars(), 10 /* durationMs */, mockListener);
- verify(mockListener).onReady(any(), anyInt());
- mController.onControlsChanged(new InsetsSourceControl[0]);
- verify(mockListener).onCancelled();
+ WindowInsetsAnimationControlListener mockListener =
+ mock(WindowInsetsAnimationControlListener.class);
+ mController.controlWindowInsetsAnimation(statusBars(), 10 /* durationMs */,
+ mockListener);
+
+ // Ready gets deferred until next predraw
+ mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
+ verify(mockListener).onReady(any(), anyInt());
+ mController.onControlsChanged(new InsetsSourceControl[0]);
+ verify(mockListener).onCancelled();
+ });
}
@Test
@@ -154,16 +161,16 @@ public class InsetsControllerTest {
mController.show(Type.all());
// quickly jump to final state by cancelling it.
mController.cancelExistingAnimation();
- assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertTrue(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertTrue(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.applyImeVisibility(false /* setVisible */);
mController.hide(Type.all());
mController.cancelExistingAnimation();
- assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.getSourceConsumer(ITYPE_IME).onWindowFocusLost();
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -180,10 +187,10 @@ public class InsetsControllerTest {
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained();
mController.applyImeVisibility(true);
mController.cancelExistingAnimation();
- assertTrue(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.applyImeVisibility(false);
mController.cancelExistingAnimation();
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.getSourceConsumer(ITYPE_IME).onWindowFocusLost();
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -201,16 +208,16 @@ public class InsetsControllerTest {
// test show select types.
mController.show(types);
mController.cancelExistingAnimation();
- assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertTrue(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test hide all
mController.hide(types);
mController.cancelExistingAnimation();
- assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -227,29 +234,29 @@ public class InsetsControllerTest {
// test show select types.
mController.show(types);
mController.cancelExistingAnimation();
- assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertTrue(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test hide all
mController.hide(Type.all());
mController.cancelExistingAnimation();
- assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test single show
mController.show(Type.navigationBars());
mController.cancelExistingAnimation();
- assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test single hide
mController.hide(Type.navigationBars());
- assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -267,31 +274,31 @@ public class InsetsControllerTest {
mController.show(Type.navigationBars());
mController.show(Type.systemBars());
mController.cancelExistingAnimation();
- assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertTrue(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.hide(Type.navigationBars());
mController.hide(Type.systemBars());
mController.cancelExistingAnimation();
- assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
int types = Type.navigationBars() | Type.systemBars();
// show two at a time and hide one by one.
mController.show(types);
mController.hide(Type.navigationBars());
mController.cancelExistingAnimation();
- assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertTrue(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.hide(Type.systemBars());
mController.cancelExistingAnimation();
- assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -309,15 +316,15 @@ public class InsetsControllerTest {
mController.show(types);
mController.hide(Type.navigationBars());
mController.cancelExistingAnimation();
- assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertTrue(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.hide(Type.systemBars());
mController.cancelExistingAnimation();
- assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(statusBar.getType()).isVisible());
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
+ assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -336,12 +343,16 @@ public class InsetsControllerTest {
ArgumentCaptor<WindowInsetsAnimationController> controllerCaptor =
ArgumentCaptor.forClass(WindowInsetsAnimationController.class);
+
+ // Ready gets deferred until next predraw
+ mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
+
verify(mockListener).onReady(controllerCaptor.capture(), anyInt());
controllerCaptor.getValue().finish(false /* shown */);
});
waitUntilNextFrame();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isVisible());
+ assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 7af833bfcba4..492c03653990 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -96,7 +96,7 @@ public class InsetsSourceConsumerTest {
@Test
public void testHide() {
mConsumer.hide();
- assertFalse("Consumer should not be visible", mConsumer.isVisible());
+ assertFalse("Consumer should not be visible", mConsumer.isRequestedVisible());
verify(mSpyInsetsSource).setVisible(eq(false));
}
@@ -106,7 +106,7 @@ public class InsetsSourceConsumerTest {
// Insets source starts out visible
mConsumer.hide();
mConsumer.show();
- assertTrue("Consumer should be visible", mConsumer.isVisible());
+ assertTrue("Consumer should be visible", mConsumer.isRequestedVisible());
verify(mSpyInsetsSource).setVisible(eq(false));
verify(mSpyInsetsSource).setVisible(eq(true));
}
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 60620881b6f2..fa2ffccaaa63 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -23,6 +23,7 @@ import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static org.junit.Assert.assertEquals;
@@ -116,14 +117,18 @@ public class InsetsStateTest {
@Test
public void testCalculateInsets_imeIgnoredWithoutAdjustResize() {
- mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
- mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
- mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
- mState.getSource(ITYPE_IME).setVisible(true);
- WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
- DisplayCutout.NO_CUTOUT, null, null, 0, null);
- assertEquals(0, insets.getSystemWindowInsetBottom());
- assertTrue(insets.isVisible(ime()));
+ try (final InsetsModeSession session =
+ new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) {
+ mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
+ mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
+ mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
+ mState.getSource(ITYPE_IME).setVisible(true);
+ WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
+ DisplayCutout.NO_CUTOUT, null, null, SOFT_INPUT_ADJUST_NOTHING, null);
+ assertEquals(0, insets.getSystemWindowInsetBottom());
+ assertEquals(100, insets.getInsets(ime()).bottom);
+ assertTrue(insets.isVisible(ime()));
+ }
}
@Test
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index 8c7b28af2e78..e5a4f6d5b3be 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -63,7 +63,8 @@ public class WindowInsetsTest {
b.setInsets(navigationBars(), Insets.of(0, 0, 0, 100));
b.setInsets(ime(), Insets.of(0, 0, 0, 300));
WindowInsets insets = b.build();
- assertEquals(300, insets.getSystemWindowInsets().bottom);
+ assertEquals(100, insets.getSystemWindowInsets().bottom);
+ assertEquals(300, insets.getInsets(ime()).bottom);
}
// TODO: Move this to CTS once API made public
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
index b9b6d55b52d6..e23c51e66a02 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.accessibility;
+package android.view.accessibility;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertSame;
@@ -29,16 +29,17 @@ import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Instrumentation;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
import android.os.UserHandle;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.IAccessibilityManager;
-import android.view.accessibility.IAccessibilityManagerClient;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.IntPair;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import org.junit.After;
import org.junit.Before;
@@ -57,6 +58,16 @@ import java.util.List;
public class AccessibilityManagerTest {
private static final boolean WITH_A11Y_ENABLED = true;
private static final boolean WITH_A11Y_DISABLED = false;
+ private static final String LABEL = "label";
+ private static final String INTENT_ACTION = "TESTACTION";
+ private static final String DESCRIPTION = "description";
+ private static final PendingIntent TEST_PENDING_INTENT = PendingIntent.getBroadcast(
+ InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION), 0);
+ private static final RemoteAction TEST_ACTION = new RemoteAction(
+ Icon.createWithContentUri("content://test"),
+ LABEL,
+ DESCRIPTION,
+ TEST_PENDING_INTENT);
@Mock private IAccessibilityManager mMockService;
private MessageCapturingHandler mHandler;
@@ -122,6 +133,29 @@ public class AccessibilityManagerTest {
}
@Test
+ public void testRegisterSystemAction() throws Exception {
+ AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+ RemoteAction action = new RemoteAction(
+ Icon.createWithContentUri("content://test"),
+ LABEL,
+ DESCRIPTION,
+ TEST_PENDING_INTENT);
+ final int actionId = 0;
+ manager.registerSystemAction(TEST_ACTION, actionId);
+
+ verify(mMockService).registerSystemAction(TEST_ACTION, actionId);
+ }
+
+ @Test
+ public void testUnregisterSystemAction() throws Exception {
+ AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+ final int actionId = 0;
+ manager.unregisterSystemAction(actionId);
+
+ verify(mMockService).unregisterSystemAction(actionId);
+ }
+
+ @Test
public void testIsEnabled() throws Exception {
// Create manager with a11y enabled
AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index f497db2256dd..89c237498e5c 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -226,6 +226,61 @@ public class EditorCursorDragTest {
}
@Test
+ public void testEditor_onTouchEvent_quickTapAfterDrag() throws Throwable {
+ String text = "Hi world!";
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
+
+ TextView tv = mActivity.findViewById(R.id.textview);
+ Editor editor = tv.getEditorForTesting();
+
+ // Simulate a tap-and-drag gesture.
+ long event1Time = 1001;
+ MotionEvent event1 = downEvent(event1Time, event1Time, 5f, 10f);
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
+ assertFalse(editor.getInsertionController().isCursorBeingModified());
+ assertFalse(editor.getSelectionController().isCursorBeingModified());
+
+ long event2Time = 1002;
+ MotionEvent event2 = moveEvent(event1Time, event2Time, 50f, 10f);
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
+ assertTrue(editor.getInsertionController().isCursorBeingModified());
+ assertFalse(editor.getSelectionController().isCursorBeingModified());
+
+ long event3Time = 1003;
+ MotionEvent event3 = moveEvent(event1Time, event3Time, 100f, 10f);
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
+ assertTrue(editor.getInsertionController().isCursorBeingModified());
+ assertFalse(editor.getSelectionController().isCursorBeingModified());
+
+ long event4Time = 2004;
+ MotionEvent event4 = upEvent(event1Time, event4Time, 100f, 10f);
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4));
+ assertFalse(editor.getInsertionController().isCursorBeingModified());
+ assertFalse(editor.getSelectionController().isCursorBeingModified());
+
+ // Simulate a quick tap after the drag, near the location where the drag ended.
+ long event5Time = 2005;
+ MotionEvent event5 = downEvent(event5Time, event5Time, 90f, 10f);
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event5));
+ assertFalse(editor.getInsertionController().isCursorBeingModified());
+ assertFalse(editor.getSelectionController().isCursorBeingModified());
+
+ long event6Time = 2006;
+ MotionEvent event6 = upEvent(event5Time, event6Time, 90f, 10f);
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event6));
+ assertFalse(editor.getInsertionController().isCursorBeingModified());
+ assertFalse(editor.getSelectionController().isCursorBeingModified());
+
+ // Simulate another quick tap in the same location; now selection should be triggered.
+ long event7Time = 2007;
+ MotionEvent event7 = downEvent(event7Time, event7Time, 90f, 10f);
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event7));
+ assertFalse(editor.getInsertionController().isCursorBeingModified());
+ assertTrue(editor.getSelectionController().isCursorBeingModified());
+ }
+
+ @Test
public void testEditor_onTouchEvent_cursorDrag() throws Throwable {
String text = "testEditor_onTouchEvent_cursorDrag";
onView(withId(R.id.textview)).perform(replaceText(text));
@@ -237,29 +292,25 @@ public class EditorCursorDragTest {
// Simulate a tap-and-drag gesture. This should trigger a cursor drag.
long event1Time = 1001;
MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
- mActivity.runOnUiThread(() -> editor.onTouchEvent(event1));
- mInstrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event2Time = 1002;
MotionEvent event2 = moveEvent(event1Time, event2Time, 21f, 30f);
- mActivity.runOnUiThread(() -> editor.onTouchEvent(event2));
- mInstrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event3Time = 1003;
- MotionEvent event3 = moveEvent(event3Time, event3Time, 120f, 30f);
- mActivity.runOnUiThread(() -> editor.onTouchEvent(event3));
- mInstrumentation.waitForIdleSync();
+ MotionEvent event3 = moveEvent(event1Time, event3Time, 120f, 30f);
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
assertTrue(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event4Time = 1004;
- MotionEvent event4 = upEvent(event3Time, event4Time, 120f, 30f);
- mActivity.runOnUiThread(() -> editor.onTouchEvent(event4));
- mInstrumentation.waitForIdleSync();
+ MotionEvent event4 = upEvent(event1Time, event4Time, 120f, 30f);
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
}
@@ -276,36 +327,31 @@ public class EditorCursorDragTest {
// Simulate a double-tap followed by a drag. This should trigger a selection drag.
long event1Time = 1001;
MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
- mActivity.runOnUiThread(() -> editor.onTouchEvent(event1));
- mInstrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event2Time = 1002;
MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
- mActivity.runOnUiThread(() -> editor.onTouchEvent(event2));
- mInstrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event3Time = 1003;
MotionEvent event3 = downEvent(event3Time, event3Time, 20f, 30f);
- mActivity.runOnUiThread(() -> editor.onTouchEvent(event3));
- mInstrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertTrue(editor.getSelectionController().isCursorBeingModified());
long event4Time = 1004;
MotionEvent event4 = moveEvent(event3Time, event4Time, 120f, 30f);
- mActivity.runOnUiThread(() -> editor.onTouchEvent(event4));
- mInstrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertTrue(editor.getSelectionController().isCursorBeingModified());
long event5Time = 1005;
MotionEvent event5 = upEvent(event3Time, event5Time, 120f, 30f);
- mActivity.runOnUiThread(() -> editor.onTouchEvent(event5));
- mInstrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event5));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
}
diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
index 6adb1b8fa0d6..215d0b800074 100644
--- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
+++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
@@ -120,6 +120,60 @@ public class EditorTouchStateTest {
}
@Test
+ public void testUpdate_doubleTap_delayAfterFirstDownEvent() throws Exception {
+ // Simulate an ACTION_DOWN event.
+ long event1Time = 1000;
+ MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+ mTouchState.update(event1, mConfig);
+ assertSingleTap(mTouchState, 20f, 30f, 0, 0, false);
+
+ // Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout.
+ long event2Time = 1000 + ViewConfiguration.getDoubleTapTimeout() + 1;
+ MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
+ mTouchState.update(event2, mConfig);
+ assertSingleTap(mTouchState, 20f, 30f, 20f, 30f, false);
+
+ // Generate an ACTION_DOWN event whose time is within the double-tap timeout when
+ // calculated from the last ACTION_UP event time. Even though the time between the last up
+ // and this down event is within the double-tap timeout, this should not be considered a
+ // double-tap (since the first down event had a longer delay).
+ long event3Time = event2Time + 1;
+ MotionEvent event3 = downEvent(event3Time, event3Time, 22f, 33f);
+ mTouchState.update(event3, mConfig);
+ assertSingleTap(mTouchState, 22f, 33f, 20f, 30f, false);
+ }
+
+ @Test
+ public void testUpdate_quickTapAfterDrag() throws Exception {
+ // Simulate an ACTION_DOWN event.
+ long event1Time = 1000;
+ MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+ mTouchState.update(event1, mConfig);
+ assertSingleTap(mTouchState, 20f, 30f, 0, 0, false);
+
+ // Simulate an ACTION_MOVE event.
+ long event2Time = 1001;
+ MotionEvent event2 = moveEvent(event1Time, event2Time, 200f, 31f);
+ mTouchState.update(event2, mConfig);
+ assertSingleTap(mTouchState, 20f, 30f, 0, 0, true);
+
+ // Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout.
+ long event3Time = 5000;
+ MotionEvent event3 = upEvent(event1Time, event3Time, 200f, 31f);
+ mTouchState.update(event3, mConfig);
+ assertSingleTap(mTouchState, 20f, 30f, 200f, 31f, false);
+
+ // Generate an ACTION_DOWN event whose time is within the double-tap timeout when
+ // calculated from the last ACTION_UP event time. Even though the time between the last up
+ // and this down event is within the double-tap timeout, this should not be considered a
+ // double-tap (since the first down event had a longer delay).
+ long event4Time = event3Time + 1;
+ MotionEvent event4 = downEvent(event4Time, event4Time, 200f, 31f);
+ mTouchState.update(event4, mConfig);
+ assertSingleTap(mTouchState, 200f, 31f, 200f, 31f, false);
+ }
+
+ @Test
public void testUpdate_tripleClick_mouse() throws Exception {
// Simulate an ACTION_DOWN event.
long event1Time = 1000;
diff --git a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
index ffc925ff82cd..f108eb8aeb0b 100644
--- a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
+++ b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
@@ -121,7 +121,12 @@ public class AndroidFutureTest {
AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel);
ExecutionException executionException =
expectThrows(ExecutionException.class, future2::get);
- assertThat(executionException.getCause()).isInstanceOf(UnsupportedOperationException.class);
+
+ Throwable cause = executionException.getCause();
+ String msg = cause.getMessage();
+ assertThat(cause).isInstanceOf(UnsupportedOperationException.class);
+ assertThat(msg).contains(getClass().getName());
+ assertThat(msg).contains("testWriteToParcel_Exception");
}
@Test
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 66d84aaf35cd..9018320e479c 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -79,138 +79,6 @@ public class ActivityThreadClientTest {
@Test
@UiThreadTest
- public void testWindowVisibilityChange_OnCreate() throws Exception {
- try (ClientMockSession clientSession = new ClientMockSession()) {
- ActivityClientRecord r = clientSession.stubActivityRecord();
-
- clientSession.launchActivity(r);
- assertEquals(ON_CREATE, r.getLifecycleState());
-
- clientSession.changeVisibility(r, true);
- assertEquals(ON_CREATE, r.getLifecycleState());
-
- clientSession.changeVisibility(r, false);
- assertEquals(ON_CREATE, r.getLifecycleState());
- }
- }
-
- @Test
- @UiThreadTest
- public void testWindowVisibilityChange_OnCreate_Finished() throws Exception {
- try (ClientMockSession clientSession = new ClientMockSession()) {
- ActivityClientRecord r = clientSession.stubActivityRecord();
-
- Activity activity = clientSession.launchActivity(r);
- activity.finish();
- assertEquals(ON_CREATE, r.getLifecycleState());
-
- clientSession.changeVisibility(r, true);
- assertEquals(ON_CREATE, r.getLifecycleState());
-
- clientSession.changeVisibility(r, false);
- assertEquals(ON_CREATE, r.getLifecycleState());
- }
- }
-
- @Test
- @UiThreadTest
- public void testWindowVisibilityChange_OnStart() throws Exception {
- try (ClientMockSession clientSession = new ClientMockSession()) {
- ActivityClientRecord r = clientSession.stubActivityRecord();
-
- clientSession.launchActivity(r);
- clientSession.startActivity(r);
- assertEquals(ON_START, r.getLifecycleState());
-
- clientSession.changeVisibility(r, false);
- assertEquals(ON_STOP, r.getLifecycleState());
-
- clientSession.changeVisibility(r, true);
- assertEquals(ON_START, r.getLifecycleState());
- }
- }
-
- @Test
- @UiThreadTest
- public void testWindowVisibilityChange_OnStart_Finished() throws Exception {
- try (ClientMockSession clientSession = new ClientMockSession()) {
- ActivityClientRecord r = clientSession.stubActivityRecord();
-
- Activity activity = clientSession.launchActivity(r);
- clientSession.startActivity(r);
- activity.finish();
- assertEquals(ON_START, r.getLifecycleState());
-
- clientSession.changeVisibility(r, false);
- assertEquals(ON_STOP, r.getLifecycleState());
-
- clientSession.changeVisibility(r, true);
- assertEquals(ON_START, r.getLifecycleState());
- }
- }
-
- @Test
- @UiThreadTest
- public void testWindowVisibilityChange_OnResume() throws Exception {
- try (ClientMockSession clientSession = new ClientMockSession()) {
- ActivityClientRecord r = clientSession.stubActivityRecord();
-
- clientSession.launchActivity(r);
- clientSession.startActivity(r);
- clientSession.resumeActivity(r);
- assertEquals(ON_RESUME, r.getLifecycleState());
-
- clientSession.changeVisibility(r, false);
- assertEquals(ON_STOP, r.getLifecycleState());
-
- clientSession.changeVisibility(r, true);
- assertEquals(ON_START, r.getLifecycleState());
- }
- }
-
- @Test
- @UiThreadTest
- public void testWindowVisibilityChange_OnPause() throws Exception {
- try (ClientMockSession clientSession = new ClientMockSession()) {
- ActivityClientRecord r = clientSession.stubActivityRecord();
-
- clientSession.launchActivity(r);
- clientSession.startActivity(r);
- clientSession.resumeActivity(r);
- clientSession.pauseActivity(r);
- assertEquals(ON_PAUSE, r.getLifecycleState());
-
- clientSession.changeVisibility(r, false);
- assertEquals(ON_STOP, r.getLifecycleState());
-
- clientSession.changeVisibility(r, true);
- assertEquals(ON_START, r.getLifecycleState());
- }
- }
-
- @Test
- @UiThreadTest
- public void testWindowVisibilityChange_OnStop() throws Exception {
- try (ClientMockSession clientSession = new ClientMockSession()) {
- ActivityClientRecord r = clientSession.stubActivityRecord();
-
- clientSession.launchActivity(r);
- clientSession.startActivity(r);
- clientSession.resumeActivity(r);
- clientSession.pauseActivity(r);
- clientSession.stopActivity(r);
- assertEquals(ON_STOP, r.getLifecycleState());
-
- clientSession.changeVisibility(r, true);
- assertEquals(ON_START, r.getLifecycleState());
-
- clientSession.changeVisibility(r, false);
- assertEquals(ON_STOP, r.getLifecycleState());
- }
- }
-
- @Test
- @UiThreadTest
public void testLifecycleAfterFinished_OnCreate() throws Exception {
try (ClientMockSession clientSession = new ClientMockSession()) {
ActivityClientRecord r = clientSession.stubActivityRecord();
@@ -308,7 +176,7 @@ public class ActivityThreadClientTest {
}
private void startActivity(ActivityClientRecord r) {
- mThread.handleStartActivity(r, null /* pendingActions */);
+ mThread.handleStartActivity(r.token, null /* pendingActions */);
}
private void resumeActivity(ActivityClientRecord r) {
@@ -323,7 +191,7 @@ public class ActivityThreadClientTest {
}
private void stopActivity(ActivityClientRecord r) {
- mThread.handleStopActivity(r.token, false /* show */, 0 /* configChanges */,
+ mThread.handleStopActivity(r.token, 0 /* configChanges */,
new PendingTransactionActions(), false /* finalStateRequest */, "test");
}
@@ -332,10 +200,6 @@ public class ActivityThreadClientTest {
false /* getNonConfigInstance */, "test");
}
- private void changeVisibility(ActivityClientRecord r, boolean show) {
- mThread.handleWindowVisibility(r.token, show);
- }
-
private ActivityClientRecord stubActivityRecord() {
ComponentName component = new ComponentName(
InstrumentationRegistry.getInstrumentation().getContext(), TestActivity.class);
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index cc01a31224bc..543504764ee3 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -46,6 +46,7 @@
<xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app"/>
<xs:element name="allow-association" type="allow-association"/>
<xs:element name="bugreport-whitelisted" type="bugreport-whitelisted"/>
+ <xs:element name="app-data-isolation-whitelisted-app" type="app-data-isolation-whitelisted-app"/>
</xs:choice>
</xs:complexType>
</xs:element>
@@ -161,6 +162,9 @@
<xs:attribute name="target" type="xs:string"/>
<xs:attribute name="allowed" type="xs:string"/>
</xs:complexType>
+ <xs:complexType name="app-data-isolation-whitelisted-app">
+ <xs:attribute name="package" type="xs:string"/>
+ </xs:complexType>
<xs:complexType name="bugreport-whitelisted">
<xs:attribute name="package" type="xs:string"/>
</xs:complexType>
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index 771c1dffb909..c36c422a852d 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -45,6 +45,12 @@ package com.android.xml.permission.configfile {
method public void set_package(String);
}
+ public class AppDataIsolationWhitelistedApp {
+ ctor public AppDataIsolationWhitelistedApp();
+ method public String get_package();
+ method public void set_package(String);
+ }
+
public class AppLink {
ctor public AppLink();
method public String get_package();
@@ -160,6 +166,7 @@ package com.android.xml.permission.configfile {
method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle_optional();
method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave_optional();
method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AppDataIsolationWhitelistedApp> getAppDataIsolationWhitelistedApp_optional();
method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink_optional();
method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission_optional();
method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService_optional();
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index eb1d1ab1089c..9930ea262b32 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -243,6 +243,7 @@ applications that come with the platform
<permission name="android.permission.MANAGE_USB"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
+ <permission name="android.permission.TETHER_PRIVILEGED"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
</privapp-permissions>
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 6e7f286d19a7..bee8d5efc933 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -21,7 +21,7 @@ import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Canvas.VertexMode;
import android.graphics.text.MeasuredText;
import android.text.GraphicsOperations;
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index d900a42b1e66..ac094ba5d5d2 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -21,8 +21,8 @@ import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
import android.annotation.WorkerThread;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.ResourcesImpl;
import android.hardware.HardwareBuffer;
import android.os.Build;
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 5623a8a49b35..bad487b47682 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -20,7 +20,7 @@ import static android.graphics.BitmapFactory.Options.validate;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Trace;
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index 629d8c131b68..34eba97819aa 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -15,7 +15,7 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
import android.os.Build;
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index 198d1e7bc956..edf53c491311 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -17,7 +17,7 @@
package android.graphics;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* Shader used to draw a bitmap as a texture. The bitmap can be repeated or
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
index cbd4eadca30a..80a3740d2f4e 100644
--- a/graphics/java/android/graphics/Camera.java
+++ b/graphics/java/android/graphics/Camera.java
@@ -16,7 +16,7 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* A camera instance can be used to compute 3D transformations and
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index a815f20293c5..9a0ca3e4ad9b 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -22,7 +22,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.text.MeasuredText;
import android.os.Build;
diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java
index 1275e0827580..4263772c1c2c 100644
--- a/graphics/java/android/graphics/CanvasProperty.java
+++ b/graphics/java/android/graphics/CanvasProperty.java
@@ -16,7 +16,8 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import com.android.internal.util.VirtualRefBasePtr;
/**
diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java
index 0f7980cc32e4..a8b18a9fcb1f 100644
--- a/graphics/java/android/graphics/ColorMatrixColorFilter.java
+++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java
@@ -18,7 +18,7 @@ package android.graphics;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* A color filter that transforms colors through a 4x5 color matrix. This filter
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 5ad93f411393..ae90995573dc 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -17,7 +17,7 @@
package android.graphics;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
import android.graphics.fonts.FontVariationAxis;
import android.text.TextUtils;
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 21cc3757a40e..c146bbd4441b 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -16,7 +16,7 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.fonts.FontVariationAxis;
import android.text.FontConfig;
import android.util.Xml;
diff --git a/graphics/java/android/graphics/GraphicBuffer.java b/graphics/java/android/graphics/GraphicBuffer.java
index 3b1fc70397ea..99fa5eef7bbd 100644
--- a/graphics/java/android/graphics/GraphicBuffer.java
+++ b/graphics/java/android/graphics/GraphicBuffer.java
@@ -16,7 +16,7 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index bcb313e1c227..83432c362672 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -28,8 +28,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Px;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
import android.annotation.WorkerThread;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java
index 62a890ff4f0b..221dfa192795 100644
--- a/graphics/java/android/graphics/LightingColorFilter.java
+++ b/graphics/java/android/graphics/LightingColorFilter.java
@@ -22,7 +22,7 @@
package android.graphics;
import android.annotation.ColorInt;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* A color filter that can be used to simulate simple lighting effects.
diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java
index 12e63c09d76b..3f3ad967fe97 100644
--- a/graphics/java/android/graphics/LinearGradient.java
+++ b/graphics/java/android/graphics/LinearGradient.java
@@ -20,7 +20,7 @@ import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
public class LinearGradient extends Shader {
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index 22b6401fdc2e..cf914c2c3eae 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -16,7 +16,7 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 6f030ffac2df..4b3924f0d55f 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -16,7 +16,7 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
import android.os.Build;
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index c4c1eaceb4fc..ff3239348240 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -16,7 +16,7 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* The NinePatch class permits drawing a bitmap in nine or more sections.
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 1fc056c3652f..91a60c327bf0 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -19,7 +19,7 @@ package android.graphics;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.drawable.Drawable;
import java.lang.annotation.Retention;
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 109d8631284d..3b586242e5b1 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -24,7 +24,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Px;
import android.annotation.Size;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.fonts.FontVariationAxis;
import android.os.Build;
import android.os.LocaleList;
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 7282d52d6e23..1362fd864d29 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -20,7 +20,7 @@ import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index 8d12cbffc793..390d3d414346 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -17,7 +17,7 @@
package android.graphics;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import java.io.InputStream;
import java.io.OutputStream;
diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java
index bc1f66fdd5c0..1275cb9ca4f9 100644
--- a/graphics/java/android/graphics/PorterDuff.java
+++ b/graphics/java/android/graphics/PorterDuff.java
@@ -16,7 +16,7 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* <p>This class contains the list of alpha compositing and blending modes
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
index cc2d3a8969fc..50ecb62e7fcc 100644
--- a/graphics/java/android/graphics/PorterDuffColorFilter.java
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -18,7 +18,7 @@ package android.graphics;
import android.annotation.ColorInt;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* A color filter that can be used to tint the source pixels using a single
diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java
index acbe3da75247..96b7b9a78ba8 100644
--- a/graphics/java/android/graphics/RadialGradient.java
+++ b/graphics/java/android/graphics/RadialGradient.java
@@ -20,7 +20,7 @@ import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
public class RadialGradient extends Shader {
@UnsupportedAppUsage
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 9e1946c557d2..081b851d1333 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -19,7 +19,7 @@ package android.graphics;
import android.annotation.CheckResult;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java
index ec7f7a05b685..d8d96413a93d 100644
--- a/graphics/java/android/graphics/Region.java
+++ b/graphics/java/android/graphics/Region.java
@@ -17,7 +17,7 @@
package android.graphics;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pools.SynchronizedPool;
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 3050d1dae5e4..5335aa4725ad 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -20,7 +20,7 @@ import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import libcore.util.NativeAllocationRegistry;
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 99f440d599cb..697daa8b7b70 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -17,7 +17,7 @@
package android.graphics;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java
index 667f45afe500..08520048b787 100644
--- a/graphics/java/android/graphics/SweepGradient.java
+++ b/graphics/java/android/graphics/SweepGradient.java
@@ -20,7 +20,7 @@ import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
public class SweepGradient extends Shader {
@UnsupportedAppUsage
diff --git a/graphics/java/android/graphics/TableMaskFilter.java b/graphics/java/android/graphics/TableMaskFilter.java
index d81c491e07e0..204f9705852a 100644
--- a/graphics/java/android/graphics/TableMaskFilter.java
+++ b/graphics/java/android/graphics/TableMaskFilter.java
@@ -16,7 +16,7 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* @hide
diff --git a/graphics/java/android/graphics/TemporaryBuffer.java b/graphics/java/android/graphics/TemporaryBuffer.java
index 0ae2c703c21c..ef3f7f704e0d 100644
--- a/graphics/java/android/graphics/TemporaryBuffer.java
+++ b/graphics/java/android/graphics/TemporaryBuffer.java
@@ -16,7 +16,8 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import com.android.internal.util.ArrayUtils;
/**
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 6d20ec32cdc4..a2dd9a8322b6 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -25,7 +25,7 @@ import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
import android.graphics.fonts.Font;
import android.graphics.fonts.FontFamily;
diff --git a/graphics/java/android/graphics/Xfermode.java b/graphics/java/android/graphics/Xfermode.java
index 6f4adfde7ff9..e79fb76d806e 100644
--- a/graphics/java/android/graphics/Xfermode.java
+++ b/graphics/java/android/graphics/Xfermode.java
@@ -21,7 +21,7 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* Xfermode is the base class for objects that are called to implement custom
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index 82f587086428..d8946009483c 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -19,7 +19,7 @@ package android.graphics.drawable;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index b29fd4db5803..686f146e9c18 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -18,23 +18,23 @@ package android.graphics.drawable;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.graphics.Canvas;
-import android.graphics.Rect;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.TypedValue;
-import android.os.SystemClock;
+
+import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
-import com.android.internal.R;
-
/**
* @hide
*/
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 11a46c4ba9b9..06159d8a0558 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -20,7 +20,7 @@ import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 66947da9166f..1acf6c512fbd 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -25,9 +25,9 @@ import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
import android.app.Application;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo.Config;
import android.content.res.ColorStateList;
import android.content.res.Resources;
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 57764c2cb693..8c3fa441cbb0 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -16,21 +16,21 @@
package android.graphics.drawable;
-import com.android.internal.R;
-
-import java.io.IOException;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
import android.os.SystemClock;
import android.util.AttributeSet;
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
/**
* An object used to create frame-by-frame animations, defined by a series of
* Drawable objects, which can be used as a View object's background.
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index e4aa774fd434..4e768c9eddfb 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -17,7 +17,7 @@
package android.graphics.drawable;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo.Config;
import android.content.res.ColorStateList;
import android.content.res.Resources;
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 31fdb025bbc5..69ed9b423d48 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -16,20 +16,22 @@
package android.graphics.drawable;
-import com.android.internal.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
-import android.graphics.*;
-import android.view.Gravity;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.Gravity;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index e53f3db08538..6d4a0c6421d9 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -52,8 +52,8 @@ void DeviceInfo::setMaxTextureSize(int maxTextureSize) {
DeviceInfo::get()->mMaxTextureSize = maxTextureSize;
}
-void DeviceInfo::onDisplayConfigChanged() {
- updateDisplayInfo();
+void DeviceInfo::onRefreshRateChanged(int64_t vsyncPeriod) {
+ mVsyncPeriod = vsyncPeriod;
}
void DeviceInfo::updateDisplayInfo() {
@@ -113,10 +113,11 @@ void DeviceInfo::updateDisplayInfo() {
ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex];
status_t status = ADisplay_getCurrentConfig(primaryDisplay, &mCurrentConfig);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display config, error %d", status);
+
mWidth = ADisplayConfig_getWidth(mCurrentConfig);
mHeight = ADisplayConfig_getHeight(mCurrentConfig);
mDensity = ADisplayConfig_getDensity(mCurrentConfig);
- mRefreshRate = ADisplayConfig_getFps(mCurrentConfig);
+ mVsyncPeriod = static_cast<int64_t>(1000000000 / ADisplayConfig_getFps(mCurrentConfig));
mCompositorOffset = ADisplayConfig_getCompositorOffsetNanos(mCurrentConfig);
mAppOffset = ADisplayConfig_getAppVsyncOffsetNanos(mCurrentConfig);
}
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index a4207460883e..16a22f4706f5 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -37,7 +37,7 @@ public:
static int32_t getWidth() { return get()->mWidth; }
static int32_t getHeight() { return get()->mHeight; }
static float getDensity() { return get()->mDensity; }
- static float getRefreshRate() { return get()->mRefreshRate; }
+ static int64_t getVsyncPeriod() { return get()->mVsyncPeriod; }
static int64_t getCompositorOffset() { return get()->mCompositorOffset; }
static int64_t getAppOffset() { return get()->mAppOffset; }
@@ -47,7 +47,8 @@ public:
sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; }
SkColorType getWideColorType() const { return mWideColorType; }
- void onDisplayConfigChanged();
+ // This method should be called whenever the display refresh rate changes.
+ void onRefreshRateChanged(int64_t vsyncPeriod);
private:
friend class renderthread::RenderThread;
@@ -68,7 +69,7 @@ private:
int32_t mWidth = 1080;
int32_t mHeight = 1920;
float mDensity = 2.0;
- float mRefreshRate = 60.0;
+ int64_t mVsyncPeriod = 16666666;
int64_t mCompositorOffset = 0;
int64_t mAppOffset = 0;
};
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 10e7160e7069..d25fc4b0b03e 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -81,7 +81,7 @@ static FrameInfoIndex sFrameStart = FrameInfoIndex::IntendedVsync;
JankTracker::JankTracker(ProfileDataContainer* globalData) {
mGlobalData = globalData;
- nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1_s / DeviceInfo::getRefreshRate());
+ nsecs_t frameIntervalNanos = DeviceInfo::getVsyncPeriod();
nsecs_t sfOffset = DeviceInfo::getCompositorOffset();
nsecs_t offsetDelta = sfOffset - DeviceInfo::getAppOffset();
// There are two different offset cases. If the offsetDelta is positive
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index f4149b9b4d7d..84549e8ce6e4 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -152,7 +152,9 @@ sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, sk_sp<SkColorS
AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
SkImageInfo info = uirenderer::BufferDescriptionToImageInfo(bufferDesc, colorSpace);
- const size_t rowBytes = info.bytesPerPixel() * bufferDesc.stride;
+ // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
+ const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
+ const size_t rowBytes = info.bytesPerPixel() * bufferStride;
return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 11dc013af6bc..35a885f46919 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -457,7 +457,10 @@ void SkiaPipeline::renderFrameImpl(const SkRect& clip,
const Rect& contentDrawBounds, SkCanvas* canvas,
const SkMatrix& preTransform) {
SkAutoCanvasRestore saver(canvas, true);
- canvas->androidFramework_setDeviceClipRestriction(preTransform.mapRect(clip).roundOut());
+ auto clipRestriction = preTransform.mapRect(clip).roundOut();
+ canvas->androidFramework_setDeviceClipRestriction(clipRestriction);
+ canvas->drawAnnotation(SkRect::Make(clipRestriction), "AndroidDeviceClipRestriction",
+ nullptr);
canvas->concat(preTransform);
// STOPSHIP: Revert, temporary workaround to clear always F16 frame buffer for b/74976293
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index a446858ca565..d78f641d45b9 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -34,7 +34,6 @@
#include <GrContextOptions.h>
#include <gl/GrGLInterface.h>
-#include <gui/DisplayEventReceiver.h>
#include <sys/resource.h>
#include <utils/Condition.h>
#include <utils/Log.h>
@@ -45,53 +44,43 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-// Number of events to read at a time from the DisplayEventReceiver pipe.
-// The value should be large enough that we can quickly drain the pipe
-// using just a few large reads.
-static const size_t EVENT_BUFFER_SIZE = 100;
-
static bool gHasRenderThreadInstance = false;
static JVMAttachHook gOnStartHook = nullptr;
-class DisplayEventReceiverWrapper : public VsyncSource {
+void RenderThread::frameCallback(int64_t frameTimeNanos, void* data) {
+ RenderThread* rt = reinterpret_cast<RenderThread*>(data);
+ rt->mVsyncRequested = false;
+ if (rt->timeLord().vsyncReceived(frameTimeNanos) && !rt->mFrameCallbackTaskPending) {
+ ATRACE_NAME("queue mFrameCallbackTask");
+ rt->mFrameCallbackTaskPending = true;
+ nsecs_t runAt = (frameTimeNanos + rt->mDispatchFrameDelay);
+ rt->queue().postAt(runAt, [=]() { rt->dispatchFrameCallbacks(); });
+ }
+}
+
+void RenderThread::refreshRateCallback(int64_t vsyncPeriod, void* data) {
+ ATRACE_NAME("refreshRateCallback");
+ RenderThread* rt = reinterpret_cast<RenderThread*>(data);
+ DeviceInfo::get()->onRefreshRateChanged(vsyncPeriod);
+ rt->setupFrameInterval();
+}
+
+class ChoreographerSource : public VsyncSource {
public:
- DisplayEventReceiverWrapper(std::unique_ptr<DisplayEventReceiver>&& receiver,
- const std::function<void()>& onDisplayConfigChanged)
- : mDisplayEventReceiver(std::move(receiver))
- , mOnDisplayConfigChanged(onDisplayConfigChanged) {}
+ ChoreographerSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
virtual void requestNextVsync() override {
- status_t status = mDisplayEventReceiver->requestNextVsync();
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "requestNextVsync failed with status: %d", status);
+ AChoreographer_postFrameCallback64(mRenderThread->mChoreographer,
+ RenderThread::frameCallback, mRenderThread);
}
- virtual nsecs_t latestVsyncEvent() override {
- DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
- nsecs_t latest = 0;
- ssize_t n;
- while ((n = mDisplayEventReceiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
- for (ssize_t i = 0; i < n; i++) {
- const DisplayEventReceiver::Event& ev = buf[i];
- switch (ev.header.type) {
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- latest = ev.header.timestamp;
- break;
- case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
- mOnDisplayConfigChanged();
- break;
- }
- }
- }
- if (n < 0) {
- ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
- }
- return latest;
+ virtual void drainPendingEvents() override {
+ AChoreographer_handlePendingEvents(mRenderThread->mChoreographer, mRenderThread);
}
private:
- std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver;
- std::function<void()> mOnDisplayConfigChanged;
+ RenderThread* mRenderThread;
};
class DummyVsyncSource : public VsyncSource {
@@ -99,11 +88,14 @@ public:
DummyVsyncSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
virtual void requestNextVsync() override {
- mRenderThread->queue().postDelayed(16_ms,
- [this]() { mRenderThread->drainDisplayEventQueue(); });
+ mRenderThread->queue().postDelayed(16_ms, [this]() {
+ RenderThread::frameCallback(systemTime(SYSTEM_TIME_MONOTONIC), mRenderThread);
+ });
}
- virtual nsecs_t latestVsyncEvent() override { return systemTime(SYSTEM_TIME_MONOTONIC); }
+ virtual void drainPendingEvents() override {
+ RenderThread::frameCallback(systemTime(SYSTEM_TIME_MONOTONIC), mRenderThread);
+ }
private:
RenderThread* mRenderThread;
@@ -145,29 +137,24 @@ RenderThread::RenderThread()
}
RenderThread::~RenderThread() {
+ // Note that if this fatal assertion is removed then member variables must
+ // be properly destroyed.
LOG_ALWAYS_FATAL("Can't destroy the render thread");
}
-void RenderThread::initializeDisplayEventReceiver() {
- LOG_ALWAYS_FATAL_IF(mVsyncSource, "Initializing a second DisplayEventReceiver?");
+void RenderThread::initializeChoreographer() {
+ LOG_ALWAYS_FATAL_IF(mVsyncSource, "Initializing a second Choreographer?");
if (!Properties::isolatedProcess) {
- auto receiver = std::make_unique<DisplayEventReceiver>(
- ISurfaceComposer::eVsyncSourceApp,
- ISurfaceComposer::eConfigChangedDispatch);
- status_t status = receiver->initCheck();
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "Initialization of DisplayEventReceiver "
- "failed with status: %d",
- status);
+ mChoreographer = AChoreographer_create();
+ LOG_ALWAYS_FATAL_IF(mChoreographer == nullptr, "Initialization of Choreographer failed");
+ AChoreographer_registerRefreshRateCallback(mChoreographer,
+ RenderThread::refreshRateCallback, this);
// Register the FD
- mLooper->addFd(receiver->getFd(), 0, Looper::EVENT_INPUT,
- RenderThread::displayEventReceiverCallback, this);
- mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver), [this] {
- DeviceInfo::get()->onDisplayConfigChanged();
- setupFrameInterval();
- });
+ mLooper->addFd(AChoreographer_getFd(mChoreographer), 0, Looper::EVENT_INPUT,
+ RenderThread::choreographerCallback, this);
+ mVsyncSource = new ChoreographerSource(this);
} else {
mVsyncSource = new DummyVsyncSource(this);
}
@@ -175,7 +162,7 @@ void RenderThread::initializeDisplayEventReceiver() {
void RenderThread::initThreadLocals() {
setupFrameInterval();
- initializeDisplayEventReceiver();
+ initializeChoreographer();
mEglManager = new EglManager();
mRenderState = new RenderState(*this);
mVkManager = new VulkanManager();
@@ -183,7 +170,7 @@ void RenderThread::initThreadLocals() {
}
void RenderThread::setupFrameInterval() {
- nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / DeviceInfo::getRefreshRate());
+ nsecs_t frameIntervalNanos = DeviceInfo::getVsyncPeriod();
mTimeLord.setFrameInterval(frameIntervalNanos);
mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
}
@@ -288,7 +275,7 @@ void RenderThread::setGrContext(sk_sp<GrContext> context) {
}
}
-int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
+int RenderThread::choreographerCallback(int fd, int events, void* data) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
"events=0x%x",
@@ -302,24 +289,10 @@ int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
events);
return 1; // keep the callback
}
+ RenderThread* rt = reinterpret_cast<RenderThread*>(data);
+ AChoreographer_handlePendingEvents(rt->mChoreographer, data);
- reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
-
- return 1; // keep the callback
-}
-
-void RenderThread::drainDisplayEventQueue() {
- ATRACE_CALL();
- nsecs_t vsyncEvent = mVsyncSource->latestVsyncEvent();
- if (vsyncEvent > 0) {
- mVsyncRequested = false;
- if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
- ATRACE_NAME("queue mFrameCallbackTask");
- mFrameCallbackTaskPending = true;
- nsecs_t runAt = (vsyncEvent + mDispatchFrameDelay);
- queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); });
- }
- }
+ return 1;
}
void RenderThread::dispatchFrameCallbacks() {
@@ -360,7 +333,7 @@ bool RenderThread::threadLoop() {
processQueue();
if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
- drainDisplayEventQueue();
+ mVsyncSource->drainPendingEvents();
mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
mPendingRegistrationFrameCallbacks.end());
mPendingRegistrationFrameCallbacks.clear();
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index da79e97a6ceb..8be46a6d16e1 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -19,6 +19,7 @@
#include <GrContext.h>
#include <SkBitmap.h>
+#include <apex/choreographer.h>
#include <cutils/compiler.h>
#include <thread/ThreadBase.h>
#include <utils/Looper.h>
@@ -73,10 +74,11 @@ protected:
struct VsyncSource {
virtual void requestNextVsync() = 0;
- virtual nsecs_t latestVsyncEvent() = 0;
+ virtual void drainPendingEvents() = 0;
virtual ~VsyncSource() {}
};
+class ChoreographerSource;
class DummyVsyncSource;
typedef void (*JVMAttachHook)(const char* name);
@@ -136,6 +138,7 @@ private:
friend class DispatchFrameCallbacks;
friend class RenderProxy;
friend class DummyVsyncSource;
+ friend class ChoreographerSource;
friend class android::uirenderer::AutoBackendTextureRelease;
friend class android::uirenderer::TestUtils;
friend class android::uirenderer::WebViewFunctor;
@@ -149,13 +152,21 @@ private:
static RenderThread& getInstance();
void initThreadLocals();
- void initializeDisplayEventReceiver();
+ void initializeChoreographer();
void setupFrameInterval();
- static int displayEventReceiverCallback(int fd, int events, void* data);
+ // Callbacks for choreographer events:
+ // choreographerCallback will call AChoreograper_handleEvent to call the
+ // corresponding callbacks for each display event type
+ static int choreographerCallback(int fd, int events, void* data);
+ // Callback that will be run on vsync ticks.
+ static void frameCallback(int64_t frameTimeNanos, void* data);
+ // Callback that will be run whenver there is a refresh rate change.
+ static void refreshRateCallback(int64_t vsyncPeriod, void* data);
void drainDisplayEventQueue();
void dispatchFrameCallbacks();
void requestVsync();
+ AChoreographer* mChoreographer;
VsyncSource* mVsyncSource;
bool mVsyncRequested;
std::set<IFrameCallback*> mFrameCallbacks;
diff --git a/location/java/android/location/Criteria.java b/location/java/android/location/Criteria.java
index 1370b1095ae1..26f73f784879 100644
--- a/location/java/android/location/Criteria.java
+++ b/location/java/android/location/Criteria.java
@@ -16,9 +16,16 @@
package android.location;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A class indicating the application criteria for selecting a
* location provider. Providers may be ordered according to accuracy,
@@ -26,6 +33,25 @@ import android.os.Parcelable;
* cost.
*/
public class Criteria implements Parcelable {
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({NO_REQUIREMENT, POWER_LOW, POWER_MEDIUM, POWER_HIGH})
+ public @interface PowerRequirement {
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({NO_REQUIREMENT, ACCURACY_LOW, ACCURACY_MEDIUM, ACCURACY_HIGH})
+ public @interface AccuracyRequirement {
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({NO_REQUIREMENT, ACCURACY_FINE, ACCURACY_COARSE})
+ public @interface LocationAccuracyRequirement {
+ }
+
/**
* A constant indicating that the application does not choose to
* place requirement on a particular feature.
@@ -81,15 +107,15 @@ public class Criteria implements Parcelable {
*/
public static final int ACCURACY_HIGH = 3;
- private int mHorizontalAccuracy = NO_REQUIREMENT;
- private int mVerticalAccuracy = NO_REQUIREMENT;
- private int mSpeedAccuracy = NO_REQUIREMENT;
- private int mBearingAccuracy = NO_REQUIREMENT;
- private int mPowerRequirement = NO_REQUIREMENT;
- private boolean mAltitudeRequired = false;
- private boolean mBearingRequired = false;
- private boolean mSpeedRequired = false;
- private boolean mCostAllowed = false;
+ private int mHorizontalAccuracy = NO_REQUIREMENT;
+ private int mVerticalAccuracy = NO_REQUIREMENT;
+ private int mSpeedAccuracy = NO_REQUIREMENT;
+ private int mBearingAccuracy = NO_REQUIREMENT;
+ private int mPowerRequirement = NO_REQUIREMENT;
+ private boolean mAltitudeRequired = false;
+ private boolean mBearingRequired = false;
+ private boolean mSpeedRequired = false;
+ private boolean mCostAllowed = false;
/**
* Constructs a new Criteria object. The new object will have no
@@ -97,7 +123,8 @@ public class Criteria implements Parcelable {
* require altitude, speed, or bearing; and will not allow monetary
* cost.
*/
- public Criteria() {}
+ public Criteria() {
+ }
/**
* Constructs a new Criteria object that is a copy of the given criteria.
@@ -115,125 +142,121 @@ public class Criteria implements Parcelable {
}
/**
- * Indicates the desired horizontal accuracy (latitude and longitude).
- * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
- * {@link #ACCURACY_HIGH} or {@link #NO_REQUIREMENT}.
- * More accurate location may consume more power and may take longer.
+ * Indicates the desired horizontal accuracy (latitude and longitude). Accuracy may be
+ * {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM}, {@link #ACCURACY_HIGH} or
+ * {@link #NO_REQUIREMENT}. More accurate location may consume more power and may take longer.
*
* @throws IllegalArgumentException if accuracy is not one of the supported constants
*/
- public void setHorizontalAccuracy(int accuracy) {
- if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_HIGH) {
- throw new IllegalArgumentException("accuracy=" + accuracy);
- }
- mHorizontalAccuracy = accuracy;
+ public void setHorizontalAccuracy(@AccuracyRequirement int accuracy) {
+ mHorizontalAccuracy = Preconditions.checkArgumentInRange(accuracy, NO_REQUIREMENT,
+ ACCURACY_HIGH, "accuracy");
}
/**
* Returns a constant indicating the desired horizontal accuracy (latitude and longitude).
- * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
- * {@link #ACCURACY_HIGH} or {@link #NO_REQUIREMENT}.
+ *
+ * @see #setHorizontalAccuracy(int)
*/
+ @AccuracyRequirement
public int getHorizontalAccuracy() {
return mHorizontalAccuracy;
}
/**
- * Indicates the desired vertical accuracy (altitude).
- * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM},
- * {@link #ACCURACY_HIGH} or {@link #NO_REQUIREMENT}.
- * More accurate location may consume more power and may take longer.
+ * Indicates the desired vertical accuracy (altitude). Accuracy may be {@link #ACCURACY_LOW},
+ * {@link #ACCURACY_MEDIUM}, {@link #ACCURACY_HIGH} or {@link #NO_REQUIREMENT}. More accurate
+ * location may consume more power and may take longer.
*
* @throws IllegalArgumentException if accuracy is not one of the supported constants
*/
- public void setVerticalAccuracy(int accuracy) {
- if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_HIGH) {
- throw new IllegalArgumentException("accuracy=" + accuracy);
- }
- mVerticalAccuracy = accuracy;
+ public void setVerticalAccuracy(@AccuracyRequirement int accuracy) {
+ mVerticalAccuracy = Preconditions.checkArgumentInRange(accuracy, NO_REQUIREMENT,
+ ACCURACY_HIGH, "accuracy");
}
/**
* Returns a constant indicating the desired vertical accuracy (altitude).
- * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_HIGH},
- * or {@link #NO_REQUIREMENT}.
+ *
+ * @see #setVerticalAccuracy(int)
*/
+ @AccuracyRequirement
public int getVerticalAccuracy() {
return mVerticalAccuracy;
}
/**
- * Indicates the desired speed accuracy.
- * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_HIGH},
- * or {@link #NO_REQUIREMENT}.
- * More accurate location may consume more power and may take longer.
+ * Indicates the desired speed accuracy. Accuracy may be {@link #ACCURACY_LOW},
+ * {@link #ACCURACY_MEDIUM}, {@link #ACCURACY_HIGH}, or {@link #NO_REQUIREMENT}. More accurate
+ * location may consume more power and may take longer.
*
* @throws IllegalArgumentException if accuracy is not one of the supported constants
*/
- public void setSpeedAccuracy(int accuracy) {
- if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_HIGH) {
- throw new IllegalArgumentException("accuracy=" + accuracy);
- }
- mSpeedAccuracy = accuracy;
+ public void setSpeedAccuracy(@AccuracyRequirement int accuracy) {
+ mSpeedAccuracy = Preconditions.checkArgumentInRange(accuracy, NO_REQUIREMENT, ACCURACY_HIGH,
+ "accuracy");
}
/**
- * Returns a constant indicating the desired speed accuracy
- * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_HIGH},
- * or {@link #NO_REQUIREMENT}.
+ * Returns a constant indicating the desired speed accuracy.
+ *
+ * @see #setSpeedAccuracy(int)
*/
+ @AccuracyRequirement
public int getSpeedAccuracy() {
return mSpeedAccuracy;
}
/**
- * Indicates the desired bearing accuracy.
- * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_HIGH},
- * or {@link #NO_REQUIREMENT}.
- * More accurate location may consume more power and may take longer.
+ * Indicates the desired bearing accuracy. Accuracy may be {@link #ACCURACY_LOW},
+ * {@link #ACCURACY_MEDIUM}, {@link #ACCURACY_HIGH}, or {@link #NO_REQUIREMENT}. More accurate
+ * location may consume more power and may take longer.
*
* @throws IllegalArgumentException if accuracy is not one of the supported constants
*/
- public void setBearingAccuracy(int accuracy) {
- if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_HIGH) {
- throw new IllegalArgumentException("accuracy=" + accuracy);
- }
- mBearingAccuracy = accuracy;
+ public void setBearingAccuracy(@AccuracyRequirement int accuracy) {
+ mBearingAccuracy = Preconditions.checkArgumentInRange(accuracy, NO_REQUIREMENT,
+ ACCURACY_HIGH, "accuracy");
}
/**
* Returns a constant indicating the desired bearing accuracy.
- * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_HIGH},
- * or {@link #NO_REQUIREMENT}.
+ *
+ * @see #setBearingAccuracy(int)
*/
+ @AccuracyRequirement
public int getBearingAccuracy() {
return mBearingAccuracy;
}
/**
- * Indicates the desired accuracy for latitude and longitude. Accuracy
- * may be {@link #ACCURACY_FINE} if desired location
- * is fine, else it can be {@link #ACCURACY_COARSE}.
- * More accurate location may consume more power and may take longer.
+ * Indicates the desired accuracy for latitude and longitude. Accuracy may be
+ * {@link #ACCURACY_FINE} or {@link #ACCURACY_COARSE}. More accurate location may consume more
+ * power and may take longer.
*
* @throws IllegalArgumentException if accuracy is not one of the supported constants
*/
- public void setAccuracy(int accuracy) {
- if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_COARSE) {
- throw new IllegalArgumentException("accuracy=" + accuracy);
- }
- if (accuracy == ACCURACY_FINE) {
- mHorizontalAccuracy = ACCURACY_HIGH;
- } else {
- mHorizontalAccuracy = ACCURACY_LOW;
+ public void setAccuracy(@LocationAccuracyRequirement int accuracy) {
+ Preconditions.checkArgumentInRange(accuracy, NO_REQUIREMENT, ACCURACY_COARSE, "accuracy");
+ switch (accuracy) {
+ case NO_REQUIREMENT:
+ setHorizontalAccuracy(NO_REQUIREMENT);
+ break;
+ case ACCURACY_FINE:
+ setHorizontalAccuracy(ACCURACY_HIGH);
+ break;
+ case ACCURACY_COARSE:
+ setHorizontalAccuracy(ACCURACY_LOW);
+ break;
}
}
/**
- * Returns a constant indicating desired accuracy of location
- * Accuracy may be {@link #ACCURACY_FINE} if desired location
- * is fine, else it can be {@link #ACCURACY_COARSE}.
+ * Returns a constant indicating desired accuracy of location.
+ *
+ * @see #setAccuracy(int)
*/
+ @LocationAccuracyRequirement
public int getAccuracy() {
if (mHorizontalAccuracy >= ACCURACY_HIGH) {
return ACCURACY_FINE;
@@ -243,21 +266,20 @@ public class Criteria implements Parcelable {
}
/**
- * Indicates the desired maximum power level. The level parameter
- * must be one of NO_REQUIREMENT, POWER_LOW, POWER_MEDIUM, or
- * POWER_HIGH.
+ * Indicates the desired maximum power requirement. The power requirement parameter may be
+ * {@link #NO_REQUIREMENT}, {@link #POWER_LOW}, {@link #POWER_MEDIUM}, or {@link #POWER_HIGH}.
*/
- public void setPowerRequirement(int level) {
- if (level < NO_REQUIREMENT || level > POWER_HIGH) {
- throw new IllegalArgumentException("level=" + level);
- }
- mPowerRequirement = level;
+ public void setPowerRequirement(@PowerRequirement int powerRequirement) {
+ mPowerRequirement = Preconditions.checkArgumentInRange(powerRequirement, NO_REQUIREMENT,
+ POWER_HIGH, "powerRequirement");
}
/**
- * Returns a constant indicating the desired power requirement. The
- * returned
+ * Returns a constant indicating the desired maximum power requirement.
+ *
+ * @see #setPowerRequirement(int)
*/
+ @PowerRequirement
public int getPowerRequirement() {
return mPowerRequirement;
}
@@ -277,8 +299,8 @@ public class Criteria implements Parcelable {
}
/**
- * Indicates whether the provider must provide altitude information.
- * Not all fixes are guaranteed to contain such information.
+ * Indicates whether the provider must provide altitude information. Not all fixes are
+ * guaranteed to contain such information.
*/
public void setAltitudeRequired(boolean altitudeRequired) {
mAltitudeRequired = altitudeRequired;
@@ -286,15 +308,16 @@ public class Criteria implements Parcelable {
/**
* Returns whether the provider must provide altitude information.
- * Not all fixes are guaranteed to contain such information.
+ *
+ * @see #setAltitudeRequired(boolean)
*/
public boolean isAltitudeRequired() {
return mAltitudeRequired;
}
/**
- * Indicates whether the provider must provide speed information.
- * Not all fixes are guaranteed to contain such information.
+ * Indicates whether the provider must provide speed information. Not all fixes are guaranteed
+ * to contain such information.
*/
public void setSpeedRequired(boolean speedRequired) {
mSpeedRequired = speedRequired;
@@ -302,15 +325,16 @@ public class Criteria implements Parcelable {
/**
* Returns whether the provider must provide speed information.
- * Not all fixes are guaranteed to contain such information.
+ *
+ * @see #setSpeedRequired(boolean)
*/
public boolean isSpeedRequired() {
return mSpeedRequired;
}
/**
- * Indicates whether the provider must provide bearing information.
- * Not all fixes are guaranteed to contain such information.
+ * Indicates whether the provider must provide bearing information. Not all fixes are guaranteed
+ * to contain such information.
*/
public void setBearingRequired(boolean bearingRequired) {
mBearingRequired = bearingRequired;
@@ -318,34 +342,36 @@ public class Criteria implements Parcelable {
/**
* Returns whether the provider must provide bearing information.
- * Not all fixes are guaranteed to contain such information.
+ *
+ * @see #setBearingRequired(boolean)
*/
public boolean isBearingRequired() {
return mBearingRequired;
}
- public static final @android.annotation.NonNull Parcelable.Creator<Criteria> CREATOR =
- new Parcelable.Creator<Criteria>() {
- @Override
- public Criteria createFromParcel(Parcel in) {
- Criteria c = new Criteria();
- c.mHorizontalAccuracy = in.readInt();
- c.mVerticalAccuracy = in.readInt();
- c.mSpeedAccuracy = in.readInt();
- c.mBearingAccuracy = in.readInt();
- c.mPowerRequirement = in.readInt();
- c.mAltitudeRequired = in.readInt() != 0;
- c.mBearingRequired = in.readInt() != 0;
- c.mSpeedRequired = in.readInt() != 0;
- c.mCostAllowed = in.readInt() != 0;
- return c;
- }
-
- @Override
- public Criteria[] newArray(int size) {
- return new Criteria[size];
- }
- };
+ @NonNull
+ public static final Parcelable.Creator<Criteria> CREATOR =
+ new Parcelable.Creator<Criteria>() {
+ @Override
+ public Criteria createFromParcel(Parcel in) {
+ Criteria c = new Criteria();
+ c.mHorizontalAccuracy = in.readInt();
+ c.mVerticalAccuracy = in.readInt();
+ c.mSpeedAccuracy = in.readInt();
+ c.mBearingAccuracy = in.readInt();
+ c.mPowerRequirement = in.readInt();
+ c.mAltitudeRequired = in.readInt() != 0;
+ c.mBearingRequired = in.readInt() != 0;
+ c.mSpeedRequired = in.readInt() != 0;
+ c.mCostAllowed = in.readInt() != 0;
+ return c;
+ }
+
+ @Override
+ public Criteria[] newArray(int size) {
+ return new Criteria[size];
+ }
+ };
@Override
public int describeContents() {
@@ -365,42 +391,57 @@ public class Criteria implements Parcelable {
parcel.writeInt(mCostAllowed ? 1 : 0);
}
- private static String powerToString(int power) {
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ s.append("Criteria[");
+ s.append("power=").append(requirementToString(mPowerRequirement)).append(", ");
+ s.append("accuracy=").append(requirementToString(mHorizontalAccuracy));
+ if (mVerticalAccuracy != NO_REQUIREMENT) {
+ s.append(", verticalAccuracy=").append(requirementToString(mVerticalAccuracy));
+ }
+ if (mSpeedAccuracy != NO_REQUIREMENT) {
+ s.append(", speedAccuracy=").append(requirementToString(mSpeedAccuracy));
+ }
+ if (mBearingAccuracy != NO_REQUIREMENT) {
+ s.append(", bearingAccuracy=").append(requirementToString(mBearingAccuracy));
+ }
+ if (mAltitudeRequired || mBearingRequired || mSpeedRequired) {
+ s.append(", required=[");
+ if (mAltitudeRequired) {
+ s.append("altitude, ");
+ }
+ if (mBearingRequired) {
+ s.append("bearing, ");
+ }
+ if (mSpeedRequired) {
+ s.append("speed, ");
+ }
+ s.setLength(s.length() - 2);
+ s.append("]");
+ }
+ if (mCostAllowed) {
+ s.append(", costAllowed");
+ }
+ s.append(']');
+ return s.toString();
+ }
+
+ private static String requirementToString(int power) {
switch (power) {
case NO_REQUIREMENT:
- return "NO_REQ";
+ return "None";
+ //case ACCURACY_LOW:
case POWER_LOW:
- return "LOW";
+ return "Low";
+ //case ACCURACY_MEDIUM:
case POWER_MEDIUM:
- return "MEDIUM";
+ return "Medium";
+ //case ACCURACY_HIGH:
case POWER_HIGH:
- return "HIGH";
+ return "High";
default:
return "???";
}
}
-
- private static String accuracyToString(int accuracy) {
- switch (accuracy) {
- case NO_REQUIREMENT:
- return "---";
- case ACCURACY_HIGH:
- return "HIGH";
- case ACCURACY_MEDIUM:
- return "MEDIUM";
- case ACCURACY_LOW:
- return "LOW";
- default:
- return "???";
- }
- }
-
- @Override
- public String toString() {
- StringBuilder s = new StringBuilder();
- s.append("Criteria[power=").append(powerToString(mPowerRequirement));
- s.append(" acc=").append(accuracyToString(mHorizontalAccuracy));
- s.append(']');
- return s.toString();
- }
}
diff --git a/location/java/com/android/internal/location/ProviderProperties.java b/location/java/com/android/internal/location/ProviderProperties.java
index def96f0fb674..68f9ec3c530b 100644
--- a/location/java/com/android/internal/location/ProviderProperties.java
+++ b/location/java/com/android/internal/location/ProviderProperties.java
@@ -16,15 +16,36 @@
package com.android.internal.location;
+import android.annotation.IntDef;
+import android.location.Criteria;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A Parcelable containing (legacy) location provider properties.
* This object is just used inside the framework and system services.
+ *
* @hide
*/
public final class ProviderProperties implements Parcelable {
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({Criteria.POWER_LOW, Criteria.POWER_MEDIUM, Criteria.POWER_HIGH})
+ public @interface PowerRequirement {
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({Criteria.ACCURACY_FINE, Criteria.ACCURACY_COARSE})
+ public @interface Accuracy {
+ }
+
/**
* True if provider requires access to a
* data network (e.g., the Internet), false otherwise.
@@ -79,58 +100,58 @@ public final class ProviderProperties implements Parcelable {
/**
* Power requirement for this provider.
- *
- * @return the power requirement for this provider, as one of the
- * constants Criteria.POWER_*.
*/
+ @PowerRequirement
public final int mPowerRequirement;
/**
* Constant describing the horizontal accuracy returned
* by this provider.
- *
- * @return the horizontal accuracy for this provider, as one of the
- * constants Criteria.ACCURACY_COARSE or Criteria.ACCURACY_FINE
*/
+ @Accuracy
public final int mAccuracy;
- public ProviderProperties(boolean mRequiresNetwork,
- boolean mRequiresSatellite, boolean mRequiresCell, boolean mHasMonetaryCost,
- boolean mSupportsAltitude, boolean mSupportsSpeed, boolean mSupportsBearing,
- int mPowerRequirement, int mAccuracy) {
- this.mRequiresNetwork = mRequiresNetwork;
- this.mRequiresSatellite = mRequiresSatellite;
- this.mRequiresCell = mRequiresCell;
- this.mHasMonetaryCost = mHasMonetaryCost;
- this.mSupportsAltitude = mSupportsAltitude;
- this.mSupportsSpeed = mSupportsSpeed;
- this.mSupportsBearing = mSupportsBearing;
- this.mPowerRequirement = mPowerRequirement;
- this.mAccuracy = mAccuracy;
+ public ProviderProperties(boolean requiresNetwork, boolean requiresSatellite,
+ boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
+ boolean supportsSpeed, boolean supportsBearing, @PowerRequirement int powerRequirement,
+ @Accuracy int accuracy) {
+ mRequiresNetwork = requiresNetwork;
+ mRequiresSatellite = requiresSatellite;
+ mRequiresCell = requiresCell;
+ mHasMonetaryCost = hasMonetaryCost;
+ mSupportsAltitude = supportsAltitude;
+ mSupportsSpeed = supportsSpeed;
+ mSupportsBearing = supportsBearing;
+ mPowerRequirement = Preconditions.checkArgumentInRange(powerRequirement, Criteria.POWER_LOW,
+ Criteria.POWER_HIGH, "powerRequirement");
+ mAccuracy = Preconditions.checkArgumentInRange(accuracy, Criteria.ACCURACY_FINE,
+ Criteria.ACCURACY_COARSE, "accuracy");
}
public static final Parcelable.Creator<ProviderProperties> CREATOR =
new Parcelable.Creator<ProviderProperties>() {
- @Override
- public ProviderProperties createFromParcel(Parcel in) {
- boolean requiresNetwork = in.readInt() == 1;
- boolean requiresSatellite = in.readInt() == 1;
- boolean requiresCell = in.readInt() == 1;
- boolean hasMonetaryCost = in.readInt() == 1;
- boolean supportsAltitude = in.readInt() == 1;
- boolean supportsSpeed = in.readInt() == 1;
- boolean supportsBearing = in.readInt() == 1;
- int powerRequirement = in.readInt();
- int accuracy = in.readInt();
- return new ProviderProperties(requiresNetwork, requiresSatellite,
- requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing,
- powerRequirement, accuracy);
- }
- @Override
- public ProviderProperties[] newArray(int size) {
- return new ProviderProperties[size];
- }
- };
+ @Override
+ public ProviderProperties createFromParcel(Parcel in) {
+ boolean requiresNetwork = in.readInt() == 1;
+ boolean requiresSatellite = in.readInt() == 1;
+ boolean requiresCell = in.readInt() == 1;
+ boolean hasMonetaryCost = in.readInt() == 1;
+ boolean supportsAltitude = in.readInt() == 1;
+ boolean supportsSpeed = in.readInt() == 1;
+ boolean supportsBearing = in.readInt() == 1;
+ int powerRequirement = in.readInt();
+ int accuracy = in.readInt();
+ return new ProviderProperties(requiresNetwork, requiresSatellite,
+ requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
+ supportsBearing,
+ powerRequirement, accuracy);
+ }
+
+ @Override
+ public ProviderProperties[] newArray(int size) {
+ return new ProviderProperties[size];
+ }
+ };
@Override
public int describeContents() {
@@ -149,4 +170,67 @@ public final class ProviderProperties implements Parcelable {
parcel.writeInt(mPowerRequirement);
parcel.writeInt(mAccuracy);
}
+
+ @Override
+ public String toString() {
+ StringBuilder b = new StringBuilder("ProviderProperties[");
+ b.append("power=").append(powerToString(mPowerRequirement)).append(", ");
+ b.append("accuracy=").append(accuracyToString(mAccuracy));
+ if (mRequiresNetwork || mRequiresSatellite || mRequiresCell) {
+ b.append(", requires=");
+ if (mRequiresNetwork) {
+ b.append("network,");
+ }
+ if (mRequiresSatellite) {
+ b.append("satellite,");
+ }
+ if (mRequiresCell) {
+ b.append("cell,");
+ }
+ b.setLength(b.length() - 1);
+ }
+ if (mHasMonetaryCost) {
+ b.append(", hasMonetaryCost");
+ }
+ if (mSupportsBearing || mSupportsSpeed || mSupportsAltitude) {
+ b.append(", supports=[");
+ if (mSupportsBearing) {
+ b.append("bearing, ");
+ }
+ if (mSupportsSpeed) {
+ b.append("speed, ");
+ }
+ if (mSupportsAltitude) {
+ b.append("altitude, ");
+ }
+ b.setLength(b.length() - 2);
+ b.append("]");
+ }
+ b.append("]");
+ return b.toString();
+ }
+
+ private static String powerToString(@PowerRequirement int power) {
+ switch (power) {
+ case Criteria.POWER_LOW:
+ return "Low";
+ case Criteria.POWER_MEDIUM:
+ return "Medium";
+ case Criteria.POWER_HIGH:
+ return "High";
+ default:
+ return "???";
+ }
+ }
+
+ private static String accuracyToString(@Accuracy int accuracy) {
+ switch (accuracy) {
+ case Criteria.ACCURACY_COARSE:
+ return "Coarse";
+ case Criteria.ACCURACY_FINE:
+ return "Fine";
+ default:
+ return "???";
+ }
+ }
}
diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java
index c23f49976799..8d8df4533ebe 100644
--- a/location/java/com/android/internal/location/ProviderRequest.java
+++ b/location/java/com/android/internal/location/ProviderRequest.java
@@ -20,33 +20,42 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.location.LocationRequest;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.WorkSource;
import android.util.TimeUtils;
+import com.android.internal.util.Preconditions;
+
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/** @hide */
public final class ProviderRequest implements Parcelable {
+
+ public static final ProviderRequest EMPTY_REQUEST = new ProviderRequest(false, Long.MAX_VALUE,
+ false, false,
+ Collections.emptyList(), new WorkSource());
+
/** Location reporting is requested (true) */
@UnsupportedAppUsage
- public boolean reportLocation = false;
+ public final boolean reportLocation;
/** The smallest requested interval */
@UnsupportedAppUsage
- public long interval = Long.MAX_VALUE;
+ public final long interval;
/**
- * When this flag is true, providers should ignore all location settings, user consents, power
- * restrictions or any other restricting factors and always satisfy this request to the best of
- * their ability. This flag should only be used in event of an emergency.
+ * Whether provider shall make stronger than normal tradeoffs to substantially restrict power
+ * use.
*/
- public boolean locationSettingsIgnored = false;
+ public final boolean lowPowerMode;
/**
- * Whether provider shall make stronger than normal tradeoffs to substantially restrict power
- * use.
+ * When this flag is true, providers should ignore all location settings, user consents, power
+ * restrictions or any other restricting factors and always satisfy this request to the best of
+ * their ability. This flag should only be used in event of an emergency.
*/
- public boolean lowPowerMode = false;
+ public final boolean locationSettingsIgnored;
/**
* A more detailed set of requests.
@@ -56,26 +65,37 @@ public final class ProviderRequest implements Parcelable {
* low power fast interval request.
*/
@UnsupportedAppUsage
- public final List<LocationRequest> locationRequests = new ArrayList<>();
+ public final List<LocationRequest> locationRequests;
- @UnsupportedAppUsage
- public ProviderRequest() {
+ public final WorkSource workSource;
+
+ private ProviderRequest(boolean reportLocation, long interval, boolean lowPowerMode,
+ boolean locationSettingsIgnored, List<LocationRequest> locationRequests,
+ WorkSource workSource) {
+ this.reportLocation = reportLocation;
+ this.interval = interval;
+ this.lowPowerMode = lowPowerMode;
+ this.locationSettingsIgnored = locationSettingsIgnored;
+ this.locationRequests = Preconditions.checkNotNull(locationRequests);
+ this.workSource = Preconditions.checkNotNull(workSource);
}
public static final Parcelable.Creator<ProviderRequest> CREATOR =
new Parcelable.Creator<ProviderRequest>() {
@Override
public ProviderRequest createFromParcel(Parcel in) {
- ProviderRequest request = new ProviderRequest();
- request.reportLocation = in.readInt() == 1;
- request.interval = in.readLong();
- request.lowPowerMode = in.readBoolean();
- request.locationSettingsIgnored = in.readBoolean();
+ boolean reportLocation = in.readInt() == 1;
+ long interval = in.readLong();
+ boolean lowPowerMode = in.readBoolean();
+ boolean locationSettingsIgnored = in.readBoolean();
int count = in.readInt();
+ ArrayList<LocationRequest> locationRequests = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
- request.locationRequests.add(LocationRequest.CREATOR.createFromParcel(in));
+ locationRequests.add(LocationRequest.CREATOR.createFromParcel(in));
}
- return request;
+ WorkSource workSource = in.readParcelable(null);
+ return new ProviderRequest(reportLocation, interval, lowPowerMode,
+ locationSettingsIgnored, locationRequests, workSource);
}
@Override
@@ -106,14 +126,13 @@ public final class ProviderRequest implements Parcelable {
StringBuilder s = new StringBuilder();
s.append("ProviderRequest[");
if (reportLocation) {
- s.append("ON");
- s.append(" interval=");
+ s.append("interval=");
TimeUtils.formatDuration(interval, s);
if (lowPowerMode) {
- s.append(" lowPowerMode");
+ s.append(", lowPowerMode");
}
if (locationSettingsIgnored) {
- s.append(" locationSettingsIgnored");
+ s.append(", locationSettingsIgnored");
}
} else {
s.append("OFF");
@@ -121,4 +140,67 @@ public final class ProviderRequest implements Parcelable {
s.append(']');
return s.toString();
}
+
+ /**
+ * A Builder for {@link ProviderRequest}s.
+ */
+ public static class Builder {
+ private long mInterval = Long.MAX_VALUE;
+ private boolean mLowPowerMode;
+ private boolean mLocationSettingsIgnored;
+ private List<LocationRequest> mLocationRequests = Collections.emptyList();
+ private WorkSource mWorkSource = new WorkSource();
+
+ public long getInterval() {
+ return mInterval;
+ }
+
+ public void setInterval(long interval) {
+ this.mInterval = interval;
+ }
+
+ public boolean isLowPowerMode() {
+ return mLowPowerMode;
+ }
+
+ public void setLowPowerMode(boolean lowPowerMode) {
+ this.mLowPowerMode = lowPowerMode;
+ }
+
+ public boolean isLocationSettingsIgnored() {
+ return mLocationSettingsIgnored;
+ }
+
+ public void setLocationSettingsIgnored(boolean locationSettingsIgnored) {
+ this.mLocationSettingsIgnored = locationSettingsIgnored;
+ }
+
+ public List<LocationRequest> getLocationRequests() {
+ return mLocationRequests;
+ }
+
+ public void setLocationRequests(List<LocationRequest> locationRequests) {
+ this.mLocationRequests = Preconditions.checkNotNull(locationRequests);
+ }
+
+ public WorkSource getWorkSource() {
+ return mWorkSource;
+ }
+
+ public void setWorkSource(WorkSource workSource) {
+ mWorkSource = Preconditions.checkNotNull(workSource);
+ }
+
+ /**
+ * Builds a ProviderRequest object with the set information.
+ */
+ public ProviderRequest build() {
+ if (mInterval == Long.MAX_VALUE) {
+ return EMPTY_REQUEST;
+ } else {
+ return new ProviderRequest(true, mInterval, mLowPowerMode,
+ mLocationSettingsIgnored, mLocationRequests, mWorkSource);
+ }
+ }
+ }
}
diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl
index 02a381669893..28bf84d6e079 100644
--- a/media/java/android/media/IMediaRoute2Provider.aidl
+++ b/media/java/android/media/IMediaRoute2Provider.aidl
@@ -24,13 +24,12 @@ import android.media.IMediaRoute2ProviderClient;
*/
oneway interface IMediaRoute2Provider {
void setClient(IMediaRoute2ProviderClient client);
- void requestCreateSession(String packageName, String routeId,
- String controlCategory, long requestId);
- void releaseSession(int sessionId);
+ void requestCreateSession(String packageName, String routeId, String routeType, long requestId);
+ void releaseSession(String sessionId);
- void selectRoute(int sessionId, String routeId);
- void deselectRoute(int sessionId, String routeId);
- void transferToRoute(int sessionId, String routeId);
+ void selectRoute(String sessionId, String routeId);
+ void deselectRoute(String sessionId, String routeId);
+ void transferToRoute(String sessionId, String routeId);
void notifyControlRequestSent(String id, in Intent request);
void requestSetVolume(String id, int volume);
diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index b7cb7059ce3d..e8af21e59cc1 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -24,7 +24,7 @@ import android.media.MediaRoute2Info;
*/
oneway interface IMediaRouter2Manager {
void notifyRouteSelected(String packageName, in MediaRoute2Info route);
- void notifyControlCategoriesChanged(String packageName, in List<String> categories);
+ void notifyRouteTypesChanged(String packageName, in List<String> routeTypes);
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
void notifyRoutesChanged(in List<MediaRoute2Info> routes);
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index e5b62ff10aa6..b573f64da51d 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -22,6 +22,7 @@ import android.media.IMediaRouter2Manager;
import android.media.IMediaRouterClient;
import android.media.MediaRoute2Info;
import android.media.MediaRouterClientState;
+import android.media.RouteDiscoveryRequest;
import android.media.RouteSessionInfo;
/**
@@ -51,8 +52,8 @@ interface IMediaRouterService {
void requestUpdateVolume2(IMediaRouter2Client client, in MediaRoute2Info route, int direction);
void requestCreateSession(IMediaRouter2Client client, in MediaRoute2Info route,
- String controlCategory, int requestId);
- void setControlCategories(IMediaRouter2Client client, in List<String> categories);
+ String routeType, int requestId);
+ void setDiscoveryRequest2(IMediaRouter2Client client, in RouteDiscoveryRequest request);
void selectRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route);
void deselectRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route);
void transferToRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route);
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 7fca03cdfd57..4cd581b6628c 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -354,8 +355,8 @@ public class MediaMetadataRetriever implements AutoCloseable {
* is less than or equal to 0.
* @see {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)}
*/
- public @Nullable Bitmap getScaledFrameAtTime(
- long timeUs, @Option int option, int dstWidth, int dstHeight) {
+ public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
+ @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight) {
validate(option, dstWidth, dstHeight);
return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, null);
}
@@ -400,7 +401,8 @@ public class MediaMetadataRetriever implements AutoCloseable {
* @see {@link #getScaledFrameAtTime(long, int, int, int)}
*/
public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
- int dstWidth, int dstHeight, @NonNull BitmapParams params) {
+ @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight,
+ @NonNull BitmapParams params) {
validate(option, dstWidth, dstHeight);
return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, params);
}
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 506d6165bbfa..1ed53d942b63 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -16,6 +16,8 @@
package android.media;
+import static android.media.MediaRouter2Utils.toUniqueId;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -83,12 +85,14 @@ public final class MediaRoute2Info implements Parcelable {
* controlled from this object. An example of fixed playback volume is a remote player,
* playing over HDMI where the user prefers to control the volume on the HDMI sink, rather
* than attenuate at the source.
+ *
* @see #getVolumeHandling()
*/
public static final int PLAYBACK_VOLUME_FIXED = 0;
/**
* Playback information indicating the playback volume is variable and can be controlled
* from this object.
+ *
* @see #getVolumeHandling()
*/
public static final int PLAYBACK_VOLUME_VARIABLE = 1;
@@ -148,7 +152,7 @@ public final class MediaRoute2Info implements Parcelable {
@Nullable
final String mClientPackageName;
@NonNull
- final List<String> mSupportedCategories;
+ final List<String> mRouteTypes;
final int mVolume;
final int mVolumeMax;
final int mVolumeHandling;
@@ -156,8 +160,6 @@ public final class MediaRoute2Info implements Parcelable {
@Nullable
final Bundle mExtras;
- private final String mUniqueId;
-
MediaRoute2Info(@NonNull Builder builder) {
mId = builder.mId;
mProviderId = builder.mProviderId;
@@ -166,13 +168,12 @@ public final class MediaRoute2Info implements Parcelable {
mConnectionState = builder.mConnectionState;
mIconUri = builder.mIconUri;
mClientPackageName = builder.mClientPackageName;
- mSupportedCategories = builder.mSupportedCategories;
+ mRouteTypes = builder.mRouteTypes;
mVolume = builder.mVolume;
mVolumeMax = builder.mVolumeMax;
mVolumeHandling = builder.mVolumeHandling;
mDeviceType = builder.mDeviceType;
mExtras = builder.mExtras;
- mUniqueId = createUniqueId();
}
MediaRoute2Info(@NonNull Parcel in) {
@@ -183,25 +184,12 @@ public final class MediaRoute2Info implements Parcelable {
mConnectionState = in.readInt();
mIconUri = in.readParcelable(null);
mClientPackageName = in.readString();
- mSupportedCategories = in.createStringArrayList();
+ mRouteTypes = in.createStringArrayList();
mVolume = in.readInt();
mVolumeMax = in.readInt();
mVolumeHandling = in.readInt();
mDeviceType = in.readInt();
mExtras = in.readBundle();
- mUniqueId = createUniqueId();
- }
-
- private String createUniqueId() {
- String uniqueId = null;
- if (mProviderId != null) {
- uniqueId = toUniqueId(mProviderId, mId);
- }
- return uniqueId;
- }
-
- static String toUniqueId(String providerId, String routeId) {
- return providerId + ":" + routeId;
}
/**
@@ -235,7 +223,7 @@ public final class MediaRoute2Info implements Parcelable {
&& (mConnectionState == other.mConnectionState)
&& Objects.equals(mIconUri, other.mIconUri)
&& Objects.equals(mClientPackageName, other.mClientPackageName)
- && Objects.equals(mSupportedCategories, other.mSupportedCategories)
+ && Objects.equals(mRouteTypes, other.mRouteTypes)
&& (mVolume == other.mVolume)
&& (mVolumeMax == other.mVolumeMax)
&& (mVolumeHandling == other.mVolumeHandling)
@@ -247,29 +235,34 @@ public final class MediaRoute2Info implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mId, mName, mDescription, mConnectionState, mIconUri,
- mSupportedCategories, mVolume, mVolumeMax, mVolumeHandling, mDeviceType);
+ mRouteTypes, mVolume, mVolumeMax, mVolumeHandling, mDeviceType);
}
/**
- * Gets the id of the route.
- * Use {@link #getUniqueId()} if you need a unique identifier.
+ * Gets the id of the route. The routes which are given by {@link MediaRouter2} will have
+ * unique IDs.
+ * <p>
+ * In order to ensure uniqueness in {@link MediaRouter2} side, the value of this method
+ * can be different from what was set in {@link MediaRoute2ProviderService}.
*
- * @see #getUniqueId()
+ * @see Builder#setId(String)
*/
@NonNull
public String getId() {
- return mId;
+ if (mProviderId != null) {
+ return toUniqueId(mProviderId, mId);
+ } else {
+ return mId;
+ }
}
/**
- * Gets the unique id of the route. A route obtained from
- * {@link com.android.server.media.MediaRouterService} always has a unique id.
- *
- * @return unique id of the route or null if it has no unique id.
+ * Gets the original id set by {@link Builder#setId(String)}.
+ * @hide
*/
- @Nullable
- public String getUniqueId() {
- return mUniqueId;
+ @NonNull
+ public String getOriginalId() {
+ return mId;
}
/**
@@ -331,8 +324,8 @@ public final class MediaRoute2Info implements Parcelable {
* Gets the supported categories of the route.
*/
@NonNull
- public List<String> getSupportedCategories() {
- return mSupportedCategories;
+ public List<String> getRouteTypes() {
+ return mRouteTypes;
}
//TODO: once device types are confirmed, reflect those into the comment.
@@ -376,32 +369,15 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
- * Returns if the route supports the specified control category
+ * Returns if the route contains at least one of the specified route types.
*
- * @param controlCategory control category to consider
- * @return true if the route supports at the category
+ * @param routeTypes the list of route types to consider
+ * @return true if the route contains at least one type in the list
*/
- public boolean supportsControlCategory(@NonNull String controlCategory) {
- Objects.requireNonNull(controlCategory, "control category must not be null");
- for (String supportedCategory : getSupportedCategories()) {
- if (TextUtils.equals(controlCategory, supportedCategory)) {
- return true;
- }
- }
- return false;
- }
-
- //TODO: Move this if we re-define control category / selector things.
- /**
- * Returns if the route supports at least one of the specified control categories
- *
- * @param controlCategories the list of control categories to consider
- * @return true if the route supports at least one category
- */
- public boolean supportsControlCategories(@NonNull Collection<String> controlCategories) {
- Objects.requireNonNull(controlCategories, "control categories must not be null");
- for (String controlCategory : controlCategories) {
- if (supportsControlCategory(controlCategory)) {
+ public boolean containsRouteTypes(@NonNull Collection<String> routeTypes) {
+ Objects.requireNonNull(routeTypes, "routeTypes must not be null");
+ for (String routeType : routeTypes) {
+ if (getRouteTypes().contains(routeType)) {
return true;
}
}
@@ -422,7 +398,7 @@ public final class MediaRoute2Info implements Parcelable {
dest.writeInt(mConnectionState);
dest.writeParcelable(mIconUri, flags);
dest.writeString(mClientPackageName);
- dest.writeStringList(mSupportedCategories);
+ dest.writeStringList(mRouteTypes);
dest.writeInt(mVolume);
dest.writeInt(mVolumeMax);
dest.writeInt(mVolumeHandling);
@@ -460,7 +436,7 @@ public final class MediaRoute2Info implements Parcelable {
int mConnectionState;
Uri mIconUri;
String mClientPackageName;
- List<String> mSupportedCategories;
+ List<String> mRouteTypes;
int mVolume;
int mVolumeMax;
int mVolumeHandling = PLAYBACK_VOLUME_FIXED;
@@ -471,7 +447,7 @@ public final class MediaRoute2Info implements Parcelable {
public Builder(@NonNull String id, @NonNull CharSequence name) {
setId(id);
setName(name);
- mSupportedCategories = new ArrayList<>();
+ mRouteTypes = new ArrayList<>();
}
public Builder(@NonNull MediaRoute2Info routeInfo) {
@@ -488,7 +464,7 @@ public final class MediaRoute2Info implements Parcelable {
mConnectionState = routeInfo.mConnectionState;
mIconUri = routeInfo.mIconUri;
setClientPackageName(routeInfo.mClientPackageName);
- setSupportedCategories(routeInfo.mSupportedCategories);
+ setRouteTypes(routeInfo.mRouteTypes);
setVolume(routeInfo.mVolume);
setVolumeMax(routeInfo.mVolumeMax);
setVolumeHandling(routeInfo.mVolumeHandling);
@@ -499,7 +475,15 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
- * Sets the unique id of the route.
+ * Sets the unique id of the route. The value given here must be unique for each of your
+ * route.
+ * <p>
+ * In order to ensure uniqueness in {@link MediaRouter2} side, the value of
+ * {@link MediaRoute2Info#getId()} can be different from what was set in
+ * {@link MediaRoute2ProviderService}.
+ * </p>
+ *
+ * @see MediaRoute2Info#getId()
*/
@NonNull
public Builder setId(@NonNull String id) {
@@ -585,35 +569,35 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
- * Sets the supported categories of the route.
+ * Sets the types of the route.
*/
@NonNull
- public Builder setSupportedCategories(@NonNull Collection<String> categories) {
- mSupportedCategories = new ArrayList<>();
- return addSupportedCategories(categories);
+ public Builder setRouteTypes(@NonNull Collection<String> routeTypes) {
+ mRouteTypes = new ArrayList<>();
+ return addRouteTypes(routeTypes);
}
/**
- * Adds supported categories for the route.
+ * Adds types for the route.
*/
@NonNull
- public Builder addSupportedCategories(@NonNull Collection<String> categories) {
- Objects.requireNonNull(categories, "categories must not be null");
- for (String category: categories) {
- addSupportedCategory(category);
+ public Builder addRouteTypes(@NonNull Collection<String> routeTypes) {
+ Objects.requireNonNull(routeTypes, "routeTypes must not be null");
+ for (String routeType: routeTypes) {
+ addRouteType(routeType);
}
return this;
}
/**
- * Add a supported category for the route.
+ * Add a type for the route.
*/
@NonNull
- public Builder addSupportedCategory(@NonNull String category) {
- if (TextUtils.isEmpty(category)) {
- throw new IllegalArgumentException("category must not be null or empty");
+ public Builder addRouteType(@NonNull String routeType) {
+ if (TextUtils.isEmpty(routeType)) {
+ throw new IllegalArgumentException("routeType must not be null or empty");
}
- mSupportedCategories.add(category);
+ mRouteTypes.add(routeType);
return this;
}
diff --git a/media/java/android/media/MediaRoute2ProviderInfo.java b/media/java/android/media/MediaRoute2ProviderInfo.java
index 7078d4a0b568..e2f246cae8c2 100644
--- a/media/java/android/media/MediaRoute2ProviderInfo.java
+++ b/media/java/android/media/MediaRoute2ProviderInfo.java
@@ -25,6 +25,7 @@ import android.util.ArrayMap;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Map;
import java.util.Objects;
/**
@@ -161,14 +162,17 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
return this;
}
mUniqueId = uniqueId;
- final int count = mRoutes.size();
- for (int i = 0; i < count; i++) {
- MediaRoute2Info route = mRoutes.valueAt(i);
- mRoutes.setValueAt(i, new MediaRoute2Info.Builder(route)
+
+ final ArrayMap<String, MediaRoute2Info> newRoutes = new ArrayMap<>();
+ for (Map.Entry<String, MediaRoute2Info> entry : mRoutes.entrySet()) {
+ MediaRoute2Info routeWithProviderId = new MediaRoute2Info.Builder(entry.getValue())
.setProviderId(mUniqueId)
- .build());
+ .build();
+ newRoutes.put(routeWithProviderId.getId(), routeWithProviderId);
}
+ mRoutes.clear();
+ mRoutes.putAll(newRoutes);
return this;
}
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 99bd1dcde3bb..24b65baebcbd 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -29,6 +29,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -55,7 +56,7 @@ public abstract class MediaRoute2ProviderService extends Service {
private MediaRoute2ProviderInfo mProviderInfo;
@GuardedBy("mSessionLock")
- private ArrayMap<Integer, RouteSessionInfo> mSessionInfo = new ArrayMap<>();
+ private ArrayMap<String, RouteSessionInfo> mSessionInfo = new ArrayMap<>();
public MediaRoute2ProviderService() {
mHandler = new Handler(Looper.getMainLooper());
@@ -106,7 +107,10 @@ public abstract class MediaRoute2ProviderService extends Service {
* null if the session is destroyed or id is not valid.
*/
@Nullable
- public final RouteSessionInfo getSessionInfo(int sessionId) {
+ public final RouteSessionInfo getSessionInfo(@NonNull String sessionId) {
+ if (TextUtils.isEmpty(sessionId)) {
+ throw new IllegalArgumentException("sessionId must not be empty");
+ }
synchronized (mSessionLock) {
return mSessionInfo.get(sessionId);
}
@@ -134,7 +138,7 @@ public abstract class MediaRoute2ProviderService extends Service {
*/
public final void updateSessionInfo(@NonNull RouteSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- int sessionId = sessionInfo.getSessionId();
+ String sessionId = sessionInfo.getId();
if (sessionInfo.getSelectedRoutes().isEmpty()) {
releaseSession(sessionId);
return;
@@ -160,7 +164,7 @@ public abstract class MediaRoute2ProviderService extends Service {
public final void notifySessionInfoChanged(@NonNull RouteSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- int sessionId = sessionInfo.getSessionId();
+ String sessionId = sessionInfo.getId();
synchronized (mSessionLock) {
if (mSessionInfo.containsKey(sessionId)) {
mSessionInfo.put(sessionId, sessionInfo);
@@ -185,7 +189,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* controlled, pass a {@link Bundle} that contains how to control it.
*
* @param sessionInfo information of the new session.
- * The {@link RouteSessionInfo#getSessionId() id} of the session must be
+ * The {@link RouteSessionInfo#getId() id} of the session must be
* unique. Pass {@code null} to reject the request or inform clients that
* session creation is failed.
* @param requestId id of the previous request to create this session
@@ -194,13 +198,13 @@ public abstract class MediaRoute2ProviderService extends Service {
// TODO: Maybe better to create notifySessionCreationFailed?
public final void notifySessionCreated(@Nullable RouteSessionInfo sessionInfo, long requestId) {
if (sessionInfo != null) {
- int sessionId = sessionInfo.getSessionId();
+ String sessionId = sessionInfo.getId();
synchronized (mSessionLock) {
if (mSessionInfo.containsKey(sessionId)) {
Log.w(TAG, "Ignoring duplicate session id.");
return;
}
- mSessionInfo.put(sessionInfo.getSessionId(), sessionInfo);
+ mSessionInfo.put(sessionInfo.getId(), sessionInfo);
}
schedulePublishState();
}
@@ -220,9 +224,12 @@ public abstract class MediaRoute2ProviderService extends Service {
* {@link #onDestroySession} is called if the session is released.
*
* @param sessionId id of the session to be released
- * @see #onDestroySession(int, RouteSessionInfo)
+ * @see #onDestroySession(String, RouteSessionInfo)
*/
- public final void releaseSession(int sessionId) {
+ public final void releaseSession(@NonNull String sessionId) {
+ if (TextUtils.isEmpty(sessionId)) {
+ throw new IllegalArgumentException("sessionId must not be empty");
+ }
//TODO: notify media router service of release.
RouteSessionInfo sessionInfo;
synchronized (mSessionLock) {
@@ -246,11 +253,11 @@ public abstract class MediaRoute2ProviderService extends Service {
*
* @param packageName the package name of the application that selected the route
* @param routeId the id of the route initially being connected
- * @param controlCategory the control category of the new session
+ * @param routeType the route type of the new session
* @param requestId the id of this session creation request
*/
public abstract void onCreateSession(@NonNull String packageName, @NonNull String routeId,
- @NonNull String controlCategory, long requestId);
+ @NonNull String routeType, long requestId);
/**
* Called when a session is about to be destroyed.
@@ -259,9 +266,10 @@ public abstract class MediaRoute2ProviderService extends Service {
*
* @param sessionId id of the session being destroyed.
* @param lastSessionInfo information of the session being destroyed.
- * @see #releaseSession(int)
+ * @see #releaseSession(String)
*/
- public abstract void onDestroySession(int sessionId, @NonNull RouteSessionInfo lastSessionInfo);
+ public abstract void onDestroySession(@NonNull String sessionId,
+ @NonNull RouteSessionInfo lastSessionInfo);
//TODO: make a way to reject the request
/**
@@ -274,7 +282,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* @param routeId id of the route
* @see #updateSessionInfo(RouteSessionInfo)
*/
- public abstract void onSelectRoute(int sessionId, @NonNull String routeId);
+ public abstract void onSelectRoute(@NonNull String sessionId, @NonNull String routeId);
//TODO: make a way to reject the request
/**
@@ -286,7 +294,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* @param sessionId id of the session
* @param routeId id of the route
*/
- public abstract void onDeselectRoute(int sessionId, @NonNull String routeId);
+ public abstract void onDeselectRoute(@NonNull String sessionId, @NonNull String routeId);
//TODO: make a way to reject the request
/**
@@ -298,7 +306,26 @@ public abstract class MediaRoute2ProviderService extends Service {
* @param sessionId id of the session
* @param routeId id of the route
*/
- public abstract void onTransferToRoute(int sessionId, @NonNull String routeId);
+ public abstract void onTransferToRoute(@NonNull String sessionId, @NonNull String routeId);
+
+ /**
+ * Called when the {@link RouteDiscoveryRequest discovery request} has changed.
+ * <p>
+ * Whenever an application registers a {@link MediaRouter2.RouteCallback callback},
+ * it also provides a discovery request to specify types of routes that it is interested in.
+ * The media router combines all of these discovery request into a single discovery request
+ * and notifies each provider.
+ * </p><p>
+ * The provider should examine {@link RouteDiscoveryRequest#getRouteTypes() route types}
+ * in the discovery request to determine what kind of routes it should try to discover
+ * and whether it should perform active or passive scans. In many cases, the provider may be
+ * able to save power by not performing any scans when the request doesn't have any matching
+ * route types.
+ * </p>
+ *
+ * @param request the new discovery request
+ */
+ public void onDiscoveryRequestChanged(@NonNull RouteDiscoveryRequest request) {}
/**
* Updates provider info and publishes routes and session info.
@@ -357,46 +384,62 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void requestCreateSession(String packageName, String routeId,
- String controlCategory, long requestId) {
+ String routeType, long requestId) {
if (!checkCallerisSystem()) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession,
- MediaRoute2ProviderService.this, packageName, routeId, controlCategory,
+ MediaRoute2ProviderService.this, packageName, routeId, routeType,
requestId));
}
@Override
- public void releaseSession(int sessionId) {
+ public void releaseSession(@NonNull String sessionId) {
if (!checkCallerisSystem()) {
return;
}
+ if (TextUtils.isEmpty(sessionId)) {
+ Log.w(TAG, "releaseSession: Ignoring empty sessionId from system service.");
+ return;
+ }
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::releaseSession,
MediaRoute2ProviderService.this, sessionId));
}
@Override
- public void selectRoute(int sessionId, String routeId) {
+ public void selectRoute(@NonNull String sessionId, String routeId) {
if (!checkCallerisSystem()) {
return;
}
+ if (TextUtils.isEmpty(sessionId)) {
+ Log.w(TAG, "selectRoute: Ignoring empty sessionId from system service.");
+ return;
+ }
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
MediaRoute2ProviderService.this, sessionId, routeId));
}
@Override
- public void deselectRoute(int sessionId, String routeId) {
+ public void deselectRoute(@NonNull String sessionId, String routeId) {
if (!checkCallerisSystem()) {
return;
}
+ if (TextUtils.isEmpty(sessionId)) {
+ Log.w(TAG, "deselectRoute: Ignoring empty sessionId from system service.");
+ return;
+ }
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onDeselectRoute,
MediaRoute2ProviderService.this, sessionId, routeId));
}
@Override
- public void transferToRoute(int sessionId, String routeId) {
+ public void transferToRoute(@NonNull String sessionId, String routeId) {
if (!checkCallerisSystem()) {
return;
}
+ if (TextUtils.isEmpty(sessionId)) {
+ Log.w(TAG, "transferToRoute: Ignoring empty sessionId from system service.");
+ return;
+ }
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onTransferToRoute,
MediaRoute2ProviderService.this, sessionId, routeId));
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index f5cfde4b968b..8ebf6174cabf 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -39,7 +39,6 @@ import com.android.internal.annotations.GuardedBy;
import java.lang.annotation.Retention;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -48,6 +47,7 @@ import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
/**
* A new Media Router
@@ -118,7 +118,7 @@ public class MediaRouter2 {
final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
@GuardedBy("sLock")
- private List<String> mControlCategories = Collections.emptyList();
+ private RouteDiscoveryRequest mDiscoveryRequest = RouteDiscoveryRequest.EMPTY;
// TODO: Make MediaRouter2 is always connected to the MediaRouterService.
@GuardedBy("sLock")
@@ -152,7 +152,6 @@ public class MediaRouter2 {
mMediaRouterService = IMediaRouterService.Stub.asInterface(
ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
mPackageName = mContext.getPackageName();
- //TODO: read control categories from the manifest
mHandler = new Handler(Looper.getMainLooper());
List<MediaRoute2Info> currentSystemRoutes = null;
@@ -177,9 +176,9 @@ public class MediaRouter2 {
* @hide
*/
public static boolean checkRouteListContainsRouteId(@NonNull List<MediaRoute2Info> routeList,
- @NonNull String uniqueRouteId) {
+ @NonNull String routeId) {
for (MediaRoute2Info info : routeList) {
- if (TextUtils.equals(uniqueRouteId, info.getUniqueId())) {
+ if (TextUtils.equals(routeId, info.getId())) {
return true;
}
}
@@ -188,24 +187,18 @@ public class MediaRouter2 {
/**
* Registers a callback to discover routes and to receive events when they change.
- */
- public void registerRouteCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull RouteCallback routeCallback) {
- registerRouteCallback(executor, routeCallback, 0);
- }
-
- /**
- * Registers a callback to discover routes and to receive events when they change.
* <p>
* If you register the same callback twice or more, it will be ignored.
* </p>
*/
public void registerRouteCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull RouteCallback routeCallback, int flags) {
+ @NonNull RouteCallback routeCallback,
+ @NonNull RouteDiscoveryRequest request) {
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(routeCallback, "callback must not be null");
+ Objects.requireNonNull(request, "request must not be null");
- RouteCallbackRecord record = new RouteCallbackRecord(executor, routeCallback, flags);
+ RouteCallbackRecord record = new RouteCallbackRecord(executor, routeCallback, request);
if (!mRouteCallbackRecords.addIfAbsent(record)) {
Log.w(TAG, "Ignoring the same callback");
return;
@@ -216,7 +209,8 @@ public class MediaRouter2 {
Client2 client = new Client2();
try {
mMediaRouterService.registerClient2(client, mPackageName);
- mMediaRouterService.setControlCategories(client, mControlCategories);
+ updateDiscoveryRequestLocked();
+ mMediaRouterService.setDiscoveryRequest2(client, mDiscoveryRequest);
mClient = client;
} catch (RemoteException ex) {
Log.e(TAG, "Unable to register media router.", ex);
@@ -238,7 +232,7 @@ public class MediaRouter2 {
Objects.requireNonNull(routeCallback, "callback must not be null");
if (!mRouteCallbackRecords.remove(
- new RouteCallbackRecord(null, routeCallback, 0))) {
+ new RouteCallbackRecord(null, routeCallback, null))) {
Log.w(TAG, "Ignoring unknown callback");
return;
}
@@ -256,30 +250,10 @@ public class MediaRouter2 {
}
}
- //TODO(b/139033746): Rename "Control Category" when it's finalized.
- /**
- * Sets the control categories of the application.
- * Routes that support at least one of the given control categories are handled
- * by the media router.
- */
- public void setControlCategories(@NonNull Collection<String> controlCategories) {
- Objects.requireNonNull(controlCategories, "control categories must not be null");
-
- List<String> newControlCategories = new ArrayList<>(controlCategories);
-
- synchronized (sRouterLock) {
- mShouldUpdateRoutes = true;
-
- // invoke callbacks due to control categories change
- handleControlCategoriesChangedLocked(newControlCategories);
- if (mClient != null) {
- try {
- mMediaRouterService.setControlCategories(mClient, mControlCategories);
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to set control categories.", ex);
- }
- }
- }
+ private void updateDiscoveryRequestLocked() {
+ mDiscoveryRequest = new RouteDiscoveryRequest.Builder(
+ mRouteCallbackRecords.stream().map(record -> record.mRequest).collect(
+ Collectors.toList())).build();
}
/**
@@ -287,8 +261,8 @@ public class MediaRouter2 {
* known to the media router.
* Please note that the list can be changed before callbacks are invoked.
*
- * @return the list of routes that support at least one of the control categories set by
- * the application
+ * @return the list of routes that contains at least one of the route types in discovery
+ * requests registered by the application
*/
@NonNull
public List<MediaRoute2Info> getRoutes() {
@@ -298,7 +272,7 @@ public class MediaRouter2 {
List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
for (MediaRoute2Info route : mRoutes.values()) {
- if (route.supportsControlCategories(mControlCategories)) {
+ if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) {
filteredRoutes.add(route);
}
}
@@ -350,26 +324,25 @@ public class MediaRouter2 {
* Requests the media route provider service to create a session with the given route.
*
* @param route the route you want to create a session with.
- * @param controlCategory the control category of the session. Should not be empty
+ * @param routeType the route type of the session. Should not be empty
*
* @see SessionCallback#onSessionCreated
* @see SessionCallback#onSessionCreationFailed
*/
@NonNull
public void requestCreateSession(@NonNull MediaRoute2Info route,
- @NonNull String controlCategory) {
+ @NonNull String routeType) {
Objects.requireNonNull(route, "route must not be null");
- if (TextUtils.isEmpty(controlCategory)) {
- throw new IllegalArgumentException("controlCategory must not be empty");
+ if (TextUtils.isEmpty(routeType)) {
+ throw new IllegalArgumentException("routeType must not be empty");
}
// TODO: Check the given route exists
- // TODO: Check the route supports the given controlCategory
+ // TODO: Check the route supports the given routeType
final int requestId;
requestId = mSessionCreationRequestCnt.getAndIncrement();
- SessionCreationRequest request = new SessionCreationRequest(
- requestId, route, controlCategory);
+ SessionCreationRequest request = new SessionCreationRequest(requestId, route, routeType);
mSessionCreationRequests.add(request);
Client2 client;
@@ -378,8 +351,7 @@ public class MediaRouter2 {
}
if (client != null) {
try {
- mMediaRouterService.requestCreateSession(
- client, route, controlCategory, requestId);
+ mMediaRouterService.requestCreateSession(client, route, routeType, requestId);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to request to create session.", ex);
mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler,
@@ -461,36 +433,6 @@ public class MediaRouter2 {
}
}
- private void handleControlCategoriesChangedLocked(List<String> newControlCategories) {
- List<MediaRoute2Info> addedRoutes = new ArrayList<>();
- List<MediaRoute2Info> removedRoutes = new ArrayList<>();
-
- List<String> prevControlCategories = mControlCategories;
- mControlCategories = newControlCategories;
-
- for (MediaRoute2Info route : mRoutes.values()) {
- boolean preSupported = route.supportsControlCategories(prevControlCategories);
- boolean postSupported = route.supportsControlCategories(newControlCategories);
- if (preSupported == postSupported) {
- continue;
- }
- if (preSupported) {
- removedRoutes.add(route);
- } else {
- addedRoutes.add(route);
- }
- }
-
- if (removedRoutes.size() > 0) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::notifyRoutesRemoved,
- MediaRouter2.this, removedRoutes));
- }
- if (addedRoutes.size() > 0) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::notifyRoutesAdded,
- MediaRouter2.this, addedRoutes));
- }
- }
-
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
// TODO: When onRoutesAdded is first called,
// 1) clear mRoutes before adding the routes
@@ -499,8 +441,8 @@ public class MediaRouter2 {
List<MediaRoute2Info> addedRoutes = new ArrayList<>();
synchronized (sRouterLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.put(route.getUniqueId(), route);
- if (route.supportsControlCategories(mControlCategories)) {
+ mRoutes.put(route.getId(), route);
+ if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) {
addedRoutes.add(route);
}
}
@@ -515,8 +457,8 @@ public class MediaRouter2 {
List<MediaRoute2Info> removedRoutes = new ArrayList<>();
synchronized (sRouterLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.remove(route.getUniqueId());
- if (route.supportsControlCategories(mControlCategories)) {
+ mRoutes.remove(route.getId());
+ if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) {
removedRoutes.add(route);
}
}
@@ -531,8 +473,8 @@ public class MediaRouter2 {
List<MediaRoute2Info> changedRoutes = new ArrayList<>();
synchronized (sRouterLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.put(route.getUniqueId(), route);
- if (route.supportsControlCategories(mControlCategories)) {
+ mRoutes.put(route.getId(), route);
+ if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) {
changedRoutes.add(route);
}
}
@@ -562,27 +504,27 @@ public class MediaRouter2 {
mSessionCreationRequests.remove(matchingRequest);
MediaRoute2Info requestedRoute = matchingRequest.mRoute;
- String requestedControlCategory = matchingRequest.mControlCategory;
+ String requestedRouteType = matchingRequest.mRouteType;
if (sessionInfo == null) {
// TODO: We may need to distinguish between failure and rejection.
// One way can be introducing 'reason'.
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ notifySessionCreationFailed(requestedRoute, requestedRouteType);
return;
- } else if (!TextUtils.equals(requestedControlCategory,
- sessionInfo.getControlCategory())) {
- Log.w(TAG, "The session has different control category from what we requested. "
- + "(requested=" + requestedControlCategory
- + ", actual=" + sessionInfo.getControlCategory()
+ } else if (!TextUtils.equals(requestedRouteType,
+ sessionInfo.getRouteType())) {
+ Log.w(TAG, "The session has different route type from what we requested. "
+ + "(requested=" + requestedRouteType
+ + ", actual=" + sessionInfo.getRouteType()
+ ")");
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ notifySessionCreationFailed(requestedRoute, requestedRouteType);
return;
} else if (!sessionInfo.getSelectedRoutes().contains(requestedRoute.getId())) {
Log.w(TAG, "The session does not contain the requested route. "
+ "(requestedRouteId=" + requestedRoute.getId()
+ ", actualRoutes=" + sessionInfo.getSelectedRoutes()
+ ")");
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ notifySessionCreationFailed(requestedRoute, requestedRouteType);
return;
} else if (!TextUtils.equals(requestedRoute.getProviderId(),
sessionInfo.getProviderId())) {
@@ -590,7 +532,7 @@ public class MediaRouter2 {
+ "(requested route's providerId=" + requestedRoute.getProviderId()
+ ", actual providerId=" + sessionInfo.getProviderId()
+ ")");
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ notifySessionCreationFailed(requestedRoute, requestedRouteType);
return;
}
}
@@ -598,7 +540,7 @@ public class MediaRouter2 {
if (sessionInfo != null) {
RouteSessionController controller = new RouteSessionController(sessionInfo);
synchronized (sRouterLock) {
- mSessionControllers.put(controller.getUniqueSessionId(), controller);
+ mSessionControllers.put(controller.getSessionId(), controller);
}
notifySessionCreated(controller);
}
@@ -612,12 +554,12 @@ public class MediaRouter2 {
RouteSessionController matchingController;
synchronized (sRouterLock) {
- matchingController = mSessionControllers.get(sessionInfo.getUniqueSessionId());
+ matchingController = mSessionControllers.get(sessionInfo.getId());
}
if (matchingController == null) {
Log.w(TAG, "changeSessionInfoOnHandler: Matching controller not found. uniqueSessionId="
- + sessionInfo.getUniqueSessionId());
+ + sessionInfo.getId());
return;
}
@@ -638,7 +580,7 @@ public class MediaRouter2 {
return;
}
- final String uniqueSessionId = sessionInfo.getUniqueSessionId();
+ final String uniqueSessionId = sessionInfo.getId();
RouteSessionController matchingController;
synchronized (sRouterLock) {
matchingController = mSessionControllers.get(uniqueSessionId);
@@ -647,7 +589,7 @@ public class MediaRouter2 {
if (matchingController == null) {
if (DEBUG) {
Log.d(TAG, "releaseControllerOnHandler: Matching controller not found. "
- + "uniqueSessionId=" + sessionInfo.getUniqueSessionId());
+ + "uniqueSessionId=" + sessionInfo.getId());
}
return;
}
@@ -666,24 +608,41 @@ public class MediaRouter2 {
notifyControllerReleased(matchingController);
}
+ private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes,
+ RouteDiscoveryRequest discoveryRequest) {
+ return routes.stream()
+ .filter(
+ route -> route.containsRouteTypes(discoveryRequest.getRouteTypes()))
+ .collect(Collectors.toList());
+ }
+
private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
for (RouteCallbackRecord record: mRouteCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mRouteCallback.onRoutesAdded(routes));
+ List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mRequest);
+ if (!filteredRoutes.isEmpty()) {
+ record.mExecutor.execute(
+ () -> record.mRouteCallback.onRoutesAdded(filteredRoutes));
+ }
}
}
private void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
for (RouteCallbackRecord record: mRouteCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mRouteCallback.onRoutesRemoved(routes));
+ List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mRequest);
+ if (!filteredRoutes.isEmpty()) {
+ record.mExecutor.execute(
+ () -> record.mRouteCallback.onRoutesRemoved(filteredRoutes));
+ }
}
}
private void notifyRoutesChanged(List<MediaRoute2Info> routes) {
for (RouteCallbackRecord record: mRouteCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mRouteCallback.onRoutesChanged(routes));
+ List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mRequest);
+ if (!filteredRoutes.isEmpty()) {
+ record.mExecutor.execute(
+ () -> record.mRouteCallback.onRoutesChanged(filteredRoutes));
+ }
}
}
@@ -694,10 +653,10 @@ public class MediaRouter2 {
}
}
- private void notifySessionCreationFailed(MediaRoute2Info route, String controlCategory) {
+ private void notifySessionCreationFailed(MediaRoute2Info route, String routeType) {
for (SessionCallbackRecord record: mSessionCallbackRecords) {
record.mExecutor.execute(
- () -> record.mSessionCallback.onSessionCreationFailed(route, controlCategory));
+ () -> record.mSessionCallback.onSessionCreationFailed(route, routeType));
}
}
@@ -764,10 +723,10 @@ public class MediaRouter2 {
* Called when the session creation request failed.
*
* @param requestedRoute the route info which was used for the request
- * @param requestedControlCategory the control category which was used for the request
+ * @param requestedRouteType the route type which was used for the request
*/
public void onSessionCreationFailed(@NonNull MediaRoute2Info requestedRoute,
- @NonNull String requestedControlCategory) {}
+ @NonNull String requestedRouteType) {}
/**
* Called when the session info has changed.
@@ -822,30 +781,19 @@ public class MediaRouter2 {
/**
* @return the ID of the session
*/
- public int getSessionId() {
+ public String getSessionId() {
synchronized (mControllerLock) {
- return mSessionInfo.getSessionId();
+ return mSessionInfo.getId();
}
}
/**
- * @return the unique ID of the session
- * @hide
+ * @return the type of routes that the session includes.
*/
@NonNull
- public String getUniqueSessionId() {
+ public String getRouteType() {
synchronized (mControllerLock) {
- return mSessionInfo.getUniqueSessionId();
- }
- }
-
- /**
- * @return the category of routes that the session includes.
- */
- @NonNull
- public String getControlCategory() {
- synchronized (mControllerLock) {
- return mSessionInfo.getControlCategory();
+ return mSessionInfo.getRouteType();
}
}
@@ -935,13 +883,13 @@ public class MediaRouter2 {
}
List<MediaRoute2Info> selectedRoutes = getSelectedRoutes();
- if (checkRouteListContainsRouteId(selectedRoutes, route.getUniqueId())) {
+ if (checkRouteListContainsRouteId(selectedRoutes, route.getId())) {
Log.w(TAG, "Ignoring selecting a route that is already selected. route=" + route);
return;
}
List<MediaRoute2Info> selectableRoutes = getSelectableRoutes();
- if (!checkRouteListContainsRouteId(selectableRoutes, route.getUniqueId())) {
+ if (!checkRouteListContainsRouteId(selectableRoutes, route.getId())) {
Log.w(TAG, "Ignoring selecting a non-selectable route=" + route);
return;
}
@@ -952,7 +900,7 @@ public class MediaRouter2 {
}
if (client != null) {
try {
- mMediaRouterService.selectRoute(client, getUniqueSessionId(), route);
+ mMediaRouterService.selectRoute(client, getSessionId(), route);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to select route for session.", ex);
}
@@ -982,13 +930,13 @@ public class MediaRouter2 {
}
List<MediaRoute2Info> selectedRoutes = getSelectedRoutes();
- if (!checkRouteListContainsRouteId(selectedRoutes, route.getUniqueId())) {
+ if (!checkRouteListContainsRouteId(selectedRoutes, route.getId())) {
Log.w(TAG, "Ignoring deselecting a route that is not selected. route=" + route);
return;
}
List<MediaRoute2Info> deselectableRoutes = getDeselectableRoutes();
- if (!checkRouteListContainsRouteId(deselectableRoutes, route.getUniqueId())) {
+ if (!checkRouteListContainsRouteId(deselectableRoutes, route.getId())) {
Log.w(TAG, "Ignoring deselecting a non-deselectable route=" + route);
return;
}
@@ -999,7 +947,7 @@ public class MediaRouter2 {
}
if (client != null) {
try {
- mMediaRouterService.deselectRoute(client, getUniqueSessionId(), route);
+ mMediaRouterService.deselectRoute(client, getSessionId(), route);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to remove route from session.", ex);
}
@@ -1029,14 +977,14 @@ public class MediaRouter2 {
}
List<MediaRoute2Info> selectedRoutes = getSelectedRoutes();
- if (checkRouteListContainsRouteId(selectedRoutes, route.getUniqueId())) {
+ if (checkRouteListContainsRouteId(selectedRoutes, route.getId())) {
Log.w(TAG, "Ignoring transferring to a route that is already added. route="
+ route);
return;
}
List<MediaRoute2Info> transferrableRoutes = getTransferrableRoutes();
- if (!checkRouteListContainsRouteId(transferrableRoutes, route.getUniqueId())) {
+ if (!checkRouteListContainsRouteId(transferrableRoutes, route.getId())) {
Log.w(TAG, "Ignoring transferring to a non-transferrable route=" + route);
return;
}
@@ -1047,7 +995,7 @@ public class MediaRouter2 {
}
if (client != null) {
try {
- mMediaRouterService.transferToRoute(client, getUniqueSessionId(), route);
+ mMediaRouterService.transferToRoute(client, getSessionId(), route);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to transfer to route for session.", ex);
}
@@ -1072,20 +1020,24 @@ public class MediaRouter2 {
Client2 client;
synchronized (sRouterLock) {
- mSessionControllers.remove(getUniqueSessionId(), this);
+ mSessionControllers.remove(getSessionId(), this);
client = mClient;
}
if (client != null) {
try {
- mMediaRouterService.releaseSession(client, getUniqueSessionId());
+ mMediaRouterService.releaseSession(client, getSessionId());
} catch (RemoteException ex) {
Log.e(TAG, "Unable to notify of controller release", ex);
}
}
}
+ /**
+ * TODO: Change this to package private. (Hidden for debugging purposes)
+ * @hide
+ */
@NonNull
- RouteSessionInfo getRouteSessionInfo() {
+ public RouteSessionInfo getRouteSessionInfo() {
synchronized (mControllerLock) {
return mSessionInfo;
}
@@ -1100,11 +1052,12 @@ public class MediaRouter2 {
// TODO: This method uses two locks (mLock outside, sLock inside).
// Check if there is any possiblity of deadlock.
private List<MediaRoute2Info> getRoutesWithIdsLocked(List<String> routeIds) {
+
List<MediaRoute2Info> routes = new ArrayList<>();
synchronized (sRouterLock) {
+ // TODO: Maybe able to change using Collection.stream()?
for (String routeId : routeIds) {
- MediaRoute2Info route = mRoutes.get(
- MediaRoute2Info.toUniqueId(mSessionInfo.mProviderId, routeId));
+ MediaRoute2Info route = mRoutes.get(routeId);
if (route != null) {
routes.add(route);
}
@@ -1117,13 +1070,13 @@ public class MediaRouter2 {
final class RouteCallbackRecord {
public final Executor mExecutor;
public final RouteCallback mRouteCallback;
- public final int mFlags;
+ public final RouteDiscoveryRequest mRequest;
RouteCallbackRecord(@Nullable Executor executor, @NonNull RouteCallback routeCallback,
- int flags) {
+ @Nullable RouteDiscoveryRequest request) {
mRouteCallback = routeCallback;
mExecutor = executor;
- mFlags = flags;
+ mRequest = request;
}
@Override
@@ -1172,13 +1125,13 @@ public class MediaRouter2 {
final class SessionCreationRequest {
public final MediaRoute2Info mRoute;
- public final String mControlCategory;
+ public final String mRouteType;
public final int mRequestId;
SessionCreationRequest(int requestId, @NonNull MediaRoute2Info route,
- @NonNull String controlCategory) {
+ @NonNull String routeType) {
mRoute = route;
- mControlCategory = controlCategory;
+ mRouteType = routeType;
mRequestId = requestId;
}
}
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 2e68e42e714f..1e6ec51442d6 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -65,7 +65,7 @@ public class MediaRouter2Manager {
@GuardedBy("mRoutesLock")
private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
@NonNull
- final ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>();
+ final ConcurrentMap<String, List<String>> mRouteTypeMap = new ConcurrentHashMap<>();
private AtomicInteger mNextRequestId = new AtomicInteger(1);
@@ -144,7 +144,7 @@ public class MediaRouter2Manager {
}
//TODO: clear mRoutes?
mClient = null;
- mControlCategoryMap.clear();
+ mRouteTypeMap.clear();
}
}
}
@@ -160,14 +160,14 @@ public class MediaRouter2Manager {
public List<MediaRoute2Info> getAvailableRoutes(@NonNull String packageName) {
Objects.requireNonNull(packageName, "packageName must not be null");
- List<String> controlCategories = mControlCategoryMap.get(packageName);
- if (controlCategories == null) {
+ List<String> routeTypes = mRouteTypeMap.get(packageName);
+ if (routeTypes == null) {
return Collections.emptyList();
}
List<MediaRoute2Info> routes = new ArrayList<>();
synchronized (mRoutesLock) {
for (MediaRoute2Info route : mRoutes.values()) {
- if (route.supportsControlCategories(controlCategories)) {
+ if (route.containsRouteTypes(routeTypes)) {
routes.add(route);
}
}
@@ -295,7 +295,7 @@ public class MediaRouter2Manager {
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
synchronized (mRoutesLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.put(route.getUniqueId(), route);
+ mRoutes.put(route.getId(), route);
}
}
if (routes.size() > 0) {
@@ -306,7 +306,7 @@ public class MediaRouter2Manager {
void removeRoutesOnHandler(List<MediaRoute2Info> routes) {
synchronized (mRoutesLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.remove(route.getUniqueId());
+ mRoutes.remove(route.getId());
}
}
if (routes.size() > 0) {
@@ -317,7 +317,7 @@ public class MediaRouter2Manager {
void changeRoutesOnHandler(List<MediaRoute2Info> routes) {
synchronized (mRoutesLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.put(route.getUniqueId(), route);
+ mRoutes.put(route.getId(), route);
}
}
if (routes.size() > 0) {
@@ -352,15 +352,15 @@ public class MediaRouter2Manager {
}
}
- void updateControlCategories(String packageName, List<String> categories) {
- List<String> prevCategories = mControlCategoryMap.put(packageName, categories);
- if ((prevCategories == null && categories.size() == 0)
- || Objects.equals(categories, prevCategories)) {
+ void updateRouteTypes(String packageName, List<String> routeTypes) {
+ List<String> prevTypes = mRouteTypeMap.put(packageName, routeTypes);
+ if ((prevTypes == null && routeTypes.size() == 0)
+ || Objects.equals(routeTypes, prevTypes)) {
return;
}
for (CallbackRecord record : mCallbackRecords) {
record.mExecutor.execute(
- () -> record.mCallback.onControlCategoriesChanged(packageName, categories));
+ () -> record.mCallback.onControlCategoriesChanged(packageName, routeTypes));
}
}
@@ -398,13 +398,13 @@ public class MediaRouter2Manager {
/**
- * Called when the control categories of an app is changed.
+ * Called when the route types of an app is changed.
*
* @param packageName the package name of the application
- * @param controlCategories the list of control categories set by an application.
+ * @param routeTypes the list of route types set by an application.
*/
public void onControlCategoriesChanged(@NonNull String packageName,
- @NonNull List<String> controlCategories) {}
+ @NonNull List<String> routeTypes) {}
}
final class CallbackRecord {
@@ -440,10 +440,9 @@ public class MediaRouter2Manager {
MediaRouter2Manager.this, packageName, route));
}
- @Override
- public void notifyControlCategoriesChanged(String packageName, List<String> categories) {
- mHandler.sendMessage(obtainMessage(MediaRouter2Manager::updateControlCategories,
- MediaRouter2Manager.this, packageName, categories));
+ public void notifyRouteTypesChanged(String packageName, List<String> routeTypes) {
+ mHandler.sendMessage(obtainMessage(MediaRouter2Manager::updateRouteTypes,
+ MediaRouter2Manager.this, packageName, routeTypes));
}
@Override
diff --git a/media/java/android/media/MediaRouter2Utils.java b/media/java/android/media/MediaRouter2Utils.java
new file mode 100644
index 000000000000..49045828dbe8
--- /dev/null
+++ b/media/java/android/media/MediaRouter2Utils.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class MediaRouter2Utils {
+
+ static final String TAG = "MR2Utils";
+ static final String SEPARATOR = ":";
+
+ /**
+ * @hide
+ */
+ @NonNull
+ public static String toUniqueId(@NonNull String providerId, @NonNull String id) {
+ if (TextUtils.isEmpty(providerId)) {
+ Log.w(TAG, "toUniqueId: providerId shouldn't be empty");
+ return null;
+ }
+ if (TextUtils.isEmpty(id)) {
+ Log.w(TAG, "toUniqueId: id shouldn't be null");
+ return null;
+ }
+
+ return providerId + SEPARATOR + id;
+ }
+
+ /**
+ * Gets provider ID from unique ID.
+ * If the corresponding provider ID could not be generated, it will return null.
+ *
+ * @hide
+ */
+ @Nullable
+ public static String getProviderId(@NonNull String uniqueId) {
+ if (TextUtils.isEmpty(uniqueId)) {
+ Log.w(TAG, "getProviderId: uniqueId shouldn't be empty");
+ return null;
+ }
+
+ int firstIndexOfSeparator = uniqueId.indexOf(SEPARATOR);
+ if (firstIndexOfSeparator == -1) {
+ return null;
+ }
+
+ String providerId = uniqueId.substring(0, firstIndexOfSeparator);
+ if (TextUtils.isEmpty(providerId)) {
+ return null;
+ }
+
+ return providerId;
+ }
+
+ /**
+ * Gets the original ID (i.e. non-unique route/session ID) from unique ID.
+ * If the corresponding ID could not be generated, it will return null.
+ *
+ * @hide
+ */
+ @Nullable
+ public static String getOriginalId(@NonNull String uniqueId) {
+ if (TextUtils.isEmpty(uniqueId)) {
+ Log.w(TAG, "getOriginalId: uniqueId shouldn't be empty");
+ return null;
+ }
+
+ int firstIndexOfSeparator = uniqueId.indexOf(SEPARATOR);
+ if (firstIndexOfSeparator == -1 || firstIndexOfSeparator + 1 >= uniqueId.length()) {
+ return null;
+ }
+
+ String providerId = uniqueId.substring(firstIndexOfSeparator + 1);
+ if (TextUtils.isEmpty(providerId)) {
+ return null;
+ }
+
+ return providerId;
+ }
+}
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index 40e90731f2a2..05fa511fc81a 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -16,7 +16,7 @@
package android.media;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
diff --git a/media/java/android/media/RouteDiscoveryRequest.aidl b/media/java/android/media/RouteDiscoveryRequest.aidl
new file mode 100644
index 000000000000..744f6569325d
--- /dev/null
+++ b/media/java/android/media/RouteDiscoveryRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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.media;
+
+parcelable RouteDiscoveryRequest;
diff --git a/media/java/android/media/RouteDiscoveryRequest.java b/media/java/android/media/RouteDiscoveryRequest.java
new file mode 100644
index 000000000000..88b31fb30ffc
--- /dev/null
+++ b/media/java/android/media/RouteDiscoveryRequest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+
+/**
+ * @hide
+ */
+public final class RouteDiscoveryRequest implements Parcelable {
+ @NonNull
+ public static final Creator<RouteDiscoveryRequest> CREATOR =
+ new Creator<RouteDiscoveryRequest>() {
+ @Override
+ public RouteDiscoveryRequest createFromParcel(Parcel in) {
+ return new RouteDiscoveryRequest(in);
+ }
+
+ @Override
+ public RouteDiscoveryRequest[] newArray(int size) {
+ return new RouteDiscoveryRequest[size];
+ }
+ };
+
+ @NonNull
+ private final List<String> mRouteTypes;
+ private final boolean mActiveScan;
+ @Nullable
+ private final Bundle mExtras;
+
+ /**
+ * @hide
+ */
+ public static final RouteDiscoveryRequest EMPTY =
+ new Builder(Collections.emptyList(), false).build();
+
+ RouteDiscoveryRequest(@NonNull Builder builder) {
+ mRouteTypes = builder.mRouteTypes;
+ mActiveScan = builder.mActiveScan;
+ mExtras = builder.mExtras;
+ }
+
+ RouteDiscoveryRequest(@NonNull Parcel in) {
+ mRouteTypes = in.createStringArrayList();
+ mActiveScan = in.readBoolean();
+ mExtras = in.readBundle();
+ }
+
+ @NonNull
+ public List<String> getRouteTypes() {
+ return mRouteTypes;
+ }
+
+ public boolean isActiveScan() {
+ return mActiveScan;
+ }
+
+ /**
+ * @hide
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStringList(mRouteTypes);
+ dest.writeBoolean(mActiveScan);
+ dest.writeBundle(mExtras);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder()
+ .append("RouteDiscoveryRequest{ ")
+ .append("routeTypes={")
+ .append(String.join(", ", mRouteTypes))
+ .append("}")
+ .append(", activeScan=")
+ .append(mActiveScan)
+ .append(" }");
+
+ return result.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof RouteDiscoveryRequest)) {
+ return false;
+ }
+ RouteDiscoveryRequest other = (RouteDiscoveryRequest) o;
+ return Objects.equals(mRouteTypes, other.mRouteTypes)
+ && mActiveScan == other.mActiveScan;
+ }
+
+ /**
+ * Builder for {@link RouteDiscoveryRequest}.
+ */
+ public static final class Builder {
+ List<String> mRouteTypes;
+ boolean mActiveScan;
+ Bundle mExtras;
+
+ public Builder(@NonNull List<String> routeTypes, boolean activeScan) {
+ mRouteTypes = new ArrayList<>(
+ Objects.requireNonNull(routeTypes, "routeTypes must not be null"));
+ mActiveScan = activeScan;
+ }
+
+ public Builder(@NonNull RouteDiscoveryRequest request) {
+ Objects.requireNonNull(request, "request must not be null");
+
+ mRouteTypes = request.getRouteTypes();
+ mActiveScan = request.isActiveScan();
+ mExtras = request.getExtras();
+ }
+
+ /**
+ * A constructor to combine all of the requests into a single request.
+ * It ignores extras of requests.
+ */
+ Builder(@NonNull Collection<RouteDiscoveryRequest> requests) {
+ Set<String> routeTypeSet = new HashSet<>();
+ mActiveScan = false;
+ for (RouteDiscoveryRequest request : requests) {
+ routeTypeSet.addAll(request.mRouteTypes);
+ mActiveScan |= request.mActiveScan;
+ }
+ mRouteTypes = new ArrayList<>(routeTypeSet);
+ }
+
+ /**
+ * Sets route types to discover.
+ */
+ public Builder setRouteTypes(@NonNull List<String> routeTypes) {
+ mRouteTypes = new ArrayList<>(
+ Objects.requireNonNull(routeTypes, "routeTypes must not be null"));
+ return this;
+ }
+
+ /**
+ * Sets if active scanning should be performed.
+ */
+ public Builder setActiveScan(boolean activeScan) {
+ mActiveScan = activeScan;
+ return this;
+ }
+
+ /**
+ * Sets the extras of the route.
+ * @hide
+ */
+ public Builder setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Builds the {@link RouteDiscoveryRequest}.
+ */
+ public RouteDiscoveryRequest build() {
+ return new RouteDiscoveryRequest(this);
+ }
+ }
+}
diff --git a/media/java/android/media/RouteSessionInfo.java b/media/java/android/media/RouteSessionInfo.java
index 2d7bc24ae7a2..5330630ef3a9 100644
--- a/media/java/android/media/RouteSessionInfo.java
+++ b/media/java/android/media/RouteSessionInfo.java
@@ -22,6 +22,7 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
@@ -33,6 +34,7 @@ import java.util.Objects;
* @hide
*/
public class RouteSessionInfo implements Parcelable {
+
@NonNull
public static final Creator<RouteSessionInfo> CREATOR =
new Creator<RouteSessionInfo>() {
@@ -46,9 +48,11 @@ public class RouteSessionInfo implements Parcelable {
}
};
- final int mSessionId;
- final String mPackageName;
- final String mControlCategory;
+ public static final String TAG = "RouteSessionInfo";
+
+ final String mId;
+ final String mClientPackageName;
+ final String mRouteType;
@Nullable
final String mProviderId;
final List<String> mSelectedRoutes;
@@ -61,15 +65,19 @@ public class RouteSessionInfo implements Parcelable {
RouteSessionInfo(@NonNull Builder builder) {
Objects.requireNonNull(builder, "builder must not be null.");
- mSessionId = builder.mSessionId;
- mPackageName = builder.mPackageName;
- mControlCategory = builder.mControlCategory;
+ mId = builder.mId;
+ mClientPackageName = builder.mClientPackageName;
+ mRouteType = builder.mRouteType;
mProviderId = builder.mProviderId;
- mSelectedRoutes = Collections.unmodifiableList(builder.mSelectedRoutes);
- mSelectableRoutes = Collections.unmodifiableList(builder.mSelectableRoutes);
- mDeselectableRoutes = Collections.unmodifiableList(builder.mDeselectableRoutes);
- mTransferrableRoutes = Collections.unmodifiableList(builder.mTransferrableRoutes);
+ mSelectedRoutes = Collections.unmodifiableList(
+ convertToUniqueRouteIds(builder.mSelectedRoutes));
+ mSelectableRoutes = Collections.unmodifiableList(
+ convertToUniqueRouteIds(builder.mSelectableRoutes));
+ mDeselectableRoutes = Collections.unmodifiableList(
+ convertToUniqueRouteIds(builder.mDeselectableRoutes));
+ mTransferrableRoutes = Collections.unmodifiableList(
+ convertToUniqueRouteIds(builder.mTransferrableRoutes));
mControlHints = builder.mControlHints;
}
@@ -77,9 +85,9 @@ public class RouteSessionInfo implements Parcelable {
RouteSessionInfo(@NonNull Parcel src) {
Objects.requireNonNull(src, "src must not be null.");
- mSessionId = src.readInt();
- mPackageName = ensureString(src.readString());
- mControlCategory = ensureString(src.readString());
+ mId = ensureString(src.readString());
+ mClientPackageName = ensureString(src.readString());
+ mRouteType = ensureString(src.readString());
mProviderId = src.readString();
mSelectedRoutes = ensureList(src.createStringArrayList());
@@ -105,82 +113,59 @@ public class RouteSessionInfo implements Parcelable {
}
/**
- * Gets non-unique session id (int) from unique session id (string).
- * If the corresponding session id could not be generated, it will return null.
- * @hide
+ * Returns whether the session info is valid or not
+ *
+ * TODO in this CL: Remove this method.
*/
- @Nullable
- public static Integer getSessionId(@NonNull String uniqueSessionId) {
- int lastIndexOfSeparator = uniqueSessionId.lastIndexOf("/");
- if (lastIndexOfSeparator == -1 || lastIndexOfSeparator + 1 >= uniqueSessionId.length()) {
- return null;
- }
-
- String integerString = uniqueSessionId.substring(lastIndexOfSeparator + 1);
- if (TextUtils.isEmpty(integerString)) {
- return null;
- }
-
- try {
- return Integer.parseInt(integerString);
- } catch (NumberFormatException ex) {
- return null;
- }
+ public boolean isValid() {
+ return !TextUtils.isEmpty(mId)
+ && !TextUtils.isEmpty(mClientPackageName)
+ && !TextUtils.isEmpty(mRouteType)
+ && mSelectedRoutes.size() > 0;
}
/**
- * Gets provider ID (string) from unique session id (string).
- * If the corresponding provider ID could not be generated, it will return null.
- * @hide
+ * Gets the id of the session. The sessions which are given by {@link MediaRouter2} will have
+ * unique IDs.
+ * <p>
+ * In order to ensure uniqueness in {@link MediaRouter2} side, the value of this method
+ * can be different from what was set in {@link MediaRoute2ProviderService}.
*
- * TODO: This logic seems error-prone. Consider to use long uniqueId.
+ * @see Builder#Builder(String, String, String)
*/
- @Nullable
- public static String getProviderId(@NonNull String uniqueSessionId) {
- int lastIndexOfSeparator = uniqueSessionId.lastIndexOf("/");
- if (lastIndexOfSeparator == -1) {
- return null;
- }
-
- String result = uniqueSessionId.substring(0, lastIndexOfSeparator);
- if (TextUtils.isEmpty(result)) {
- return null;
+ @NonNull
+ public String getId() {
+ if (mProviderId != null) {
+ return MediaRouter2Utils.toUniqueId(mProviderId, mId);
+ } else {
+ return mId;
}
- return result;
}
/**
- * Returns whether the session info is valid or not
- */
- public boolean isValid() {
- return !TextUtils.isEmpty(mPackageName)
- && !TextUtils.isEmpty(mControlCategory)
- && mSelectedRoutes.size() > 0;
- }
-
- /**
- * Gets the id of the session
+ * Gets the original id set by {@link Builder#Builder(String, String, String)}.
+ * @hide
*/
@NonNull
- public int getSessionId() {
- return mSessionId;
+ public String getOriginalId() {
+ return mId;
}
/**
* Gets the client package name of the session
*/
@NonNull
- public String getPackageName() {
- return mPackageName;
+ public String getClientPackageName() {
+ return mClientPackageName;
}
/**
- * Gets the control category of the session.
- * Routes that don't support the category can't be added to the session.
+ * Gets the route type of the session.
+ * Routes that don't have the type can't be added to the session.
*/
@NonNull
- public String getControlCategory() {
- return mControlCategory;
+ public String getRouteType() {
+ return mRouteType;
}
/**
@@ -193,19 +178,6 @@ public class RouteSessionInfo implements Parcelable {
}
/**
- * Gets the unique id of the session.
- * @hide
- */
- @NonNull
- public String getUniqueSessionId() {
- StringBuilder sessionIdBuilder = new StringBuilder()
- .append(mProviderId)
- .append("/")
- .append(mSessionId);
- return sessionIdBuilder.toString();
- }
-
- /**
* Gets the list of ids of selected routes for the session. It shouldn't be empty.
*/
@NonNull
@@ -252,9 +224,9 @@ public class RouteSessionInfo implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mSessionId);
- dest.writeString(mPackageName);
- dest.writeString(mControlCategory);
+ dest.writeString(mId);
+ dest.writeString(mClientPackageName);
+ dest.writeString(mRouteType);
dest.writeString(mProviderId);
dest.writeStringList(mSelectedRoutes);
dest.writeStringList(mSelectableRoutes);
@@ -267,8 +239,8 @@ public class RouteSessionInfo implements Parcelable {
public String toString() {
StringBuilder result = new StringBuilder()
.append("RouteSessionInfo{ ")
- .append("sessionId=").append(mSessionId)
- .append(", controlCategory=").append(mControlCategory)
+ .append("sessionId=").append(mId)
+ .append(", routeType=").append(mRouteType)
.append(", selectedRoutes={")
.append(String.join(",", mSelectedRoutes))
.append("}")
@@ -285,13 +257,31 @@ public class RouteSessionInfo implements Parcelable {
return result.toString();
}
+ private List<String> convertToUniqueRouteIds(@NonNull List<String> routeIds) {
+ if (routeIds == null) {
+ Log.w(TAG, "routeIds is null. Returning an empty list");
+ return Collections.emptyList();
+ }
+
+ // mProviderId can be null if not set. Return the original list for this case.
+ if (mProviderId == null) {
+ return routeIds;
+ }
+
+ List<String> result = new ArrayList<>();
+ for (String routeId : routeIds) {
+ result.add(MediaRouter2Utils.toUniqueId(mProviderId, routeId));
+ }
+ return result;
+ }
+
/**
* Builder class for {@link RouteSessionInfo}.
*/
public static final class Builder {
- final String mPackageName;
- final int mSessionId;
- final String mControlCategory;
+ final String mId;
+ final String mClientPackageName;
+ final String mRouteType;
String mProviderId;
final List<String> mSelectedRoutes;
final List<String> mSelectableRoutes;
@@ -299,23 +289,43 @@ public class RouteSessionInfo implements Parcelable {
final List<String> mTransferrableRoutes;
Bundle mControlHints;
- public Builder(int sessionId, @NonNull String packageName,
- @NonNull String controlCategory) {
- mSessionId = sessionId;
- mPackageName = Objects.requireNonNull(packageName, "packageName must not be null");
- mControlCategory = Objects.requireNonNull(controlCategory,
- "controlCategory must not be null");
-
+ /**
+ * Constructor for builder to create {@link RouteSessionInfo}.
+ * <p>
+ * In order to ensure ID uniqueness in {@link MediaRouter2} side, the value of
+ * {@link RouteSessionInfo#getId()} can be different from what was set in
+ * {@link MediaRoute2ProviderService}.
+ * </p>
+ *
+ * @see MediaRoute2Info#getId()
+ */
+ public Builder(@NonNull String id, @NonNull String clientPackageName,
+ @NonNull String routeType) {
+ if (TextUtils.isEmpty(id)) {
+ throw new IllegalArgumentException("id must not be empty");
+ }
+ mId = id;
+ mClientPackageName = Objects.requireNonNull(
+ clientPackageName, "clientPackageName must not be null");
+ mRouteType = Objects.requireNonNull(routeType, "routeType must not be null");
mSelectedRoutes = new ArrayList<>();
mSelectableRoutes = new ArrayList<>();
mDeselectableRoutes = new ArrayList<>();
mTransferrableRoutes = new ArrayList<>();
}
- public Builder(RouteSessionInfo sessionInfo) {
- mSessionId = sessionInfo.mSessionId;
- mPackageName = sessionInfo.mPackageName;
- mControlCategory = sessionInfo.mControlCategory;
+ /**
+ * Constructor for builder to create {@link RouteSessionInfo} with
+ * existing {@link RouteSessionInfo} instance.
+ *
+ * @param sessionInfo the existing instance to copy data from.
+ */
+ public Builder(@NonNull RouteSessionInfo sessionInfo) {
+ Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
+
+ mId = sessionInfo.mId;
+ mClientPackageName = sessionInfo.mClientPackageName;
+ mRouteType = sessionInfo.mRouteType;
mProviderId = sessionInfo.mProviderId;
mSelectedRoutes = new ArrayList<>(sessionInfo.mSelectedRoutes);
@@ -327,10 +337,17 @@ public class RouteSessionInfo implements Parcelable {
}
/**
- * Sets the provider id of the session.
+ * Sets the provider ID of the session.
+ * Also, calling this method will make all type of route IDs be unique by adding
+ * {@code providerId:} as a prefix. So do NOT call this method twice on same instance.
+ *
+ * @hide
*/
@NonNull
- public Builder setProviderId(String providerId) {
+ public Builder setProviderId(@NonNull String providerId) {
+ if (TextUtils.isEmpty(providerId)) {
+ throw new IllegalArgumentException("providerId must not be empty");
+ }
mProviderId = providerId;
return this;
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index aff725734ee1..aece39d78694 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -940,16 +940,15 @@ public final class MediaSessionManager {
/**
* Called when a media key event is dispatched through the media session service. The
* session token can be {@link null} if the framework has sent the media key event to the
- * media button receiver to revive the media app's playback.
- *
- * the session is dead when , but the framework sent
+ * media button receiver to revive the media app's playback after the corresponding session
+ * is released.
*
* @param event Dispatched media key event.
* @param packageName Package
* @param sessionToken The media session's token. Can be {@code null}.
*/
default void onMediaKeyEventDispatched(@NonNull KeyEvent event, @NonNull String packageName,
- @NonNull MediaSession.Token sessionToken) { }
+ @Nullable MediaSession.Token sessionToken) { }
}
/**
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index 56e5566df29c..77596a5de815 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -22,7 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index 61b3e76e7cee..938ffcd5f731 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -23,7 +23,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.hardware.soundtrigger.ModelParams;
@@ -428,8 +428,7 @@ public final class SoundTriggerManager {
*/
@RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
public int setParameter(@Nullable UUID soundModelId,
- @ModelParams int modelParam, int value)
- throws UnsupportedOperationException, IllegalArgumentException {
+ @ModelParams int modelParam, int value) {
try {
return mSoundTriggerService.setParameter(new ParcelUuid(soundModelId), modelParam,
value);
@@ -449,15 +448,10 @@ public final class SoundTriggerManager {
* @param soundModelId UUID of model to get parameter
* @param modelParam {@link ModelParams}
* @return value of parameter
- * @throws UnsupportedOperationException if hal or model do not support this API.
- * {@link SoundTriggerManager#queryParameter} should be checked first.
- * @throws IllegalArgumentException if invalid model handle or parameter is passed.
- * {@link SoundTriggerManager#queryParameter} should be checked first.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
public int getParameter(@NonNull UUID soundModelId,
- @ModelParams int modelParam)
- throws UnsupportedOperationException, IllegalArgumentException {
+ @ModelParams int modelParam) {
try {
return mSoundTriggerService.getParameter(new ParcelUuid(soundModelId), modelParam);
} catch (RemoteException e) {
@@ -479,8 +473,7 @@ public final class SoundTriggerManager {
public ModelParamRange queryParameter(@Nullable UUID soundModelId,
@ModelParams int modelParam) {
try {
- return mSoundTriggerService.queryParameter(new ParcelUuid(soundModelId),
- modelParam);
+ return mSoundTriggerService.queryParameter(new ParcelUuid(soundModelId), modelParam);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 1b9cac0c8c99..377b2bc19c6b 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -20,7 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.StringRes;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 5c11ed9bb7b4..7fbb3376d5fb 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -22,9 +22,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
import android.app.ActivityManager;
import android.app.Service;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index ab7bbca1d01c..4318a0ae7d06 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -62,6 +62,8 @@ public final class TvTrackInfo implements Parcelable {
private final int mAudioChannelCount;
private final int mAudioSampleRate;
private final boolean mAudioDescription;
+ private final boolean mHardOfHearing;
+ private final boolean mSpokenSubtitle;
private final int mVideoWidth;
private final int mVideoHeight;
private final float mVideoFrameRate;
@@ -72,8 +74,9 @@ public final class TvTrackInfo implements Parcelable {
private TvTrackInfo(int type, String id, String language, CharSequence description,
boolean encrypted, int audioChannelCount, int audioSampleRate, boolean audioDescription,
- int videoWidth, int videoHeight, float videoFrameRate, float videoPixelAspectRatio,
- byte videoActiveFormatDescription, Bundle extra) {
+ boolean hardOfHearing, boolean spokenSubtitle, int videoWidth, int videoHeight,
+ float videoFrameRate, float videoPixelAspectRatio, byte videoActiveFormatDescription,
+ Bundle extra) {
mType = type;
mId = id;
mLanguage = language;
@@ -82,6 +85,8 @@ public final class TvTrackInfo implements Parcelable {
mAudioChannelCount = audioChannelCount;
mAudioSampleRate = audioSampleRate;
mAudioDescription = audioDescription;
+ mHardOfHearing = hardOfHearing;
+ mSpokenSubtitle = spokenSubtitle;
mVideoWidth = videoWidth;
mVideoHeight = videoHeight;
mVideoFrameRate = videoFrameRate;
@@ -99,6 +104,8 @@ public final class TvTrackInfo implements Parcelable {
mAudioChannelCount = in.readInt();
mAudioSampleRate = in.readInt();
mAudioDescription = in.readInt() != 0;
+ mHardOfHearing = in.readInt() != 0;
+ mSpokenSubtitle = in.readInt() != 0;
mVideoWidth = in.readInt();
mVideoHeight = in.readInt();
mVideoFrameRate = in.readFloat();
@@ -192,6 +199,39 @@ public final class TvTrackInfo implements Parcelable {
}
/**
+ * Returns {@code true} if the track is intended for people with hearing impairment, {@code
+ * false} otherwise. Valid only for {@link #TYPE_AUDIO} and {@link #TYPE_SUBTITLE} tracks.
+ *
+ * <p>For example of broadcast, hard of hearing information may be referred to broadcast
+ * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio Language
+ * Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN 300 468).
+ *
+ * @throws IllegalStateException if not called on an audio track or a subtitle track
+ */
+ public boolean isHardOfHearing() {
+ if (mType != TYPE_AUDIO && mType != TYPE_SUBTITLE) {
+ throw new IllegalStateException("Not an audio or a subtitle track");
+ }
+ return mHardOfHearing;
+ }
+
+ /**
+ * Returns {@code true} if the track is a spoken subtitle for people with visual impairment,
+ * {@code false} otherwise. Valid only for {@link #TYPE_AUDIO} tracks.
+ *
+ * <p>For example of broadcast, spoken subtitle information may be referred to broadcast
+ * standard (e.g. Supplementary Audio Language Descriptor of ETSI EN 300 468).
+ *
+ * @throws IllegalStateException if not called on an audio track
+ */
+ public boolean isSpokenSubtitle() {
+ if (mType != TYPE_AUDIO) {
+ throw new IllegalStateException("Not an audio track");
+ }
+ return mSpokenSubtitle;
+ }
+
+ /**
* Returns the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO}
* tracks.
*
@@ -287,6 +327,8 @@ public final class TvTrackInfo implements Parcelable {
dest.writeInt(mAudioChannelCount);
dest.writeInt(mAudioSampleRate);
dest.writeInt(mAudioDescription ? 1 : 0);
+ dest.writeInt(mHardOfHearing ? 1 : 0);
+ dest.writeInt(mSpokenSubtitle ? 1 : 0);
dest.writeInt(mVideoWidth);
dest.writeInt(mVideoHeight);
dest.writeFloat(mVideoFrameRate);
@@ -310,6 +352,7 @@ public final class TvTrackInfo implements Parcelable {
if (!TextUtils.equals(mId, obj.mId) || mType != obj.mType
|| !TextUtils.equals(mLanguage, obj.mLanguage)
|| !TextUtils.equals(mDescription, obj.mDescription)
+ || mEncrypted != obj.mEncrypted
|| !Objects.equals(mExtra, obj.mExtra)) {
return false;
}
@@ -318,7 +361,9 @@ public final class TvTrackInfo implements Parcelable {
case TYPE_AUDIO:
return mAudioChannelCount == obj.mAudioChannelCount
&& mAudioSampleRate == obj.mAudioSampleRate
- && mAudioDescription == obj.mAudioDescription;
+ && mAudioDescription == obj.mAudioDescription
+ && mHardOfHearing == obj.mHardOfHearing
+ && mSpokenSubtitle == obj.mSpokenSubtitle;
case TYPE_VIDEO:
return mVideoWidth == obj.mVideoWidth
@@ -326,6 +371,9 @@ public final class TvTrackInfo implements Parcelable {
&& mVideoFrameRate == obj.mVideoFrameRate
&& mVideoPixelAspectRatio == obj.mVideoPixelAspectRatio
&& mVideoActiveFormatDescription == obj.mVideoActiveFormatDescription;
+
+ case TYPE_SUBTITLE:
+ return mHardOfHearing == obj.mHardOfHearing;
}
return true;
@@ -361,6 +409,8 @@ public final class TvTrackInfo implements Parcelable {
private int mAudioChannelCount;
private int mAudioSampleRate;
private boolean mAudioDescription;
+ private boolean mHardOfHearing;
+ private boolean mSpokenSubtitle;
private int mVideoWidth;
private int mVideoHeight;
private float mVideoFrameRate;
@@ -474,6 +524,46 @@ public final class TvTrackInfo implements Parcelable {
}
/**
+ * Sets the hard of hearing attribute of the track. Valid only for {@link #TYPE_AUDIO} and
+ * {@link #TYPE_SUBTITLE} tracks.
+ *
+ * <p>For example of broadcast, hard of hearing information may be referred to broadcast
+ * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio
+ * Language Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN
+ * 300 468).
+ *
+ * @param hardOfHearing The hard of hearing attribute of the track.
+ * @throws IllegalStateException if not called on an audio track or a subtitle track
+ */
+ @NonNull
+ public Builder setHardOfHearing(boolean hardOfHearing) {
+ if (mType != TYPE_AUDIO && mType != TYPE_SUBTITLE) {
+ throw new IllegalStateException("Not an audio track or a subtitle track");
+ }
+ mHardOfHearing = hardOfHearing;
+ return this;
+ }
+
+ /**
+ * Sets the spoken subtitle attribute of the audio. Valid only for {@link #TYPE_AUDIO}
+ * tracks.
+ *
+ * <p>For example of broadcast, spoken subtitle information may be referred to broadcast
+ * standard (e.g. Supplementary Audio Language Descriptor of ETSI EN 300 468).
+ *
+ * @param spokenSubtitle The spoken subtitle attribute of the audio.
+ * @throws IllegalStateException if not called on an audio track
+ */
+ @NonNull
+ public Builder setSpokenSubtitle(boolean spokenSubtitle) {
+ if (mType != TYPE_AUDIO) {
+ throw new IllegalStateException("Not an audio track");
+ }
+ mSpokenSubtitle = spokenSubtitle;
+ return this;
+ }
+
+ /**
* Sets the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO}
* tracks.
*
@@ -575,9 +665,9 @@ public final class TvTrackInfo implements Parcelable {
*/
public TvTrackInfo build() {
return new TvTrackInfo(mType, mId, mLanguage, mDescription, mEncrypted,
- mAudioChannelCount, mAudioSampleRate, mAudioDescription, mVideoWidth,
- mVideoHeight, mVideoFrameRate, mVideoPixelAspectRatio,
- mVideoActiveFormatDescription, mExtra);
+ mAudioChannelCount, mAudioSampleRate, mAudioDescription, mHardOfHearing,
+ mSpokenSubtitle, mVideoWidth, mVideoHeight, mVideoFrameRate,
+ mVideoPixelAspectRatio, mVideoActiveFormatDescription, mExtra);
}
}
}
diff --git a/media/java/android/media/tv/tuner/Descrambler.java b/media/java/android/media/tv/tuner/Descrambler.java
new file mode 100644
index 000000000000..f9f7a22c3de8
--- /dev/null
+++ b/media/java/android/media/tv/tuner/Descrambler.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 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.media.tv.tuner;
+
+import android.annotation.Nullable;
+import android.media.tv.tuner.Tuner.Filter;
+import android.media.tv.tuner.TunerConstants.DemuxPidType;
+
+/**
+ * This class is used to interact with descramblers.
+ *
+ * <p> Descrambler is a hardware component used to descramble data.
+ *
+ * <p> This class controls the TIS interaction with Tuner HAL.
+ * @hide
+ */
+public class Descrambler implements AutoCloseable {
+ private long mNativeContext;
+
+ private native int nativeAddPid(int pidType, int pid, Filter filter);
+ private native int nativeRemovePid(int pidType, int pid, Filter filter);
+ private native int nativeSetKeyToken(byte[] keyToken);
+ private native int nativeClose();
+
+ private Descrambler() {}
+
+ /**
+ * Add packets' PID to the descrambler for descrambling.
+ *
+ * The descrambler will start descrambling packets with this PID. Multiple PIDs can be added
+ * into one descrambler instance because descambling can happen simultaneously on packets
+ * from different PIDs.
+ *
+ * If the Descrambler previously contained a filter for the PID, the old filter is replaced
+ * by the specified filter.
+ *
+ * @param pidType the type of the PID.
+ * @param pid the PID of packets to start to be descrambled.
+ * @param filter an optional filter instance to identify upper stream.
+ * @return result status of the operation.
+ *
+ * @hide
+ */
+ public int addPid(@DemuxPidType int pidType, int pid, @Nullable Filter filter) {
+ return nativeAddPid(pidType, pid, filter);
+ }
+
+ /**
+ * Remove packets' PID from the descrambler
+ *
+ * The descrambler will stop descrambling packets with this PID.
+ *
+ * @param pidType the type of the PID.
+ * @param pid the PID of packets to stop to be descrambled.
+ * @param filter an optional filter instance to identify upper stream.
+ * @return result status of the operation.
+ *
+ * @hide
+ */
+ public int removePid(@DemuxPidType int pidType, int pid, @Nullable Filter filter) {
+ return nativeRemovePid(pidType, pid, filter);
+ }
+
+ /**
+ * Set a key token to link descrambler to a key slot
+ *
+ * A descrambler instance can have only one key slot to link, but a key slot can hold a few
+ * keys for different purposes.
+ *
+ * @param keyToken the token to be used to link the key slot.
+ * @return result status of the operation.
+ *
+ * @hide
+ */
+ public int setKeyToken(byte[] keyToken) {
+ return nativeSetKeyToken(keyToken);
+ }
+
+ /**
+ * Release the descrambler instance.
+ *
+ * @hide
+ */
+ @Override
+ public void close() {
+ nativeClose();
+ }
+
+}
diff --git a/media/java/android/media/tv/tuner/Dvr.java b/media/java/android/media/tv/tuner/Dvr.java
new file mode 100644
index 000000000000..0bfba8f9d4f3
--- /dev/null
+++ b/media/java/android/media/tv/tuner/Dvr.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 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.media.tv.tuner;
+
+import android.annotation.NonNull;
+import android.media.tv.tuner.Tuner.DvrCallback;
+import android.media.tv.tuner.Tuner.Filter;
+import android.os.ParcelFileDescriptor;
+
+/** @hide */
+public class Dvr {
+ private long mNativeContext;
+ private DvrCallback mCallback;
+
+ private native int nativeAttachFilter(Filter filter);
+ private native int nativeDetachFilter(Filter filter);
+ private native int nativeConfigureDvr(DvrSettings settings);
+ private native int nativeStartDvr();
+ private native int nativeStopDvr();
+ private native int nativeFlushDvr();
+ private native int nativeClose();
+ private native void nativeSetFileDescriptor(int fd);
+ private native int nativeRead(int size);
+ private native int nativeRead(byte[] bytes, int offset, int size);
+ private native int nativeWrite(int size);
+ private native int nativeWrite(byte[] bytes, int offset, int size);
+
+ private Dvr() {}
+
+ /**
+ * Attaches a filter to DVR interface for recording.
+ *
+ * @param filter the filter to be attached.
+ * @return result status of the operation.
+ */
+ public int attachFilter(Filter filter) {
+ return nativeAttachFilter(filter);
+ }
+
+ /**
+ * Detaches a filter from DVR interface.
+ *
+ * @param filter the filter to be detached.
+ * @return result status of the operation.
+ */
+ public int detachFilter(Filter filter) {
+ return nativeDetachFilter(filter);
+ }
+
+ /**
+ * Configures the DVR.
+ *
+ * @param settings the settings of the DVR interface.
+ * @return result status of the operation.
+ */
+ public int configure(DvrSettings settings) {
+ return nativeConfigureDvr(settings);
+ }
+
+ /**
+ * Starts DVR.
+ *
+ * Starts consuming playback data or producing data for recording.
+ *
+ * @return result status of the operation.
+ */
+ public int start() {
+ return nativeStartDvr();
+ }
+
+ /**
+ * Stops DVR.
+ *
+ * Stops consuming playback data or producing data for recording.
+ *
+ * @return result status of the operation.
+ */
+ public int stop() {
+ return nativeStopDvr();
+ }
+
+ /**
+ * Flushed DVR data.
+ *
+ * @return result status of the operation.
+ */
+ public int flush() {
+ return nativeFlushDvr();
+ }
+
+ /**
+ * closes the DVR instance to release resources.
+ *
+ * @return result status of the operation.
+ */
+ public int close() {
+ return nativeClose();
+ }
+
+ /**
+ * Sets file descriptor to read/write data.
+ */
+ public void setFileDescriptor(ParcelFileDescriptor fd) {
+ nativeSetFileDescriptor(fd.getFd());
+ }
+
+ /**
+ * Reads data from the file for DVR playback.
+ */
+ public int read(int size) {
+ return nativeRead(size);
+ }
+
+ /**
+ * Reads data from the buffer for DVR playback.
+ */
+ public int read(@NonNull byte[] bytes, int offset, int size) {
+ if (size + offset > bytes.length) {
+ throw new ArrayIndexOutOfBoundsException(
+ "Array length=" + bytes.length + ", offset=" + offset + ", size=" + size);
+ }
+ return nativeRead(bytes, offset, size);
+ }
+
+ /**
+ * Writes recording data to file.
+ */
+ public int write(int size) {
+ return nativeWrite(size);
+ }
+
+ /**
+ * Writes recording data to buffer.
+ */
+ public int write(@NonNull byte[] bytes, int offset, int size) {
+ return nativeWrite(bytes, offset, size);
+ }
+}
diff --git a/media/java/android/media/tv/tuner/Filter.java b/media/java/android/media/tv/tuner/Filter.java
new file mode 100644
index 000000000000..db3b97afb1da
--- /dev/null
+++ b/media/java/android/media/tv/tuner/Filter.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 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.media.tv.tuner;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.media.tv.tuner.Tuner.FilterCallback;
+import android.media.tv.tuner.filter.FilterConfiguration;
+import android.media.tv.tuner.filter.Settings;
+
+/**
+ * Tuner data filter.
+ *
+ * <p> This class is used to filter wanted data according to the filter's configuration.
+ * @hide
+ */
+public class Filter implements AutoCloseable {
+ private long mNativeContext;
+ private FilterCallback mCallback;
+ int mId;
+
+ private native int nativeConfigureFilter(
+ int type, int subType, FilterConfiguration settings);
+ private native int nativeGetId();
+ private native int nativeSetDataSource(Tuner.Filter source);
+ private native int nativeStartFilter();
+ private native int nativeStopFilter();
+ private native int nativeFlushFilter();
+ private native int nativeRead(byte[] buffer, int offset, int size);
+ private native int nativeClose();
+
+ private Filter(int id) {
+ mId = id;
+ }
+
+ private void onFilterStatus(int status) {
+ }
+
+ /**
+ * Configures the filter.
+ *
+ * @param settings the settings of the filter.
+ * @return result status of the operation.
+ * @hide
+ */
+ public int configure(FilterConfiguration settings) {
+ int subType = -1;
+ Settings s = settings.getSettings();
+ if (s != null) {
+ subType = s.getType();
+ }
+ return nativeConfigureFilter(settings.getType(), subType, settings);
+ }
+
+ /**
+ * Gets the filter Id.
+ *
+ * @return the hardware resource Id for the filter.
+ * @hide
+ */
+ public int getId() {
+ return nativeGetId();
+ }
+
+ /**
+ * Sets the filter's data source.
+ *
+ * A filter uses demux as data source by default. If the data was packetized
+ * by multiple protocols, multiple filters may need to work together to
+ * extract all protocols' header. Then a filter's data source can be output
+ * from another filter.
+ *
+ * @param source the filter instance which provides data input. Switch to
+ * use demux as data source if the filter instance is NULL.
+ * @return result status of the operation.
+ * @hide
+ */
+ public int setDataSource(@Nullable Tuner.Filter source) {
+ return nativeSetDataSource(source);
+ }
+
+ /**
+ * Starts the filter.
+ *
+ * @return result status of the operation.
+ * @hide
+ */
+ public int start() {
+ return nativeStartFilter();
+ }
+
+
+ /**
+ * Stops the filter.
+ *
+ * @return result status of the operation.
+ * @hide
+ */
+ public int stop() {
+ return nativeStopFilter();
+ }
+
+ /**
+ * Flushes the filter.
+ *
+ * @return result status of the operation.
+ * @hide
+ */
+ public int flush() {
+ return nativeFlushFilter();
+ }
+
+ /** @hide */
+ public int read(@NonNull byte[] buffer, int offset, int size) {
+ size = Math.min(size, buffer.length - offset);
+ return nativeRead(buffer, offset, size);
+ }
+
+ /**
+ * Release the Filter instance.
+ *
+ * @hide
+ */
+ @Override
+ public void close() {
+ nativeClose();
+ }
+}
diff --git a/media/java/android/media/tv/tuner/FilterConfiguration.java b/media/java/android/media/tv/tuner/FilterConfiguration.java
deleted file mode 100644
index b80a82a904b6..000000000000
--- a/media/java/android/media/tv/tuner/FilterConfiguration.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright 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.media.tv.tuner;
-
-import android.annotation.Nullable;
-import android.media.tv.tuner.TunerConstants.FilterType;
-
-import java.util.List;
-
-/**
- * Demux Filter configuration.
- *
- * @hide
- */
-public abstract class FilterConfiguration {
- @Nullable
- protected final Settings mSettings;
-
- protected FilterConfiguration(Settings settings) {
- mSettings = settings;
- }
-
- /**
- * Gets filter configuration type
- */
- @FilterType
- public abstract int getType();
-
- public Settings getSettings() {
- return mSettings;
- }
-
- // TODO: more builders and getters
-
- /**
- * Filter configuration for a TS filter.
- */
- public static class TsFilterConfiguration extends FilterConfiguration {
- private int mTpid;
-
- private TsFilterConfiguration(Settings settings, int tpid) {
- super(settings);
- mTpid = tpid;
- }
-
- @Override
- public int getType() {
- return TunerConstants.FILTER_TYPE_TS;
- }
-
- /**
- * Creates a new builder.
- */
- public static Builder newBuilder() {
- return new Builder();
- }
-
- /**
- * Builder for TsFilterConfiguration.
- */
- public static class Builder {
- private Settings mSettings;
- private int mTpid;
-
- /**
- * Sets settings.
- */
- public Builder setSettings(Settings settings) {
- mSettings = settings;
- return this;
- }
-
- /**
- * Sets TPID.
- */
- public Builder setTpid(int tpid) {
- mTpid = tpid;
- return this;
- }
-
- /**
- * Builds a TsFilterConfiguration instance.
- */
- public TsFilterConfiguration build() {
- return new TsFilterConfiguration(mSettings, mTpid);
- }
- }
- }
-
- /**
- * Filter configuration for a MMTP filter.
- */
- public static class MmtpFilterConfiguration extends FilterConfiguration {
- private int mMmtpPid;
-
- public MmtpFilterConfiguration(Settings settings) {
- super(settings);
- }
-
- @Override
- public int getType() {
- return TunerConstants.FILTER_TYPE_MMTP;
- }
- }
-
-
- /**
- * Filter configuration for a IP filter.
- */
- public static class IpFilterConfiguration extends FilterConfiguration {
- private byte[] mSrcIpAddress;
- private byte[] mDstIpAddress;
- private int mSrcPort;
- private int mDstPort;
- private boolean mPassthrough;
-
- public IpFilterConfiguration(Settings settings) {
- super(settings);
- }
-
- @Override
- public int getType() {
- return TunerConstants.FILTER_TYPE_IP;
- }
- }
-
-
- /**
- * Filter configuration for a TLV filter.
- */
- public static class TlvFilterConfiguration extends FilterConfiguration {
- private int mPacketType;
- private boolean mIsCompressedIpPacket;
- private boolean mPassthrough;
-
- public TlvFilterConfiguration(Settings settings) {
- super(settings);
- }
-
- @Override
- public int getType() {
- return TunerConstants.FILTER_TYPE_TLV;
- }
- }
-
-
- /**
- * Filter configuration for a ALP filter.
- */
- public static class AlpFilterConfiguration extends FilterConfiguration {
- private int mPacketType;
- private int mLengthType;
-
- public AlpFilterConfiguration(Settings settings) {
- super(settings);
- }
-
- @Override
- public int getType() {
- return TunerConstants.FILTER_TYPE_ALP;
- }
- }
-
-
- /**
- * Settings for filters of different subtypes.
- */
- public abstract static class Settings {
- protected final int mType;
-
- protected Settings(int type) {
- mType = type;
- }
-
- /**
- * Gets filter settings type.
- * @return
- */
- int getType() {
- return mType;
- }
- }
-
- /**
- * Filter Settings for Section data according to ISO/IEC 13818-1.
- */
- public static class SectionSettings extends Settings {
-
- private SectionSettings(int mainType) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_SECTION));
- }
- }
-
- /**
- * Bits Settings for Section Filter.
- */
- public static class SectionSettingsWithSectionBits extends SectionSettings {
- private List<Byte> mFilter;
- private List<Byte> mMask;
- private List<Byte> mMode;
-
- private SectionSettingsWithSectionBits(int mainType) {
- super(mainType);
- }
- }
-
- /**
- * Table information for Section Filter.
- */
- public static class SectionSettingsWithTableInfo extends SectionSettings {
- private int mTableId;
- private int mVersion;
-
- private SectionSettingsWithTableInfo(int mainType) {
- super(mainType);
- }
- }
-
- /**
- * Filter Settings for a PES Data.
- */
- public static class PesSettings extends Settings {
- private int mStreamId;
- private boolean mIsRaw;
-
- private PesSettings(int mainType, int streamId, boolean isRaw) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_PES));
- mStreamId = streamId;
- mIsRaw = isRaw;
- }
-
- /**
- * Creates a builder for PesSettings.
- */
- public static Builder newBuilder(int mainType) {
- return new Builder(mainType);
- }
-
- /**
- * Builder for PesSettings.
- */
- public static class Builder {
- private final int mMainType;
- private int mStreamId;
- private boolean mIsRaw;
-
- public Builder(int mainType) {
- mMainType = mainType;
- }
-
- /**
- * Sets stream ID.
- */
- public Builder setStreamId(int streamId) {
- mStreamId = streamId;
- return this;
- }
-
- /**
- * Sets whether it's raw.
- * true if the filter send onFilterStatus instead of onFilterEvent.
- */
- public Builder setIsRaw(boolean isRaw) {
- mIsRaw = isRaw;
- return this;
- }
-
- /**
- * Builds a PesSettings instance.
- */
- public PesSettings build() {
- return new PesSettings(mMainType, mStreamId, mIsRaw);
- }
- }
- }
-
- /**
- * Filter Settings for a Video and Audio.
- */
- public static class AvSettings extends Settings {
- private boolean mIsPassthrough;
-
- private AvSettings(int mainType, boolean isAudio) {
- super(TunerUtils.getFilterSubtype(
- mainType,
- isAudio
- ? TunerConstants.FILTER_SUBTYPE_AUDIO
- : TunerConstants.FILTER_SUBTYPE_VIDEO));
- }
- }
-
- /**
- * Filter Settings for a Download.
- */
- public static class DownloadSettings extends Settings {
- private int mDownloadId;
-
- public DownloadSettings(int mainType) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_DOWNLOAD));
- }
- }
-
- /**
- * The Settings for the record in DVR.
- */
- public static class RecordSettings extends Settings {
- private int mIndexType;
- private int mIndexMask;
-
- public RecordSettings(int mainType) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_RECORD));
- }
- }
-
-}
diff --git a/media/java/android/media/tv/tuner/FrontendCapabilities.java b/media/java/android/media/tv/tuner/FrontendCapabilities.java
deleted file mode 100644
index fcfd7c8c8639..000000000000
--- a/media/java/android/media/tv/tuner/FrontendCapabilities.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright 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.media.tv.tuner;
-
-/**
- * Frontend Capabilities.
- * @hide
- */
-public class FrontendCapabilities {
- /** Analog Capabilities. */
- public class Analog extends FrontendCapabilities {
- private final int mTypeCap;
- private final int mSifStandardCap;
-
- Analog(int typeCap, int sifStandardCap) {
- mTypeCap = typeCap;
- mSifStandardCap = sifStandardCap;
- }
- /**
- * Gets type capability.
- */
- public int getTypeCapability() {
- return mTypeCap;
- }
- /** Gets SIF standard capability. */
- public int getSifStandardCapability() {
- return mSifStandardCap;
- }
- }
-
- /** ATSC Capabilities. */
- public class Atsc extends FrontendCapabilities {
- private final int mModulationCap;
-
- Atsc(int modulationCap) {
- mModulationCap = modulationCap;
- }
- /** Gets modulation capability. */
- public int getModulationCapability() {
- return mModulationCap;
- }
- }
-
- /** ATSC-3 Capabilities. */
- public class Atsc3 extends FrontendCapabilities {
- private final int mBandwidthCap;
- private final int mModulationCap;
- private final int mTimeInterleaveModeCap;
- private final int mCodeRateCap;
- private final int mFecCap;
- private final int mDemodOutputFormatCap;
-
- Atsc3(int bandwidthCap, int modulationCap, int timeInterleaveModeCap, int codeRateCap,
- int fecCap, int demodOutputFormatCap) {
- mBandwidthCap = bandwidthCap;
- mModulationCap = modulationCap;
- mTimeInterleaveModeCap = timeInterleaveModeCap;
- mCodeRateCap = codeRateCap;
- mFecCap = fecCap;
- mDemodOutputFormatCap = demodOutputFormatCap;
- }
-
- /** Gets bandwidth capability. */
- public int getBandwidthCapability() {
- return mBandwidthCap;
- }
- /** Gets modulation capability. */
- public int getModulationCapability() {
- return mModulationCap;
- }
- /** Gets time interleave mod capability. */
- public int getTimeInterleaveModeCapability() {
- return mTimeInterleaveModeCap;
- }
- /** Gets code rate capability. */
- public int getCodeRateCapability() {
- return mCodeRateCap;
- }
- /** Gets FEC capability. */
- public int getFecCapability() {
- return mFecCap;
- }
- /** Gets demodulator output format capability. */
- public int getDemodOutputFormatCapability() {
- return mDemodOutputFormatCap;
- }
- }
-
- /** DVBS Capabilities. */
- public class Dvbs extends FrontendCapabilities {
- private final int mModulationCap;
- private final long mInnerFecCap;
- private final int mStandard;
-
- Dvbs(int modulationCap, long innerFecCap, int standard) {
- mModulationCap = modulationCap;
- mInnerFecCap = innerFecCap;
- mStandard = standard;
- }
-
- /** Gets modulation capability. */
- public int getModulationCapability() {
- return mModulationCap;
- }
- /** Gets inner FEC capability. */
- public long getInnerFecCapability() {
- return mInnerFecCap;
- }
- /** Gets DVBS standard capability. */
- public int getStandardCapability() {
- return mStandard;
- }
- }
-
- /** DVBC Capabilities. */
- public class Dvbc extends FrontendCapabilities {
- private final int mModulationCap;
- private final int mFecCap;
- private final int mAnnexCap;
-
- Dvbc(int modulationCap, int fecCap, int annexCap) {
- mModulationCap = modulationCap;
- mFecCap = fecCap;
- mAnnexCap = annexCap;
- }
-
- /** Gets modulation capability. */
- public int getModulationCapability() {
- return mModulationCap;
- }
- /** Gets FEC capability. */
- public int getFecCapability() {
- return mFecCap;
- }
- /** Gets annex capability. */
- public int getAnnexCapability() {
- return mAnnexCap;
- }
- }
-
- /** DVBT Capabilities. */
- public class Dvbt extends FrontendCapabilities {
- private final int mTransmissionModeCap;
- private final int mBandwidthCap;
- private final int mConstellationCap;
- private final int mCoderateCap;
- private final int mHierarchyCap;
- private final int mGuardIntervalCap;
- private final boolean mIsT2Supported;
- private final boolean mIsMisoSupported;
-
- Dvbt(int transmissionModeCap, int bandwidthCap, int constellationCap, int coderateCap,
- int hierarchyCap, int guardIntervalCap, boolean isT2Supported,
- boolean isMisoSupported) {
- mTransmissionModeCap = transmissionModeCap;
- mBandwidthCap = bandwidthCap;
- mConstellationCap = constellationCap;
- mCoderateCap = coderateCap;
- mHierarchyCap = hierarchyCap;
- mGuardIntervalCap = guardIntervalCap;
- mIsT2Supported = isT2Supported;
- mIsMisoSupported = isMisoSupported;
- }
-
- /** Gets transmission mode capability. */
- public int getTransmissionModeCapability() {
- return mTransmissionModeCap;
- }
- /** Gets bandwidth capability. */
- public int getBandwidthCapability() {
- return mBandwidthCap;
- }
- /** Gets constellation capability. */
- public int getConstellationCapability() {
- return mConstellationCap;
- }
- /** Gets code rate capability. */
- public int getCodeRateCapability() {
- return mCoderateCap;
- }
- /** Gets hierarchy capability. */
- public int getHierarchyCapability() {
- return mHierarchyCap;
- }
- /** Gets guard interval capability. */
- public int getGuardIntervalCapability() {
- return mGuardIntervalCap;
- }
- /** Returns whether T2 is supported. */
- public boolean getIsT2Supported() {
- return mIsT2Supported;
- }
- /** Returns whether MISO is supported. */
- public boolean getIsMisoSupported() {
- return mIsMisoSupported;
- }
- }
-
- /** ISDBS Capabilities. */
- public class Isdbs extends FrontendCapabilities {
- private final int mModulationCap;
- private final int mCoderateCap;
-
- Isdbs(int modulationCap, int coderateCap) {
- mModulationCap = modulationCap;
- mCoderateCap = coderateCap;
- }
-
- /** Gets modulation capability. */
- public int getModulationCapability() {
- return mModulationCap;
- }
- /** Gets code rate capability. */
- public int getCodeRateCapability() {
- return mCoderateCap;
- }
- }
-
- /** ISDBS-3 Capabilities. */
- public class Isdbs3 extends FrontendCapabilities {
- private final int mModulationCap;
- private final int mCoderateCap;
-
- Isdbs3(int modulationCap, int coderateCap) {
- mModulationCap = modulationCap;
- mCoderateCap = coderateCap;
- }
-
- /** Gets modulation capability. */
- public int getModulationCapability() {
- return mModulationCap;
- }
- /** Gets code rate capability. */
- public int getCodeRateCapability() {
- return mCoderateCap;
- }
- }
-
- /** ISDBC Capabilities. */
- public class Isdbc extends FrontendCapabilities {
- private final int mModeCap;
- private final int mBandwidthCap;
- private final int mModulationCap;
- private final int mCoderateCap;
- private final int mGuardIntervalCap;
-
- Isdbc(int modeCap, int bandwidthCap, int modulationCap, int coderateCap,
- int guardIntervalCap) {
- mModeCap = modeCap;
- mBandwidthCap = bandwidthCap;
- mModulationCap = modulationCap;
- mCoderateCap = coderateCap;
- mGuardIntervalCap = guardIntervalCap;
- }
-
- /** Gets mode capability. */
- public int getModeCapability() {
- return mModeCap;
- }
- /** Gets bandwidth capability. */
- public int getBandwidthCapability() {
- return mBandwidthCap;
- }
- /** Gets modulation capability. */
- public int getModulationCapability() {
- return mModulationCap;
- }
- /** Gets code rate capability. */
- public int getCodeRateCapability() {
- return mCoderateCap;
- }
- /** Gets guard interval capability. */
- public int getGuardIntervalCapability() {
- return mGuardIntervalCap;
- }
- }
-}
diff --git a/media/java/android/media/tv/tuner/TimeFilter.java b/media/java/android/media/tv/tuner/TimeFilter.java
new file mode 100644
index 000000000000..8bd0d26ce951
--- /dev/null
+++ b/media/java/android/media/tv/tuner/TimeFilter.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 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.media.tv.tuner;
+
+import android.annotation.Nullable;
+import android.media.tv.tuner.TunerConstants.Result;
+
+/**
+ * A timer filter is used to filter data based on timestamps.
+ *
+ * <p> If the timestamp is set, data is discarded if its timestamp is smaller than the
+ * timestamp in this time filter.
+ *
+ * <p> The format of the timestamps is the same as PTS defined in ISO/IEC 13818-1:2019. The
+ * timestamps may or may not be related to PTS or DTS.
+ *
+ * @hide
+ */
+public class TimeFilter implements AutoCloseable {
+ private native int nativeSetTimestamp(long timestamp);
+ private native int nativeClearTimestamp();
+ private native Long nativeGetTimestamp();
+ private native Long nativeGetSourceTime();
+ private native int nativeClose();
+
+ private boolean mEnable = false;
+
+ /**
+ * Set timestamp for time based filter.
+ *
+ * It is used to set initial timestamp and enable time filtering. Once set, the time will be
+ * increased automatically like a clock. Contents are discarded if their timestamps are
+ * older than the time in the time filter.
+ *
+ * This method can be called more than once to reset the initial timestamp.
+ *
+ * @param timestamp initial timestamp for the time filter before it's increased. It's
+ * based on the 90KHz counter, and it's the same format as PTS (Presentation Time Stamp)
+ * defined in ISO/IEC 13818-1:2019. The timestamps may or may not be related to PTS or DTS.
+ * @return result status of the operation.
+ */
+ @Result
+ public int setCurrentTimestamp(long timestamp) {
+ int res = nativeSetTimestamp(timestamp);
+ // TODO: use a constant for SUCCESS
+ if (res == 0) {
+ mEnable = true;
+ }
+ return res;
+ }
+
+ /**
+ * Clear the timestamp in the time filter.
+ *
+ * It is used to clear the time value of the time filter. Time filtering is disabled then.
+ *
+ * @return result status of the operation.
+ */
+ @Result
+ public int clearTimestamp() {
+ int res = nativeClearTimestamp();
+ if (res == 0) {
+ mEnable = false;
+ }
+ return res;
+ }
+
+ /**
+ * Get the current time in the time filter.
+ *
+ * It is used to inquiry current time in the time filter.
+ *
+ * @return current timestamp in the time filter. It's based on the 90KHz counter, and it's
+ * the same format as PTS (Presentation Time Stamp) defined in ISO/IEC 13818-1:2019. The
+ * timestamps may or may not be related to PTS or DTS. {@code null} if the timestamp is
+ * never set.
+ */
+ @Nullable
+ public Long getTimeStamp() {
+ if (!mEnable) {
+ return null;
+ }
+ return nativeGetTimestamp();
+ }
+
+ /**
+ * Get the timestamp from the beginning of incoming data stream.
+ *
+ * It is used to inquiry the timestamp from the beginning of incoming data stream.
+ *
+ * @return first timestamp of incoming data stream. It's based on the 90KHz counter, and
+ * it's the same format as PTS (Presentation Time Stamp) defined in ISO/IEC 13818-1:2019.
+ * The timestamps may or may not be related to PTS or DTS.
+ */
+ @Nullable
+ public Long getSourceTime() {
+ if (!mEnable) {
+ return null;
+ }
+ return nativeGetSourceTime();
+ }
+
+ /**
+ * Close the Time Filter instance
+ *
+ * It is to release the TimeFilter instance. Resources are reclaimed so the instance must
+ * not be accessed after this method is called.
+ */
+ @Override
+ public void close() {
+ nativeClose();
+ }
+}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 43f9a8973e80..962a7f6d58f6 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -21,16 +21,14 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
-import android.media.tv.tuner.FilterConfiguration.Settings;
-import android.media.tv.tuner.TunerConstants.DemuxPidType;
import android.media.tv.tuner.TunerConstants.FilterStatus;
import android.media.tv.tuner.TunerConstants.FilterSubtype;
-import android.media.tv.tuner.TunerConstants.FilterType;
import android.media.tv.tuner.TunerConstants.FrontendScanType;
import android.media.tv.tuner.TunerConstants.LnbPosition;
import android.media.tv.tuner.TunerConstants.LnbTone;
import android.media.tv.tuner.TunerConstants.LnbVoltage;
import android.media.tv.tuner.TunerConstants.Result;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
import android.media.tv.tuner.filter.FilterEvent;
import android.media.tv.tuner.frontend.FrontendCallback;
import android.media.tv.tuner.frontend.FrontendInfo;
@@ -39,7 +37,6 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import java.io.FileDescriptor;
import java.util.List;
/**
@@ -123,6 +120,7 @@ public final class Tuner implements AutoCloseable {
private native int nativeDisconnectCiCam();
private native FrontendInfo nativeGetFrontendInfo(int id);
private native Filter nativeOpenFilter(int type, int subType, int bufferSize);
+ private native TimeFilter nativeOpenTimeFilter();
private native List<Integer> nativeGetLnbIds();
private native Lnb nativeOpenLnbById(int id);
@@ -456,122 +454,11 @@ public final class Tuner implements AutoCloseable {
* Tuner data filter.
*
* <p> This class is used to filter wanted data according to the filter's configuration.
+ * TODO: remove
*/
public class Filter {
- private long mNativeContext;
- private FilterCallback mCallback;
- int mId;
-
- private native int nativeConfigureFilter(
- int type, int subType, FilterConfiguration settings);
- private native int nativeGetId();
- private native int nativeSetDataSource(Filter source);
- private native int nativeStartFilter();
- private native int nativeStopFilter();
- private native int nativeFlushFilter();
- private native int nativeRead(byte[] buffer, int offset, int size);
- private native int nativeClose();
-
- private Filter(int id) {
- mId = id;
- }
-
- private void onFilterStatus(int status) {
- if (mHandler != null) {
- mHandler.sendMessage(
- mHandler.obtainMessage(MSG_ON_FILTER_STATUS, status, 0, this));
- }
- }
-
- /**
- * Configures the filter.
- *
- * @param settings the settings of the filter.
- * @return result status of the operation.
- * @hide
- */
- public int configure(FilterConfiguration settings) {
- int subType = -1;
- Settings s = settings.getSettings();
- if (s != null) {
- subType = s.getType();
- }
- return nativeConfigureFilter(settings.getType(), subType, settings);
- }
-
- /**
- * Gets the filter Id.
- *
- * @return the hardware resource Id for the filter.
- * @hide
- */
- public int getId() {
- return nativeGetId();
- }
-
- /**
- * Sets the filter's data source.
- *
- * A filter uses demux as data source by default. If the data was packetized
- * by multiple protocols, multiple filters may need to work together to
- * extract all protocols' header. Then a filter's data source can be output
- * from another filter.
- *
- * @param source the filter instance which provides data input. Switch to
- * use demux as data source if the filter instance is NULL.
- * @return result status of the operation.
- * @hide
- */
- public int setDataSource(@Nullable Filter source) {
- return nativeSetDataSource(source);
- }
-
- /**
- * Starts the filter.
- *
- * @return result status of the operation.
- * @hide
- */
- public int start() {
- return nativeStartFilter();
- }
-
-
- /**
- * Stops the filter.
- *
- * @return result status of the operation.
- * @hide
- */
- public int stop() {
- return nativeStopFilter();
- }
-
- /**
- * Flushes the filter.
- *
- * @return result status of the operation.
- * @hide
- */
- public int flush() {
- return nativeFlushFilter();
- }
-
- /** @hide */
- public int read(@NonNull byte[] buffer, int offset, int size) {
- size = Math.min(size, buffer.length - offset);
- return nativeRead(buffer, offset, size);
- }
-
- /**
- * Release the Filter instance.
- *
- * @return result status of the operation.
- * @hide
- */
- public int close() {
- return nativeClose();
- }
+ FilterCallback mCallback;
+ private Filter() {}
}
private Filter openFilter(@FilterType int mainType, @FilterSubtype int subType, int bufferSize,
@@ -587,6 +474,18 @@ public final class Tuner implements AutoCloseable {
return filter;
}
+ /**
+ * Open a time filter instance.
+ *
+ * It is used to open time filter of demux.
+ *
+ * @return a time filter instance.
+ * @hide
+ */
+ public TimeFilter openTimeFilter() {
+ return nativeOpenTimeFilter();
+ }
+
/** @hide */
public class Lnb {
private int mId;
@@ -699,81 +598,11 @@ public final class Tuner implements AutoCloseable {
* <p> Descrambler is a hardware component used to descramble data.
*
* <p> This class controls the TIS interaction with Tuner HAL.
- * TODO: make it static and extends Closable.
+ * TODO: Remove
*/
public class Descrambler {
- private long mNativeContext;
-
- private native int nativeAddPid(int pidType, int pid, Filter filter);
- private native int nativeRemovePid(int pidType, int pid, Filter filter);
- private native int nativeSetKeyToken(byte[] keyToken);
- private native int nativeClose();
-
- private Descrambler() {}
-
- /**
- * Add packets' PID to the descrambler for descrambling.
- *
- * The descrambler will start descrambling packets with this PID. Multiple PIDs can be added
- * into one descrambler instance because descambling can happen simultaneously on packets
- * from different PIDs.
- *
- * If the Descrambler previously contained a filter for the PID, the old filter is replaced
- * by the specified filter.
- *
- * @param pidType the type of the PID.
- * @param pid the PID of packets to start to be descrambled.
- * @param filter an optional filter instance to identify upper stream.
- * @return result status of the operation.
- *
- * @hide
- */
- public int addPid(@DemuxPidType int pidType, int pid, @Nullable Filter filter) {
- return nativeAddPid(pidType, pid, filter);
+ private Descrambler() {
}
-
- /**
- * Remove packets' PID from the descrambler
- *
- * The descrambler will stop descrambling packets with this PID.
- *
- * @param pidType the type of the PID.
- * @param pid the PID of packets to stop to be descrambled.
- * @param filter an optional filter instance to identify upper stream.
- * @return result status of the operation.
- *
- * @hide
- */
- public int removePid(@DemuxPidType int pidType, int pid, @Nullable Filter filter) {
- return nativeRemovePid(pidType, pid, filter);
- }
-
- /**
- * Set a key token to link descrambler to a key slot
- *
- * A descrambler instance can have only one key slot to link, but a key slot can hold a few
- * keys for different purposes.
- *
- * @param keyToken the token to be used to link the key slot.
- * @return result status of the operation.
- *
- * @hide
- */
- public int setKeyToken(byte[] keyToken) {
- return nativeSetKeyToken(keyToken);
- }
-
- /**
- * Release the descrambler instance.
- *
- * @return result status of the operation.
- *
- * @hide
- */
- public int close() {
- return nativeClose();
- }
-
}
/**
@@ -788,137 +617,6 @@ public final class Tuner implements AutoCloseable {
return nativeOpenDescrambler();
}
- // TODO: consider splitting Dvr to Playback and Recording
- /** @hide */
- public class Dvr {
- private long mNativeContext;
- private DvrCallback mCallback;
-
- private native int nativeAttachFilter(Filter filter);
- private native int nativeDetachFilter(Filter filter);
- private native int nativeConfigureDvr(DvrSettings settings);
- private native int nativeStartDvr();
- private native int nativeStopDvr();
- private native int nativeFlushDvr();
- private native int nativeClose();
- private native void nativeSetFileDescriptor(FileDescriptor fd);
- private native int nativeRead(int size);
- private native int nativeRead(byte[] bytes, int offset, int size);
- private native int nativeWrite(int size);
- private native int nativeWrite(byte[] bytes, int offset, int size);
-
- private Dvr() {}
-
- /**
- * Attaches a filter to DVR interface for recording.
- *
- * @param filter the filter to be attached.
- * @return result status of the operation.
- */
- public int attachFilter(Filter filter) {
- return nativeAttachFilter(filter);
- }
-
- /**
- * Detaches a filter from DVR interface.
- *
- * @param filter the filter to be detached.
- * @return result status of the operation.
- */
- public int detachFilter(Filter filter) {
- return nativeDetachFilter(filter);
- }
-
- /**
- * Configures the DVR.
- *
- * @param settings the settings of the DVR interface.
- * @return result status of the operation.
- */
- public int configure(DvrSettings settings) {
- return nativeConfigureDvr(settings);
- }
-
- /**
- * Starts DVR.
- *
- * Starts consuming playback data or producing data for recording.
- *
- * @return result status of the operation.
- */
- public int start() {
- return nativeStartDvr();
- }
-
- /**
- * Stops DVR.
- *
- * Stops consuming playback data or producing data for recording.
- *
- * @return result status of the operation.
- */
- public int stop() {
- return nativeStopDvr();
- }
-
- /**
- * Flushed DVR data.
- *
- * @return result status of the operation.
- */
- public int flush() {
- return nativeFlushDvr();
- }
-
- /**
- * closes the DVR instance to release resources.
- *
- * @return result status of the operation.
- */
- public int close() {
- return nativeClose();
- }
-
- /**
- * Sets file descriptor to read/write data.
- */
- public void setFileDescriptor(FileDescriptor fd) {
- nativeSetFileDescriptor(fd);
- }
-
- /**
- * Reads data from the file for DVR playback.
- */
- public int read(int size) {
- return nativeRead(size);
- }
-
- /**
- * Reads data from the buffer for DVR playback.
- */
- public int read(@NonNull byte[] bytes, int offset, int size) {
- if (size + offset > bytes.length) {
- throw new ArrayIndexOutOfBoundsException(
- "Array length=" + bytes.length + ", offset=" + offset + ", size=" + size);
- }
- return nativeRead(bytes, offset, size);
- }
-
- /**
- * Writes recording data to file.
- */
- public int write(int size) {
- return nativeWrite(size);
- }
-
- /**
- * Writes recording data to buffer.
- */
- public int write(@NonNull byte[] bytes, int offset, int size) {
- return nativeWrite(bytes, offset, size);
- }
- }
-
private Dvr openDvr(int type, int bufferSize) {
Dvr dvr = nativeOpenDvr(type, bufferSize);
return dvr;
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index d24e582a8b21..bbaa5180aece 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -128,21 +128,6 @@ public final class TunerConstants {
public static final int FRONTEND_SETTINGS_ISDBT = 9;
/** @hide */
- @IntDef({FILTER_TYPE_TS, FILTER_TYPE_MMTP, FILTER_TYPE_IP, FILTER_TYPE_TLV, FILTER_TYPE_ALP})
- @Retention(RetentionPolicy.SOURCE)
- public @interface FilterType {}
- /** @hide */
- public static final int FILTER_TYPE_TS = Constants.DemuxFilterMainType.TS;
- /** @hide */
- public static final int FILTER_TYPE_MMTP = Constants.DemuxFilterMainType.MMTP;
- /** @hide */
- public static final int FILTER_TYPE_IP = Constants.DemuxFilterMainType.IP;
- /** @hide */
- public static final int FILTER_TYPE_TLV = Constants.DemuxFilterMainType.TLV;
- /** @hide */
- public static final int FILTER_TYPE_ALP = Constants.DemuxFilterMainType.ALP;
-
- /** @hide */
@IntDef({FILTER_SUBTYPE_UNDEFINED, FILTER_SUBTYPE_SECTION, FILTER_SUBTYPE_PES,
FILTER_SUBTYPE_AUDIO, FILTER_SUBTYPE_VIDEO, FILTER_SUBTYPE_DOWNLOAD,
FILTER_SUBTYPE_RECORD, FILTER_SUBTYPE_TS, FILTER_SUBTYPE_PCR, FILTER_SUBTYPE_TEMI,
@@ -227,41 +212,6 @@ public final class TunerConstants {
/** @hide */
public static final int FRONTEND_SCAN_BLIND = Constants.FrontendScanType.SCAN_BLIND;
- /** @hide */
- @IntDef({SCAN_MESSAGE_TYPE_LOCKED, SCAN_MESSAGE_TYPE_END, SCAN_MESSAGE_TYPE_PROGRESS_PERCENT,
- SCAN_MESSAGE_TYPE_FREQUENCY, SCAN_MESSAGE_TYPE_SYMBOL_RATE, SCAN_MESSAGE_TYPE_PLP_IDS,
- SCAN_MESSAGE_TYPE_GROUP_IDS, SCAN_MESSAGE_TYPE_INPUT_STREAM_IDS,
- SCAN_MESSAGE_TYPE_STANDARD, SCAN_MESSAGE_TYPE_ATSC3_PLP_INFO})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ScanMessageType {}
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_LOCKED = Constants.FrontendScanMessageType.LOCKED;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_END = Constants.FrontendScanMessageType.END;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_PROGRESS_PERCENT =
- Constants.FrontendScanMessageType.PROGRESS_PERCENT;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_FREQUENCY =
- Constants.FrontendScanMessageType.FREQUENCY;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_SYMBOL_RATE =
- Constants.FrontendScanMessageType.SYMBOL_RATE;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_PLP_IDS = Constants.FrontendScanMessageType.PLP_IDS;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_GROUP_IDS =
- Constants.FrontendScanMessageType.GROUP_IDS;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_INPUT_STREAM_IDS =
- Constants.FrontendScanMessageType.INPUT_STREAM_IDS;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_STANDARD =
- Constants.FrontendScanMessageType.STANDARD;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_ATSC3_PLP_INFO =
- Constants.FrontendScanMessageType.ATSC3_PLP_INFO;
-
/** @hide */
@IntDef({FRONTEND_STATUS_TYPE_DEMOD_LOCK, FRONTEND_STATUS_TYPE_SNR, FRONTEND_STATUS_TYPE_BER,
diff --git a/media/java/android/media/tv/tuner/TunerUtils.java b/media/java/android/media/tv/tuner/TunerUtils.java
index a7ccb0288e03..8780b726e3b2 100644
--- a/media/java/android/media/tv/tuner/TunerUtils.java
+++ b/media/java/android/media/tv/tuner/TunerUtils.java
@@ -20,7 +20,8 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerConstants.FilterSubtype;
-import android.media.tv.tuner.TunerConstants.FilterType;
+import android.media.tv.tuner.filter.FilterConfiguration;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
/**
* Utility class for tuner framework.
@@ -50,7 +51,7 @@ public final class TunerUtils {
* @param subtype filter subtype.
*/
public static int getFilterSubtype(@FilterType int mainType, @FilterSubtype int subtype) {
- if (mainType == TunerConstants.FILTER_TYPE_TS) {
+ if (mainType == FilterConfiguration.FILTER_TYPE_TS) {
switch (subtype) {
case TunerConstants.FILTER_SUBTYPE_UNDEFINED:
return Constants.DemuxTsFilterType.UNDEFINED;
@@ -73,7 +74,7 @@ public final class TunerUtils {
default:
break;
}
- } else if (mainType == TunerConstants.FILTER_TYPE_MMTP) {
+ } else if (mainType == FilterConfiguration.FILTER_TYPE_MMTP) {
switch (subtype) {
case TunerConstants.FILTER_SUBTYPE_UNDEFINED:
return Constants.DemuxMmtpFilterType.UNDEFINED;
@@ -95,7 +96,7 @@ public final class TunerUtils {
break;
}
- } else if (mainType == TunerConstants.FILTER_TYPE_IP) {
+ } else if (mainType == FilterConfiguration.FILTER_TYPE_IP) {
switch (subtype) {
case TunerConstants.FILTER_SUBTYPE_UNDEFINED:
return Constants.DemuxIpFilterType.UNDEFINED;
@@ -112,7 +113,7 @@ public final class TunerUtils {
default:
break;
}
- } else if (mainType == TunerConstants.FILTER_TYPE_TLV) {
+ } else if (mainType == FilterConfiguration.FILTER_TYPE_TLV) {
switch (subtype) {
case TunerConstants.FILTER_SUBTYPE_UNDEFINED:
return Constants.DemuxTlvFilterType.UNDEFINED;
@@ -125,7 +126,7 @@ public final class TunerUtils {
default:
break;
}
- } else if (mainType == TunerConstants.FILTER_TYPE_ALP) {
+ } else if (mainType == FilterConfiguration.FILTER_TYPE_ALP) {
switch (subtype) {
case TunerConstants.FILTER_SUBTYPE_UNDEFINED:
return Constants.DemuxAlpFilterType.UNDEFINED;
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
new file mode 100644
index 000000000000..f0fe533093ba
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+/**
+ * Filter configuration for a ALP filter.
+ * @hide
+ */
+public class AlpFilterConfiguration extends FilterConfiguration {
+ private int mPacketType;
+ private int mLengthType;
+
+ public AlpFilterConfiguration(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return FilterConfiguration.FILTER_TYPE_ALP;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java
new file mode 100644
index 000000000000..a7c49d5585f8
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/AvSettings.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerUtils;
+
+/**
+ * Filter Settings for a Video and Audio.
+ * @hide
+ */
+public class AvSettings extends Settings {
+ private boolean mIsPassthrough;
+
+ private AvSettings(int mainType, boolean isAudio) {
+ super(TunerUtils.getFilterSubtype(
+ mainType,
+ isAudio
+ ? TunerConstants.FILTER_SUBTYPE_AUDIO
+ : TunerConstants.FILTER_SUBTYPE_VIDEO));
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/DownloadSettings.java b/media/java/android/media/tv/tuner/filter/DownloadSettings.java
new file mode 100644
index 000000000000..0742b1166ede
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/DownloadSettings.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerUtils;
+
+/**
+ * Filter Settings for a Download.
+ * @hide
+ */
+public class DownloadSettings extends Settings {
+ private int mDownloadId;
+
+ public DownloadSettings(int mainType) {
+ super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_DOWNLOAD));
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
new file mode 100644
index 000000000000..99b10cde34f9
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.hardware.tv.tuner.V1_0.Constants;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Filter configuration used to configure filters.
+ *
+ * @hide
+ */
+public abstract class FilterConfiguration {
+
+ /** @hide */
+ @IntDef({FILTER_TYPE_TS, FILTER_TYPE_MMTP, FILTER_TYPE_IP, FILTER_TYPE_TLV, FILTER_TYPE_ALP})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FilterType {}
+
+ /**
+ * TS filter type.
+ */
+ public static final int FILTER_TYPE_TS = Constants.DemuxFilterMainType.TS;
+ /**
+ * MMTP filter type.
+ */
+ public static final int FILTER_TYPE_MMTP = Constants.DemuxFilterMainType.MMTP;
+ /**
+ * IP filter type.
+ */
+ public static final int FILTER_TYPE_IP = Constants.DemuxFilterMainType.IP;
+ /**
+ * TLV filter type.
+ */
+ public static final int FILTER_TYPE_TLV = Constants.DemuxFilterMainType.TLV;
+ /**
+ * ALP filter type.
+ */
+ public static final int FILTER_TYPE_ALP = Constants.DemuxFilterMainType.ALP;
+
+ @Nullable
+ private final Settings mSettings;
+
+ /* package */ FilterConfiguration(Settings settings) {
+ mSettings = settings;
+ }
+
+ /**
+ * Gets filter configuration type.
+ * @hide
+ */
+ @FilterType
+ public abstract int getType();
+
+ /** @hide */
+ @Nullable
+ public Settings getSettings() {
+ return mSettings;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
new file mode 100644
index 000000000000..c89636887628
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+/**
+ * Filter configuration for a IP filter.
+ * @hide
+ */
+public class IpFilterConfiguration extends FilterConfiguration {
+ private byte[] mSrcIpAddress;
+ private byte[] mDstIpAddress;
+ private int mSrcPort;
+ private int mDstPort;
+ private boolean mPassthrough;
+
+ public IpFilterConfiguration(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return FilterConfiguration.FILTER_TYPE_IP;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
new file mode 100644
index 000000000000..9045ce67a61f
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+/**
+ * Filter configuration for a MMTP filter.
+ * @hide
+ */
+public class MmtpFilterConfiguration extends FilterConfiguration {
+ private int mMmtpPid;
+
+ public MmtpFilterConfiguration(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return FilterConfiguration.FILTER_TYPE_MMTP;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/PesSettings.java b/media/java/android/media/tv/tuner/filter/PesSettings.java
new file mode 100644
index 000000000000..f38abf12e120
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/PesSettings.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+import android.annotation.NonNull;
+import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
+
+/**
+ * Filter Settings for a PES Data.
+ *
+ * @hide
+ */
+public class PesSettings extends Settings {
+ private final int mStreamId;
+ private final boolean mIsRaw;
+
+ private PesSettings(@FilterType int mainType, int streamId, boolean isRaw) {
+ super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_PES));
+ mStreamId = streamId;
+ mIsRaw = isRaw;
+ }
+
+ /**
+ * Creates a builder for {@link PesSettings}.
+ *
+ * @param mainType the filter main type of the settings.
+ */
+ @NonNull
+ public static Builder newBuilder(@FilterType int mainType) {
+ return new Builder(mainType);
+ }
+
+ /**
+ * Builder for {@link PesSettings}.
+ */
+ public static class Builder {
+ private final int mMainType;
+ private int mStreamId;
+ private boolean mIsRaw;
+
+ private Builder(int mainType) {
+ mMainType = mainType;
+ }
+
+ /**
+ * Sets stream ID.
+ *
+ * @param streamId the stream ID.
+ */
+ @NonNull
+ public Builder setStreamId(int streamId) {
+ mStreamId = streamId;
+ return this;
+ }
+
+ /**
+ * Sets whether it's raw.
+ *
+ * @param isRaw {@code true} if the data is raw. Filter sends onFilterStatus callback
+ * instead of onFilterEvent for raw data. {@code false} otherwise.
+ */
+ @NonNull
+ public Builder setIsRaw(boolean isRaw) {
+ mIsRaw = isRaw;
+ return this;
+ }
+
+ /**
+ * Builds a {@link PesSettings} object.
+ */
+ @NonNull
+ public PesSettings build() {
+ return new PesSettings(mMainType, mStreamId, mIsRaw);
+ }
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
new file mode 100644
index 000000000000..701868afc789
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerUtils;
+
+/**
+ * The Settings for the record in DVR.
+ * @hide
+ */
+public class RecordSettings extends Settings {
+ private int mIndexType;
+ private int mIndexMask;
+
+ public RecordSettings(int mainType) {
+ super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_RECORD));
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettings.java b/media/java/android/media/tv/tuner/filter/SectionSettings.java
new file mode 100644
index 000000000000..36e3d7cfee43
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/SectionSettings.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerUtils;
+
+/**
+ * Filter Settings for Section data according to ISO/IEC 13818-1.
+ * @hide
+ */
+public class SectionSettings extends Settings {
+
+ SectionSettings(int mainType) {
+ super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_SECTION));
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
new file mode 100644
index 000000000000..414ea6790bf5
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+import java.util.List;
+
+/**
+ * Bits Settings for Section Filter.
+ * @hide
+ */
+public class SectionSettingsWithSectionBits extends SectionSettings {
+ private List<Byte> mFilter;
+ private List<Byte> mMask;
+ private List<Byte> mMode;
+
+ private SectionSettingsWithSectionBits(int mainType) {
+ super(mainType);
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
new file mode 100644
index 000000000000..0df1d7308e60
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+/**
+ * Table information for Section Filter.
+ * @hide
+ */
+public class SectionSettingsWithTableInfo extends SectionSettings {
+ private int mTableId;
+ private int mVersion;
+
+ private SectionSettingsWithTableInfo(int mainType) {
+ super(mainType);
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/Settings.java b/media/java/android/media/tv/tuner/filter/Settings.java
new file mode 100644
index 000000000000..146aca74ce0e
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/Settings.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+/**
+ * Settings for filters of different subtypes.
+ *
+ * @hide
+ */
+public abstract class Settings {
+ private final int mType;
+
+ /* package */ Settings(int type) {
+ mType = type;
+ }
+
+ /**
+ * Gets filter settings type.
+ *
+ * @hide
+ */
+ public int getType() {
+ return mType;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
new file mode 100644
index 000000000000..de8ee754a28c
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+/**
+ * Filter configuration for a TLV filter.
+ * @hide
+ */
+public class TlvFilterConfiguration extends FilterConfiguration {
+ private int mPacketType;
+ private boolean mIsCompressedIpPacket;
+ private boolean mPassthrough;
+
+ public TlvFilterConfiguration(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return FilterConfiguration.FILTER_TYPE_TLV;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
new file mode 100644
index 000000000000..d0241b6aba09
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 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.media.tv.tuner.filter;
+
+import android.annotation.NonNull;
+
+/**
+ * Filter configuration for a TS filter.
+ *
+ * @hide
+ */
+public class TsFilterConfiguration extends FilterConfiguration {
+ private final int mTpid;
+
+ private TsFilterConfiguration(Settings settings, int tpid) {
+ super(settings);
+ mTpid = tpid;
+ }
+
+ @Override
+ public int getType() {
+ return FilterConfiguration.FILTER_TYPE_TS;
+ }
+
+ /**
+ * Creates a builder for {@link TsFilterConfiguration}.
+ */
+ @NonNull
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder for {@link TsFilterConfiguration}.
+ */
+ public static class Builder {
+ private Settings mSettings;
+ private int mTpid;
+
+ /**
+ * Sets filter settings.
+ *
+ * @param settings the filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@NonNull Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
+ * Sets Tag Protocol ID.
+ *
+ * @param tpid the Tag Protocol ID.
+ */
+ @NonNull
+ public Builder setTpid(int tpid) {
+ mTpid = tpid;
+ return this;
+ }
+
+ /**
+ * Builds a {@link TsFilterConfiguration} object.
+ */
+ @NonNull
+ public TsFilterConfiguration build() {
+ return new TsFilterConfiguration(mSettings, mTpid);
+ }
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java
new file mode 100644
index 000000000000..2962e98790e5
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 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.media.tv.tuner.frontend;
+
+/**
+ * Analog Capabilities.
+ * @hide
+ */
+public class AnalogFrontendCapabilities extends FrontendCapabilities {
+ private final int mTypeCap;
+ private final int mSifStandardCap;
+
+ AnalogFrontendCapabilities(int typeCap, int sifStandardCap) {
+ mTypeCap = typeCap;
+ mSifStandardCap = sifStandardCap;
+ }
+ /**
+ * Gets type capability.
+ */
+ public int getTypeCapability() {
+ return mTypeCap;
+ }
+ /** Gets SIF standard capability. */
+ public int getSifStandardCapability() {
+ return mSifStandardCap;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java
new file mode 100644
index 000000000000..677f9387c6d2
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 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.media.tv.tuner.frontend;
+
+/**
+ * ATSC-3 Capabilities.
+ * @hide
+ */
+public class Atsc3FrontendCapabilities extends FrontendCapabilities {
+ private final int mBandwidthCap;
+ private final int mModulationCap;
+ private final int mTimeInterleaveModeCap;
+ private final int mCodeRateCap;
+ private final int mFecCap;
+ private final int mDemodOutputFormatCap;
+
+ Atsc3FrontendCapabilities(int bandwidthCap, int modulationCap, int timeInterleaveModeCap,
+ int codeRateCap, int fecCap, int demodOutputFormatCap) {
+ mBandwidthCap = bandwidthCap;
+ mModulationCap = modulationCap;
+ mTimeInterleaveModeCap = timeInterleaveModeCap;
+ mCodeRateCap = codeRateCap;
+ mFecCap = fecCap;
+ mDemodOutputFormatCap = demodOutputFormatCap;
+ }
+
+ /** Gets bandwidth capability. */
+ public int getBandwidthCapability() {
+ return mBandwidthCap;
+ }
+ /** Gets modulation capability. */
+ public int getModulationCapability() {
+ return mModulationCap;
+ }
+ /** Gets time interleave mod capability. */
+ public int getTimeInterleaveModeCapability() {
+ return mTimeInterleaveModeCap;
+ }
+ /** Gets code rate capability. */
+ public int getCodeRateCapability() {
+ return mCodeRateCap;
+ }
+ /** Gets FEC capability. */
+ public int getFecCapability() {
+ return mFecCap;
+ }
+ /** Gets demodulator output format capability. */
+ public int getDemodOutputFormatCapability() {
+ return mDemodOutputFormatCap;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java
new file mode 100644
index 000000000000..6ae3c632f5db
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 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.media.tv.tuner.frontend;
+
+/**
+ * ATSC Capabilities.
+ * @hide
+ */
+public class AtscFrontendCapabilities extends FrontendCapabilities {
+ private final int mModulationCap;
+
+ AtscFrontendCapabilities(int modulationCap) {
+ mModulationCap = modulationCap;
+ }
+ /** Gets modulation capability. */
+ public int getModulationCapability() {
+ return mModulationCap;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
new file mode 100644
index 000000000000..edea7af06774
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 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.media.tv.tuner.frontend;
+
+/**
+ * DVBC Capabilities.
+ * @hide
+ */
+public class DvbcFrontendCapabilities extends FrontendCapabilities {
+ private final int mModulationCap;
+ private final int mFecCap;
+ private final int mAnnexCap;
+
+ DvbcFrontendCapabilities(int modulationCap, int fecCap, int annexCap) {
+ mModulationCap = modulationCap;
+ mFecCap = fecCap;
+ mAnnexCap = annexCap;
+ }
+
+ /** Gets modulation capability. */
+ public int getModulationCapability() {
+ return mModulationCap;
+ }
+ /** Gets FEC capability. */
+ public int getFecCapability() {
+ return mFecCap;
+ }
+ /** Gets annex capability. */
+ public int getAnnexCapability() {
+ return mAnnexCap;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java
new file mode 100644
index 000000000000..f5a41574cd04
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 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.media.tv.tuner.frontend;
+
+/**
+ * DVBS Capabilities.
+ * @hide
+ */
+public class DvbsFrontendCapabilities extends FrontendCapabilities {
+ private final int mModulationCap;
+ private final long mInnerFecCap;
+ private final int mStandard;
+
+ DvbsFrontendCapabilities(int modulationCap, long innerFecCap, int standard) {
+ mModulationCap = modulationCap;
+ mInnerFecCap = innerFecCap;
+ mStandard = standard;
+ }
+
+ /** Gets modulation capability. */
+ public int getModulationCapability() {
+ return mModulationCap;
+ }
+ /** Gets inner FEC capability. */
+ public long getInnerFecCapability() {
+ return mInnerFecCap;
+ }
+ /** Gets DVBS standard capability. */
+ public int getStandardCapability() {
+ return mStandard;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java
new file mode 100644
index 000000000000..e9c16ddd4dc8
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 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.media.tv.tuner.frontend;
+
+/**
+ * DVBT Capabilities.
+ * @hide
+ */
+public class DvbtFrontendCapabilities extends FrontendCapabilities {
+ private final int mTransmissionModeCap;
+ private final int mBandwidthCap;
+ private final int mConstellationCap;
+ private final int mCoderateCap;
+ private final int mHierarchyCap;
+ private final int mGuardIntervalCap;
+ private final boolean mIsT2Supported;
+ private final boolean mIsMisoSupported;
+
+ DvbtFrontendCapabilities(int transmissionModeCap, int bandwidthCap, int constellationCap,
+ int coderateCap, int hierarchyCap, int guardIntervalCap, boolean isT2Supported,
+ boolean isMisoSupported) {
+ mTransmissionModeCap = transmissionModeCap;
+ mBandwidthCap = bandwidthCap;
+ mConstellationCap = constellationCap;
+ mCoderateCap = coderateCap;
+ mHierarchyCap = hierarchyCap;
+ mGuardIntervalCap = guardIntervalCap;
+ mIsT2Supported = isT2Supported;
+ mIsMisoSupported = isMisoSupported;
+ }
+
+ /** Gets transmission mode capability. */
+ public int getTransmissionModeCapability() {
+ return mTransmissionModeCap;
+ }
+ /** Gets bandwidth capability. */
+ public int getBandwidthCapability() {
+ return mBandwidthCap;
+ }
+ /** Gets constellation capability. */
+ public int getConstellationCapability() {
+ return mConstellationCap;
+ }
+ /** Gets code rate capability. */
+ public int getCodeRateCapability() {
+ return mCoderateCap;
+ }
+ /** Gets hierarchy capability. */
+ public int getHierarchyCapability() {
+ return mHierarchyCap;
+ }
+ /** Gets guard interval capability. */
+ public int getGuardIntervalCapability() {
+ return mGuardIntervalCap;
+ }
+ /** Returns whether T2 is supported. */
+ public boolean getIsT2Supported() {
+ return mIsT2Supported;
+ }
+ /** Returns whether MISO is supported. */
+ public boolean getIsMisoSupported() {
+ return mIsMisoSupported;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendCallback.java b/media/java/android/media/tv/tuner/frontend/FrontendCallback.java
index 91776e17dc21..0992eb665330 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendCallback.java
@@ -16,8 +16,6 @@
package android.media.tv.tuner.frontend;
-import android.media.tv.tuner.ScanMessage;
-
/**
* Frontend Callback.
*
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java
new file mode 100644
index 000000000000..7350bc0c3914
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 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.media.tv.tuner.frontend;
+
+/**
+ * Frontend Capabilities.
+ * @hide
+ */
+public abstract class FrontendCapabilities {
+}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
index ef6c029fe626..5d03570eea80 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
@@ -16,7 +16,6 @@
package android.media.tv.tuner.frontend;
-import android.media.tv.tuner.FrontendCapabilities;
import android.media.tv.tuner.TunerConstants.FrontendType;
/**
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbcFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/IsdbcFrontendCapabilities.java
new file mode 100644
index 000000000000..6544b17609c2
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/IsdbcFrontendCapabilities.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 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.media.tv.tuner.frontend;
+
+/**
+ * ISDBC Capabilities.
+ * @hide
+ */
+public class IsdbcFrontendCapabilities extends FrontendCapabilities {
+ private final int mModeCap;
+ private final int mBandwidthCap;
+ private final int mModulationCap;
+ private final int mCoderateCap;
+ private final int mGuardIntervalCap;
+
+ IsdbcFrontendCapabilities(int modeCap, int bandwidthCap, int modulationCap, int coderateCap,
+ int guardIntervalCap) {
+ mModeCap = modeCap;
+ mBandwidthCap = bandwidthCap;
+ mModulationCap = modulationCap;
+ mCoderateCap = coderateCap;
+ mGuardIntervalCap = guardIntervalCap;
+ }
+
+ /** Gets mode capability. */
+ public int getModeCapability() {
+ return mModeCap;
+ }
+ /** Gets bandwidth capability. */
+ public int getBandwidthCapability() {
+ return mBandwidthCap;
+ }
+ /** Gets modulation capability. */
+ public int getModulationCapability() {
+ return mModulationCap;
+ }
+ /** Gets code rate capability. */
+ public int getCodeRateCapability() {
+ return mCoderateCap;
+ }
+ /** Gets guard interval capability. */
+ public int getGuardIntervalCapability() {
+ return mGuardIntervalCap;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java
new file mode 100644
index 000000000000..92832b7fcbdd
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 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.media.tv.tuner.frontend;
+
+/**
+ * ISDBS-3 Capabilities.
+ * @hide
+ */
+public class Isdbs3FrontendCapabilities extends FrontendCapabilities {
+ private final int mModulationCap;
+ private final int mCoderateCap;
+
+ Isdbs3FrontendCapabilities(int modulationCap, int coderateCap) {
+ mModulationCap = modulationCap;
+ mCoderateCap = coderateCap;
+ }
+
+ /** Gets modulation capability. */
+ public int getModulationCapability() {
+ return mModulationCap;
+ }
+ /** Gets code rate capability. */
+ public int getCodeRateCapability() {
+ return mCoderateCap;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java
new file mode 100644
index 000000000000..b930b2578092
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 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.media.tv.tuner.frontend;
+
+/**
+ * ISDBS Capabilities.
+ * @hide
+ */
+public class IsdbsFrontendCapabilities extends FrontendCapabilities {
+ private final int mModulationCap;
+ private final int mCoderateCap;
+
+ IsdbsFrontendCapabilities(int modulationCap, int coderateCap) {
+ mModulationCap = modulationCap;
+ mCoderateCap = coderateCap;
+ }
+
+ /** Gets modulation capability. */
+ public int getModulationCapability() {
+ return mModulationCap;
+ }
+ /** Gets code rate capability. */
+ public int getCodeRateCapability() {
+ return mCoderateCap;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/ScanMessage.java b/media/java/android/media/tv/tuner/frontend/ScanMessage.java
index 35f54f8447c0..dd687dd2959c 100644
--- a/media/java/android/media/tv/tuner/ScanMessage.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanMessage.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * 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.
@@ -14,9 +14,13 @@
* limitations under the License.
*/
-package android.media.tv.tuner;
+package android.media.tv.tuner.frontend;
-import android.media.tv.tuner.TunerConstants.ScanMessageType;
+import android.annotation.IntDef;
+import android.hardware.tv.tuner.V1_0.Constants;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Message from frontend during scan operations.
@@ -24,6 +28,43 @@ import android.media.tv.tuner.TunerConstants.ScanMessageType;
* @hide
*/
public class ScanMessage {
+
+ /** @hide */
+ @IntDef({
+ LOCKED,
+ END,
+ PROGRESS_PERCENT,
+ FREQUENCY,
+ SYMBOL_RATE,
+ PLP_IDS,
+ GROUP_IDS,
+ INPUT_STREAM_IDS,
+ STANDARD,
+ ATSC3_PLP_INFO
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+ /** @hide */
+ public static final int LOCKED = Constants.FrontendScanMessageType.LOCKED;
+ /** @hide */
+ public static final int END = Constants.FrontendScanMessageType.END;
+ /** @hide */
+ public static final int PROGRESS_PERCENT = Constants.FrontendScanMessageType.PROGRESS_PERCENT;
+ /** @hide */
+ public static final int FREQUENCY = Constants.FrontendScanMessageType.FREQUENCY;
+ /** @hide */
+ public static final int SYMBOL_RATE = Constants.FrontendScanMessageType.SYMBOL_RATE;
+ /** @hide */
+ public static final int PLP_IDS = Constants.FrontendScanMessageType.PLP_IDS;
+ /** @hide */
+ public static final int GROUP_IDS = Constants.FrontendScanMessageType.GROUP_IDS;
+ /** @hide */
+ public static final int INPUT_STREAM_IDS = Constants.FrontendScanMessageType.INPUT_STREAM_IDS;
+ /** @hide */
+ public static final int STANDARD = Constants.FrontendScanMessageType.STANDARD;
+ /** @hide */
+ public static final int ATSC3_PLP_INFO = Constants.FrontendScanMessageType.ATSC3_PLP_INFO;
+
private final int mType;
private final Object mValue;
@@ -33,69 +74,69 @@ public class ScanMessage {
}
/** Gets scan message type. */
- @ScanMessageType
+ @Type
public int getMessageType() {
return mType;
}
/** Message indicates whether frontend is locked or not. */
public boolean getIsLocked() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_LOCKED) {
+ if (mType != LOCKED) {
throw new IllegalStateException();
}
return (Boolean) mValue;
}
/** Message indicates whether the scan has reached the end or not. */
public boolean getIsEnd() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_END) {
+ if (mType != END) {
throw new IllegalStateException();
}
return (Boolean) mValue;
}
/** Progress message in percent. */
public int getProgressPercent() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_PROGRESS_PERCENT) {
+ if (mType != PROGRESS_PERCENT) {
throw new IllegalStateException();
}
return (Integer) mValue;
}
/** Gets frequency. */
public int getFrequency() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_FREQUENCY) {
+ if (mType != FREQUENCY) {
throw new IllegalStateException();
}
return (Integer) mValue;
}
/** Gets symbol rate. */
public int getSymbolRate() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_SYMBOL_RATE) {
+ if (mType != SYMBOL_RATE) {
throw new IllegalStateException();
}
return (Integer) mValue;
}
/** Gets PLP IDs. */
public int[] getPlpIds() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_PLP_IDS) {
+ if (mType != PLP_IDS) {
throw new IllegalStateException();
}
return (int[]) mValue;
}
/** Gets group IDs. */
public int[] getGroupIds() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_GROUP_IDS) {
+ if (mType != GROUP_IDS) {
throw new IllegalStateException();
}
return (int[]) mValue;
}
/** Gets Input stream IDs. */
public int[] getInputStreamIds() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_INPUT_STREAM_IDS) {
+ if (mType != INPUT_STREAM_IDS) {
throw new IllegalStateException();
}
return (int[]) mValue;
}
/** Gets the DVB-T or DVB-S standard. */
public int getStandard() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_STANDARD) {
+ if (mType != STANDARD) {
throw new IllegalStateException();
}
return (int) mValue;
@@ -103,7 +144,7 @@ public class ScanMessage {
/** Gets PLP information for ATSC3. */
public Atsc3PlpInfo[] getAtsc3PlpInfos() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_ATSC3_PLP_INFO) {
+ if (mType != ATSC3_PLP_INFO) {
throw new IllegalStateException();
}
return (Atsc3PlpInfo[]) mValue;
diff --git a/media/java/android/mtp/MtpPropertyList.java b/media/java/android/mtp/MtpPropertyList.java
index 557f099c25c1..53d838d84518 100644
--- a/media/java/android/mtp/MtpPropertyList.java
+++ b/media/java/android/mtp/MtpPropertyList.java
@@ -16,7 +16,8 @@
package android.mtp;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import java.util.ArrayList;
import java.util.List;
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index c7dbca61f90a..ba752633718c 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -16,9 +16,8 @@
package android.mtp;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.storage.StorageVolume;
-import android.provider.MediaStore;
/**
* This class represents a storage unit on an MTP device.
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 86a1076af122..06adf30a8303 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -21,8 +21,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.UnsupportedAppUsage;
import android.app.Service;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index ee6761344613..536a061190d7 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -143,6 +143,10 @@ cc_library_shared {
"libutils",
],
+ header_libs: [
+ "libstagefright_foundation_headers",
+ ],
+
export_include_dirs: ["."],
cflags: [
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index f0f368815d9d..4f1125f5e482 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -696,6 +696,10 @@ static jobject android_media_tv_Tuner_open_filter(
return tuner->openFilter(filterType, bufferSize);
}
+static jobject android_media_tv_Tuner_open_time_filter(JNIEnv, jobject) {
+ return NULL;
+}
+
static DemuxFilterSettings getFilterSettings(
JNIEnv *env, int type, int subtype, jobject filterSettingsObj) {
DemuxFilterSettings filterSettings;
@@ -840,6 +844,28 @@ static int android_media_tv_Tuner_close_filter(JNIEnv*, jobject) {
return 0;
}
+// TODO: implement TimeFilter functions
+static int android_media_tv_Tuner_time_filter_set_timestamp(
+ JNIEnv, jobject, jlong) {
+ return 0;
+}
+
+static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv, jobject) {
+ return 0;
+}
+
+static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv, jobject) {
+ return NULL;
+}
+
+static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv, jobject) {
+ return NULL;
+}
+
+static int android_media_tv_Tuner_time_filter_close(JNIEnv, jobject) {
+ return 0;
+}
+
static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->openDescrambler();
@@ -1119,6 +1145,8 @@ static const JNINativeMethod gTunerMethods[] = {
(void *)android_media_tv_Tuner_get_frontend_info },
{ "nativeOpenFilter", "(III)Landroid/media/tv/tuner/Tuner$Filter;",
(void *)android_media_tv_Tuner_open_filter },
+ { "nativeOpenTimeFilter", "()Landroid/media/tv/tuner/Tuner$TimeFilter;",
+ (void *)android_media_tv_Tuner_open_time_filter },
{ "nativeGetLnbIds", "()Ljava/util/List;",
(void *)android_media_tv_Tuner_get_lnb_ids },
{ "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Tuner$Lnb;",
@@ -1144,6 +1172,16 @@ static const JNINativeMethod gFilterMethods[] = {
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_filter },
};
+static const JNINativeMethod gTimeFilterMethods[] = {
+ { "nativeSetTimeStamp", "(J)I", (void *)android_media_tv_Tuner_time_filter_set_timestamp },
+ { "nativeClearTimeStamp", "()I", (void *)android_media_tv_Tuner_time_filter_clear_timestamp },
+ { "nativeGetTimeStamp", "()Ljava/lang/Long;",
+ (void *)android_media_tv_Tuner_time_filter_get_timestamp },
+ { "nativeGetSourceTime", "()Ljava/lang/Long;",
+ (void *)android_media_tv_Tuner_time_filter_get_source_time },
+ { "nativeClose", "()I", (void *)android_media_tv_Tuner_time_filter_close },
+};
+
static const JNINativeMethod gDescramblerMethods[] = {
{ "nativeAddPid", "(IILandroid/media/tv/tuner/Tuner$Filter;)I",
(void *)android_media_tv_Tuner_add_pid },
@@ -1194,6 +1232,13 @@ static bool register_android_media_tv_Tuner(JNIEnv *env) {
return false;
}
if (AndroidRuntime::registerNativeMethods(
+ env, "android/media/tv/tuner/Tuner$TimeFilter",
+ gTimeFilterMethods,
+ NELEM(gTimeFilterMethods)) != JNI_OK) {
+ ALOGE("Failed to register time filter native methods");
+ return false;
+ }
+ if (AndroidRuntime::registerNativeMethods(
env, "android/media/tv/tuner/Tuner$Descrambler",
gDescramblerMethods,
NELEM(gDescramblerMethods)) != JNI_OK) {
diff --git a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
index dfbf5d20e074..121443f56285 100644
--- a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
+++ b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
@@ -17,12 +17,11 @@
package android.media.effect;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.filterfw.core.Filter;
import android.filterfw.core.FilterFactory;
import android.filterfw.core.FilterFunction;
import android.filterfw.core.Frame;
-import android.media.effect.EffectContext;
/**
* Effect subclass for effects based on a single Filter. Subclasses need only invoke the
diff --git a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
index 52615bf09faa..3a7f1ed4f7ec 100644
--- a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
+++ b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
@@ -17,11 +17,11 @@
package android.filterfw;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.filterfw.core.AsyncRunner;
-import android.filterfw.core.FilterGraph;
import android.filterfw.core.FilterContext;
+import android.filterfw.core.FilterGraph;
import android.filterfw.core.FrameManager;
import android.filterfw.core.GraphRunner;
import android.filterfw.core.RoundRobinScheduler;
diff --git a/media/mca/filterfw/java/android/filterfw/core/Filter.java b/media/mca/filterfw/java/android/filterfw/core/Filter.java
index 4f56b923f6ed..a608ef5be3f4 100644
--- a/media/mca/filterfw/java/android/filterfw/core/Filter.java
+++ b/media/mca/filterfw/java/android/filterfw/core/Filter.java
@@ -17,19 +17,15 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.FilterContext;
-import android.filterfw.core.FilterPort;
-import android.filterfw.core.KeyValueMap;
-import android.filterfw.io.TextGraphReader;
-import android.filterfw.io.GraphIOException;
+import android.compat.annotation.UnsupportedAppUsage;
import android.filterfw.format.ObjectFormat;
+import android.filterfw.io.GraphIOException;
+import android.filterfw.io.TextGraphReader;
import android.util.Log;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
-import java.lang.Thread;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java
index a19220ef85f8..6b0a2193dceb 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java
@@ -17,11 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.Filter;
-import android.filterfw.core.Frame;
-import android.filterfw.core.FrameManager;
-import android.filterfw.core.GLEnvironment;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.HashMap;
import java.util.HashSet;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
index e6ca11ffca3c..35a298fd6dfb 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
@@ -17,6 +17,11 @@
package android.filterfw.core;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.filterpacks.base.FrameBranch;
+import android.filterpacks.base.NullFilter;
+import android.util.Log;
+
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -25,14 +30,6 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
-import android.filterfw.core.FilterContext;
-import android.filterfw.core.KeyValueMap;
-import android.filterpacks.base.FrameBranch;
-import android.filterpacks.base.NullFilter;
-
-import android.annotation.UnsupportedAppUsage;
-import android.util.Log;
-
/**
* @hide
*/
diff --git a/media/mca/filterfw/java/android/filterfw/core/Frame.java b/media/mca/filterfw/java/android/filterfw/core/Frame.java
index e880783247a3..c4d935ae4873 100644
--- a/media/mca/filterfw/java/android/filterfw/core/Frame.java
+++ b/media/mca/filterfw/java/android/filterfw/core/Frame.java
@@ -17,9 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.FrameFormat;
-import android.filterfw.core.FrameManager;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Bitmap;
import java.nio.ByteBuffer;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
index eb0ff0a32c3f..a87e9b9ffbcf 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
@@ -17,9 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.KeyValueMap;
-import android.filterfw.core.MutableFrameFormat;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.Arrays;
import java.util.Map.Entry;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java
index 85c8fcd9787d..e49aaf1d6fad 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java
@@ -17,10 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.Frame;
-import android.filterfw.core.FrameFormat;
-import android.filterfw.core.MutableFrameFormat;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
index e25d6a7d70ab..7e4e8a64a81f 100644
--- a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
+++ b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
@@ -17,13 +17,12 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.NativeAllocatorTag;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.SurfaceTexture;
+import android.media.MediaRecorder;
import android.os.Looper;
import android.util.Log;
import android.view.Surface;
-import android.media.MediaRecorder;
/**
* @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java
index 9e3025fafb6e..1ccd7feaa7c3 100644
--- a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java
+++ b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java
@@ -17,15 +17,10 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.Frame;
-import android.filterfw.core.FrameFormat;
-import android.filterfw.core.FrameManager;
-import android.filterfw.core.NativeFrame;
-import android.filterfw.core.StopWatchMap;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Bitmap;
-import android.opengl.GLES20;
import android.graphics.Rect;
+import android.opengl.GLES20;
import java.nio.ByteBuffer;
diff --git a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
index 250cfaaba9d4..b57e8bb7262e 100644
--- a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
+++ b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
@@ -17,7 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java
index ae2ad99899f0..da00b1ffb180 100644
--- a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java
+++ b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java
@@ -17,9 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.FrameFormat;
-import android.filterfw.core.KeyValueMap;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.Arrays;
diff --git a/media/mca/filterfw/java/android/filterfw/core/Program.java b/media/mca/filterfw/java/android/filterfw/core/Program.java
index 376c08554eb2..145388e4437e 100644
--- a/media/mca/filterfw/java/android/filterfw/core/Program.java
+++ b/media/mca/filterfw/java/android/filterfw/core/Program.java
@@ -17,8 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.Frame;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
index f41636e7cf76..e043be0e27bd 100644
--- a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
+++ b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
@@ -17,12 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.Frame;
-import android.filterfw.core.NativeAllocatorTag;
-import android.filterfw.core.Program;
-import android.filterfw.core.StopWatchMap;
-import android.filterfw.core.VertexFrame;
+import android.compat.annotation.UnsupportedAppUsage;
import android.filterfw.geometry.Quad;
import android.opengl.GLES20;
diff --git a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java
index ac087305287f..0e05092d0cdd 100644
--- a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java
+++ b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java
@@ -17,7 +17,7 @@
package android.filterfw.format;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.filterfw.core.FrameFormat;
import android.filterfw.core.MutableFrameFormat;
import android.graphics.Bitmap;
diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Point.java b/media/mca/filterfw/java/android/filterfw/geometry/Point.java
index d7acf12dd1de..96d2d7b08b74 100644
--- a/media/mca/filterfw/java/android/filterfw/geometry/Point.java
+++ b/media/mca/filterfw/java/android/filterfw/geometry/Point.java
@@ -17,8 +17,7 @@
package android.filterfw.geometry;
-import android.annotation.UnsupportedAppUsage;
-import java.lang.Math;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* @hide
diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java
index 610e5b80399d..2b308a91576f 100644
--- a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java
+++ b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java
@@ -17,10 +17,8 @@
package android.filterfw.geometry;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.geometry.Point;
+import android.compat.annotation.UnsupportedAppUsage;
-import java.lang.Float;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index 04fccc7e0f94..8c0273b06e8c 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -46,8 +46,8 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
public static final String ROUTE_ID5_TO_TRANSFER_TO = "route_id5_to_transfer_to";
public static final String ROUTE_NAME5 = "Sample Route 5 - Route to transfer to";
- public static final String ROUTE_ID_SPECIAL_CATEGORY = "route_special_category";
- public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route";
+ public static final String ROUTE_ID_SPECIAL_TYPE = "route_special_type";
+ public static final String ROUTE_NAME_SPECIAL_TYPE = "Special Type Route";
public static final int VOLUME_MAX = 100;
public static final String ROUTE_ID_FIXED_VOLUME = "route_fixed_volume";
@@ -58,49 +58,49 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
public static final String ACTION_REMOVE_ROUTE =
"com.android.mediarouteprovider.action_remove_route";
- public static final String CATEGORY_SAMPLE =
- "com.android.mediarouteprovider.CATEGORY_SAMPLE";
- public static final String CATEGORY_SPECIAL =
- "com.android.mediarouteprovider.CATEGORY_SPECIAL";
+ public static final String TYPE_SAMPLE =
+ "com.android.mediarouteprovider.TYPE_SAMPLE";
+ public static final String TYPE_SPECIAL =
+ "com.android.mediarouteprovider.TYPE_SPECIAL";
Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
- Map<String, Integer> mRouteSessionMap = new HashMap<>();
+ Map<String, String> mRouteSessionMap = new HashMap<>();
private int mNextSessionId = 1000;
private void initializeRoutes() {
MediaRoute2Info route1 = new MediaRoute2Info.Builder(ROUTE_ID1, ROUTE_NAME1)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setDeviceType(DEVICE_TYPE_TV)
.build();
MediaRoute2Info route2 = new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setDeviceType(DEVICE_TYPE_SPEAKER)
.build();
MediaRoute2Info route3 = new MediaRoute2Info.Builder(
ROUTE_ID3_SESSION_CREATION_FAILED, ROUTE_NAME3)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.build();
MediaRoute2Info route4 = new MediaRoute2Info.Builder(
ROUTE_ID4_TO_SELECT_AND_DESELECT, ROUTE_NAME4)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.build();
MediaRoute2Info route5 = new MediaRoute2Info.Builder(
ROUTE_ID5_TO_TRANSFER_TO, ROUTE_NAME5)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.build();
MediaRoute2Info routeSpecial =
- new MediaRoute2Info.Builder(ROUTE_ID_SPECIAL_CATEGORY, ROUTE_NAME_SPECIAL_CATEGORY)
- .addSupportedCategory(CATEGORY_SAMPLE)
- .addSupportedCategory(CATEGORY_SPECIAL)
+ new MediaRoute2Info.Builder(ROUTE_ID_SPECIAL_TYPE, ROUTE_NAME_SPECIAL_TYPE)
+ .addRouteType(TYPE_SAMPLE)
+ .addRouteType(TYPE_SPECIAL)
.build();
MediaRoute2Info fixedVolumeRoute =
new MediaRoute2Info.Builder(ROUTE_ID_FIXED_VOLUME, ROUTE_NAME_FIXED_VOLUME)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_FIXED)
.build();
MediaRoute2Info variableVolumeRoute =
new MediaRoute2Info.Builder(ROUTE_ID_VARIABLE_VOLUME, ROUTE_NAME_VARIABLE_VOLUME)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(VOLUME_MAX)
.build();
@@ -167,7 +167,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onCreateSession(String packageName, String routeId, String controlCategory,
+ public void onCreateSession(String packageName, String routeId, String routeType,
long requestId) {
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
@@ -177,7 +177,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
maybeDeselectRoute(routeId);
- final int sessionId = mNextSessionId;
+ final String sessionId = String.valueOf(mNextSessionId);
mNextSessionId++;
mRoutes.put(routeId, new MediaRoute2Info.Builder(route)
@@ -186,7 +186,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
mRouteSessionMap.put(routeId, sessionId);
RouteSessionInfo sessionInfo = new RouteSessionInfo.Builder(
- sessionId, packageName, controlCategory)
+ sessionId, packageName, routeType)
.addSelectedRoute(routeId)
.addSelectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
.addTransferrableRoute(ROUTE_ID5_TO_TRANSFER_TO)
@@ -196,7 +196,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onDestroySession(int sessionId, RouteSessionInfo lastSessionInfo) {
+ public void onDestroySession(String sessionId, RouteSessionInfo lastSessionInfo) {
for (String routeId : lastSessionInfo.getSelectedRoutes()) {
mRouteSessionMap.remove(routeId);
MediaRoute2Info route = mRoutes.get(routeId);
@@ -209,7 +209,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onSelectRoute(int sessionId, String routeId) {
+ public void onSelectRoute(String sessionId, String routeId) {
RouteSessionInfo sessionInfo = getSessionInfo(sessionId);
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null || sessionInfo == null) {
@@ -218,7 +218,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
maybeDeselectRoute(routeId);
mRoutes.put(routeId, new MediaRoute2Info.Builder(route)
- .setClientPackageName(sessionInfo.getPackageName())
+ .setClientPackageName(sessionInfo.getClientPackageName())
.build());
mRouteSessionMap.put(routeId, sessionId);
@@ -232,7 +232,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onDeselectRoute(int sessionId, String routeId) {
+ public void onDeselectRoute(String sessionId, String routeId) {
RouteSessionInfo sessionInfo = getSessionInfo(sessionId);
MediaRoute2Info route = mRoutes.get(routeId);
@@ -254,7 +254,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onTransferToRoute(int sessionId, String routeId) {
+ public void onTransferToRoute(String sessionId, String routeId) {
RouteSessionInfo sessionInfo = getSessionInfo(sessionId);
RouteSessionInfo newSessionInfo = new RouteSessionInfo.Builder(sessionInfo)
.clearSelectedRoutes()
@@ -271,7 +271,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
return;
}
- int sessionId = mRouteSessionMap.get(routeId);
+ String sessionId = mRouteSessionMap.get(routeId);
onDeselectRoute(sessionId, routeId);
}
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
index 6fe847bf5f3a..ce4bb8ef2688 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
@@ -23,18 +23,18 @@ import static android.media.MediaRoute2Info.DEVICE_TYPE_TV;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
-import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORIES_ALL;
-import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORIES_SPECIAL;
-import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORY_SAMPLE;
-import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORY_SPECIAL;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID1;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID2;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID3_SESSION_CREATION_FAILED;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID4_TO_SELECT_AND_DESELECT;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID5_TO_TRANSFER_TO;
-import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_SPECIAL_CATEGORY;
+import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_SPECIAL_TYPE;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_VARIABLE_VOLUME;
import static com.android.mediaroutertest.MediaRouterManagerTest.SYSTEM_PROVIDER_ID;
+import static com.android.mediaroutertest.MediaRouterManagerTest.TYPES_ALL;
+import static com.android.mediaroutertest.MediaRouterManagerTest.TYPES_SPECIAL;
+import static com.android.mediaroutertest.MediaRouterManagerTest.TYPE_SAMPLE;
+import static com.android.mediaroutertest.MediaRouterManagerTest.TYPE_SPECIAL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -50,6 +50,7 @@ import android.media.MediaRouter2;
import android.media.MediaRouter2.RouteCallback;
import android.media.MediaRouter2.RouteSessionController;
import android.media.MediaRouter2.SessionCallback;
+import android.media.RouteDiscoveryRequest;
import android.media.RouteSessionInfo;
import android.net.Uri;
import android.os.Parcel;
@@ -95,14 +96,14 @@ public class MediaRouter2Test {
}
/**
- * Tests if we get proper routes for application that has special control category.
+ * Tests if we get proper routes for application that has special route type.
*/
@Test
public void testGetRoutes() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(TYPES_SPECIAL);
assertEquals(1, routes.size());
- assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
+ assertNotNull(routes.get(ROUTE_ID_SPECIAL_TYPE));
}
@Test
@@ -114,7 +115,7 @@ public class MediaRouter2Test {
.setIconUri(new Uri.Builder().path("icon").build())
.setVolume(5)
.setVolumeMax(20)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setVolumeHandling(PLAYBACK_VOLUME_VARIABLE)
.setDeviceType(DEVICE_TYPE_SPEAKER)
.build();
@@ -137,7 +138,7 @@ public class MediaRouter2Test {
.setClientPackageName("com.android.mediaroutertest")
.setConnectionState(CONNECTION_STATE_CONNECTING)
.setIconUri(new Uri.Builder().path("icon").build())
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setVolume(5)
.setVolumeMax(20)
.setVolumeHandling(PLAYBACK_VOLUME_VARIABLE)
@@ -168,9 +169,9 @@ public class MediaRouter2Test {
.setClientPackageName("another.client.package").build();
assertNotEquals(route, routeClient);
- MediaRoute2Info routeCategory = new MediaRoute2Info.Builder(route)
- .addSupportedCategory(CATEGORY_SPECIAL).build();
- assertNotEquals(route, routeCategory);
+ MediaRoute2Info routeType = new MediaRoute2Info.Builder(route)
+ .addRouteType(TYPE_SPECIAL).build();
+ assertNotEquals(route, routeType);
MediaRoute2Info routeVolume = new MediaRoute2Info.Builder(route)
.setVolume(10).build();
@@ -191,7 +192,7 @@ public class MediaRouter2Test {
@Test
public void testControlVolumeWithRouter() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(TYPES_ALL);
MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
assertNotNull(volRoute);
@@ -202,12 +203,14 @@ public class MediaRouter2Test {
awaitOnRouteChanged(
() -> mRouter2.requestUpdateVolume(volRoute, deltaVolume),
ROUTE_ID_VARIABLE_VOLUME,
- (route -> route.getVolume() == originalVolume + deltaVolume));
+ (route -> route.getVolume() == originalVolume + deltaVolume),
+ TYPES_ALL);
awaitOnRouteChanged(
() -> mRouter2.requestSetVolume(volRoute, originalVolume),
ROUTE_ID_VARIABLE_VOLUME,
- (route -> route.getVolume() == originalVolume));
+ (route -> route.getVolume() == originalVolume),
+ TYPES_ALL);
}
@Test
@@ -234,13 +237,13 @@ public class MediaRouter2Test {
@Test
public void testRequestCreateSessionWithInvalidArguments() {
MediaRoute2Info route = new MediaRoute2Info.Builder("id", "name").build();
- String controlCategory = "controlCategory";
+ String routeType = "routeType";
// Tests null route
assertThrows(NullPointerException.class,
- () -> mRouter2.requestCreateSession(null, controlCategory));
+ () -> mRouter2.requestCreateSession(null, routeType));
- // Tests null or empty control category
+ // Tests null or empty route type
assertThrows(IllegalArgumentException.class,
() -> mRouter2.requestCreateSession(route, null));
assertThrows(IllegalArgumentException.class,
@@ -249,10 +252,10 @@ public class MediaRouter2Test {
@Test
public void testRequestCreateSessionSuccess() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info route = routes.get(ROUTE_ID1);
assertNotNull(route);
@@ -266,25 +269,25 @@ public class MediaRouter2Test {
public void onSessionCreated(RouteSessionController controller) {
assertNotNull(controller);
assertTrue(createRouteMap(controller.getSelectedRoutes()).containsKey(ROUTE_ID1));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType()));
controllers.add(controller);
successLatch.countDown();
}
@Override
public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedControlCategory) {
+ String requestedRouteType) {
failureLatch.countDown();
}
};
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(route, TYPE_SAMPLE);
assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
// onSessionCreationFailed should not be called.
@@ -298,10 +301,10 @@ public class MediaRouter2Test {
@Test
public void testRequestCreateSessionFailure() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info route = routes.get(ROUTE_ID3_SESSION_CREATION_FAILED);
assertNotNull(route);
@@ -319,20 +322,20 @@ public class MediaRouter2Test {
@Override
public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedControlCategory) {
+ String requestedRouteType) {
assertEquals(route, requestedRoute);
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, requestedControlCategory));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, requestedRouteType));
failureLatch.countDown();
}
};
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(route, TYPE_SAMPLE);
assertTrue(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
// onSessionCreated should not be called.
@@ -346,8 +349,8 @@ public class MediaRouter2Test {
@Test
public void testRequestCreateSessionMultipleSessions() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
final CountDownLatch successLatch = new CountDownLatch(2);
final CountDownLatch failureLatch = new CountDownLatch(1);
@@ -363,12 +366,12 @@ public class MediaRouter2Test {
@Override
public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedControlCategory) {
+ String requestedRouteType) {
failureLatch.countDown();
}
};
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info route1 = routes.get(ROUTE_ID1);
MediaRoute2Info route2 = routes.get(ROUTE_ID2);
assertNotNull(route1);
@@ -376,12 +379,12 @@ public class MediaRouter2Test {
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route1, CATEGORY_SAMPLE);
- mRouter2.requestCreateSession(route2, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(route1, TYPE_SAMPLE);
+ mRouter2.requestCreateSession(route2, TYPE_SAMPLE);
assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
// onSessionCreationFailed should not be called.
@@ -395,8 +398,9 @@ public class MediaRouter2Test {
assertNotEquals(controller1.getSessionId(), controller2.getSessionId());
assertTrue(createRouteMap(controller1.getSelectedRoutes()).containsKey(ROUTE_ID1));
assertTrue(createRouteMap(controller2.getSelectedRoutes()).containsKey(ROUTE_ID2));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller1.getControlCategory()));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller2.getControlCategory()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller1.getRouteType()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller2.getRouteType()));
+
} finally {
releaseControllers(createdControllers);
mRouter2.unregisterRouteCallback(routeCallback);
@@ -406,10 +410,10 @@ public class MediaRouter2Test {
@Test
public void testSessionCallbackIsNotCalledAfterUnregistered() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info route = routes.get(ROUTE_ID1);
assertNotNull(route);
@@ -427,18 +431,18 @@ public class MediaRouter2Test {
@Override
public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedControlCategory) {
+ String requestedRouteType) {
failureLatch.countDown();
}
};
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(route, TYPE_SAMPLE);
// Unregisters session callback
mRouter2.unregisterSessionCallback(sessionCallback);
@@ -456,10 +460,10 @@ public class MediaRouter2Test {
// TODO: Add tests for illegal inputs if needed (e.g. selecting already selected route)
@Test
public void testRouteSessionControllerSelectAndDeselectRoute() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1);
assertNotNull(routeToCreateSessionWith);
@@ -474,7 +478,7 @@ public class MediaRouter2Test {
public void onSessionCreated(RouteSessionController controller) {
assertNotNull(controller);
assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType()));
controllers.add(controller);
onSessionCreatedLatch.countDown();
}
@@ -483,20 +487,21 @@ public class MediaRouter2Test {
public void onSessionInfoChanged(RouteSessionController controller,
RouteSessionInfo oldInfo, RouteSessionInfo newInfo) {
if (onSessionCreatedLatch.getCount() != 0
- || controllers.get(0).getSessionId() != controller.getSessionId()) {
+ || !TextUtils.equals(
+ controllers.get(0).getSessionId(), controller.getSessionId())) {
return;
}
if (onSessionInfoChangedLatchForSelect.getCount() != 0) {
// Check oldInfo
- assertEquals(controller.getSessionId(), oldInfo.getSessionId());
+ assertEquals(controller.getSessionId(), oldInfo.getId());
assertEquals(1, oldInfo.getSelectedRoutes().size());
assertTrue(oldInfo.getSelectedRoutes().contains(ROUTE_ID1));
assertTrue(oldInfo.getSelectableRoutes().contains(
ROUTE_ID4_TO_SELECT_AND_DESELECT));
// Check newInfo
- assertEquals(controller.getSessionId(), newInfo.getSessionId());
+ assertEquals(controller.getSessionId(), newInfo.getId());
assertEquals(2, newInfo.getSelectedRoutes().size());
assertTrue(newInfo.getSelectedRoutes().contains(ROUTE_ID1));
assertTrue(newInfo.getSelectedRoutes().contains(
@@ -507,7 +512,7 @@ public class MediaRouter2Test {
onSessionInfoChangedLatchForSelect.countDown();
} else {
// Check newInfo
- assertEquals(controller.getSessionId(), newInfo.getSessionId());
+ assertEquals(controller.getSessionId(), newInfo.getId());
assertEquals(1, newInfo.getSelectedRoutes().size());
assertTrue(newInfo.getSelectedRoutes().contains(ROUTE_ID1));
assertFalse(newInfo.getSelectedRoutes().contains(
@@ -522,11 +527,11 @@ public class MediaRouter2Test {
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(routeToCreateSessionWith, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(routeToCreateSessionWith, TYPE_SAMPLE);
assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(1, controllers.size());
@@ -554,10 +559,10 @@ public class MediaRouter2Test {
@Test
public void testRouteSessionControllerTransferToRoute() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1);
assertNotNull(routeToCreateSessionWith);
@@ -570,8 +575,12 @@ public class MediaRouter2Test {
@Override
public void onSessionCreated(RouteSessionController controller) {
assertNotNull(controller);
+ android.util.Log.d(TAG, "selected route ids ");
+ for (String routeId : getRouteIds(controller.getSelectedRoutes())) {
+ android.util.Log.d(TAG, "route id : " + routeId);
+ }
assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType()));
controllers.add(controller);
onSessionCreatedLatch.countDown();
}
@@ -580,18 +589,19 @@ public class MediaRouter2Test {
public void onSessionInfoChanged(RouteSessionController controller,
RouteSessionInfo oldInfo, RouteSessionInfo newInfo) {
if (onSessionCreatedLatch.getCount() != 0
- || controllers.get(0).getSessionId() != controller.getSessionId()) {
+ || !TextUtils.equals(
+ controllers.get(0).getSessionId(), controller.getSessionId())) {
return;
}
// Check oldInfo
- assertEquals(controller.getSessionId(), oldInfo.getSessionId());
+ assertEquals(controller.getSessionId(), oldInfo.getId());
assertEquals(1, oldInfo.getSelectedRoutes().size());
assertTrue(oldInfo.getSelectedRoutes().contains(ROUTE_ID1));
assertTrue(oldInfo.getTransferrableRoutes().contains(ROUTE_ID5_TO_TRANSFER_TO));
// Check newInfo
- assertEquals(controller.getSessionId(), newInfo.getSessionId());
+ assertEquals(controller.getSessionId(), newInfo.getId());
assertEquals(1, newInfo.getSelectedRoutes().size());
assertFalse(newInfo.getSelectedRoutes().contains(ROUTE_ID1));
assertTrue(newInfo.getSelectedRoutes().contains(ROUTE_ID5_TO_TRANSFER_TO));
@@ -603,11 +613,11 @@ public class MediaRouter2Test {
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(routeToCreateSessionWith, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(routeToCreateSessionWith, TYPE_SAMPLE);
assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(1, controllers.size());
@@ -632,10 +642,10 @@ public class MediaRouter2Test {
@Test
public void testRouteSessionControllerReleaseShouldIgnoreTransferTo() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1);
assertNotNull(routeToCreateSessionWith);
@@ -649,7 +659,7 @@ public class MediaRouter2Test {
public void onSessionCreated(RouteSessionController controller) {
assertNotNull(controller);
assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType()));
controllers.add(controller);
onSessionCreatedLatch.countDown();
}
@@ -658,7 +668,8 @@ public class MediaRouter2Test {
public void onSessionInfoChanged(RouteSessionController controller,
RouteSessionInfo oldInfo, RouteSessionInfo newInfo) {
if (onSessionCreatedLatch.getCount() != 0
- || controllers.get(0).getSessionId() != controller.getSessionId()) {
+ || !TextUtils.equals(
+ controllers.get(0).getSessionId(), controller.getSessionId())) {
return;
}
onSessionInfoChangedLatch.countDown();
@@ -667,11 +678,11 @@ public class MediaRouter2Test {
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(routeToCreateSessionWith, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(routeToCreateSessionWith, TYPE_SAMPLE);
assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(1, controllers.size());
@@ -701,17 +712,16 @@ public class MediaRouter2Test {
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
for (MediaRoute2Info route : routes) {
- // intentionally not using route.getUniqueId() for convenience.
routeMap.put(route.getId(), route);
}
return routeMap;
}
- Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> controlCategories)
+ Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> routeTypes)
throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- // A dummy callback is required to send control category info.
+ // A dummy callback is required to send route type info.
RouteCallback routeCallback = new RouteCallback() {
@Override
public void onRoutesAdded(List<MediaRoute2Info> routes) {
@@ -724,8 +734,8 @@ public class MediaRouter2Test {
}
};
- mRouter2.setControlCategories(controlCategories);
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback,
+ new RouteDiscoveryRequest.Builder(routeTypes, true).build());
try {
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
return createRouteMap(mRouter2.getRoutes());
@@ -741,7 +751,7 @@ public class MediaRouter2Test {
}
/**
- * Returns a list of IDs (not uniqueId) of the given route list.
+ * Returns a list of IDs of the given route list.
*/
List<String> getRouteIds(@NonNull List<MediaRoute2Info> routes) {
List<String> result = new ArrayList<>();
@@ -752,7 +762,8 @@ public class MediaRouter2Test {
}
void awaitOnRouteChanged(Runnable task, String routeId,
- Predicate<MediaRoute2Info> predicate) throws Exception {
+ Predicate<MediaRoute2Info> predicate,
+ List<String> routeTypes) throws Exception {
CountDownLatch latch = new CountDownLatch(1);
RouteCallback routeCallback = new RouteCallback() {
@Override
@@ -763,7 +774,8 @@ public class MediaRouter2Test {
}
}
};
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback,
+ new RouteDiscoveryRequest.Builder(routeTypes, true).build());
try {
task.run();
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 83c7c173e8e8..9ff9177c1b40 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -31,6 +31,7 @@ import android.media.MediaRouter2;
import android.media.MediaRouter2.RouteCallback;
import android.media.MediaRouter2.SessionCallback;
import android.media.MediaRouter2Manager;
+import android.media.RouteDiscoveryRequest;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -57,41 +58,48 @@ import java.util.function.Predicate;
public class MediaRouterManagerTest {
private static final String TAG = "MediaRouterManagerTest";
- // Must be the same as SampleMediaRoute2ProviderService
- public static final String ROUTE_ID1 = "route_id1";
+ public static final String SAMPLE_PROVIDER_ROUTES_ID_PREFIX =
+ "com.android.mediarouteprovider.example/.SampleMediaRoute2ProviderService:";
+
+ // Must be the same as SampleMediaRoute2ProviderService except the prefix of IDs.
+ public static final String ROUTE_ID1 = SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id1";
public static final String ROUTE_NAME1 = "Sample Route 1";
- public static final String ROUTE_ID2 = "route_id2";
+ public static final String ROUTE_ID2 = SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id2";
public static final String ROUTE_NAME2 = "Sample Route 2";
public static final String ROUTE_ID3_SESSION_CREATION_FAILED =
- "route_id3_session_creation_failed";
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id3_session_creation_failed";
public static final String ROUTE_NAME3 = "Sample Route 3 - Session creation failed";
public static final String ROUTE_ID4_TO_SELECT_AND_DESELECT =
- "route_id4_to_select_and_deselect";
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id4_to_select_and_deselect";
public static final String ROUTE_NAME4 = "Sample Route 4 - Route to select and deselect";
- public static final String ROUTE_ID5_TO_TRANSFER_TO = "route_id5_to_transfer_to";
+ public static final String ROUTE_ID5_TO_TRANSFER_TO =
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id5_to_transfer_to";
public static final String ROUTE_NAME5 = "Sample Route 5 - Route to transfer to";
- public static final String ROUTE_ID_SPECIAL_CATEGORY = "route_special_category";
- public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route";
+ public static final String ROUTE_ID_SPECIAL_TYPE =
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_special_type";
+ public static final String ROUTE_NAME_SPECIAL_TYPE = "Special Type Route";
public static final String SYSTEM_PROVIDER_ID =
"com.android.server.media/.SystemMediaRoute2Provider";
public static final int VOLUME_MAX = 100;
- public static final String ROUTE_ID_FIXED_VOLUME = "route_fixed_volume";
+ public static final String ROUTE_ID_FIXED_VOLUME =
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_fixed_volume";
public static final String ROUTE_NAME_FIXED_VOLUME = "Fixed Volume Route";
- public static final String ROUTE_ID_VARIABLE_VOLUME = "route_variable_volume";
+ public static final String ROUTE_ID_VARIABLE_VOLUME =
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_variable_volume";
public static final String ROUTE_NAME_VARIABLE_VOLUME = "Variable Volume Route";
public static final String ACTION_REMOVE_ROUTE =
"com.android.mediarouteprovider.action_remove_route";
- public static final String CATEGORY_SAMPLE =
- "com.android.mediarouteprovider.CATEGORY_SAMPLE";
- public static final String CATEGORY_SPECIAL =
- "com.android.mediarouteprovider.CATEGORY_SPECIAL";
+ public static final String TYPE_SAMPLE =
+ "com.android.mediarouteprovider.TYPE_SAMPLE";
+ public static final String TYPE_SPECIAL =
+ "com.android.mediarouteprovider.TYPE_SPECIAL";
- private static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
+ private static final String TYPE_LIVE_AUDIO = "android.media.intent.route.TYPE_LIVE_AUDIO";
private static final int TIMEOUT_MS = 5000;
@@ -105,18 +113,18 @@ public class MediaRouterManagerTest {
private final List<RouteCallback> mRouteCallbacks = new ArrayList<>();
private final List<SessionCallback> mSessionCallbacks = new ArrayList<>();
- public static final List<String> CATEGORIES_ALL = new ArrayList();
- public static final List<String> CATEGORIES_SPECIAL = new ArrayList();
- private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>();
+ public static final List<String> TYPES_ALL = new ArrayList();
+ public static final List<String> TYPES_SPECIAL = new ArrayList();
+ private static final List<String> TYPES_LIVE_AUDIO = new ArrayList<>();
static {
- CATEGORIES_ALL.add(CATEGORY_SAMPLE);
- CATEGORIES_ALL.add(CATEGORY_SPECIAL);
- CATEGORIES_ALL.add(CATEGORY_LIVE_AUDIO);
+ TYPES_ALL.add(TYPE_SAMPLE);
+ TYPES_ALL.add(TYPE_SPECIAL);
+ TYPES_ALL.add(TYPE_LIVE_AUDIO);
- CATEGORIES_SPECIAL.add(CATEGORY_SPECIAL);
+ TYPES_SPECIAL.add(TYPE_SPECIAL);
- CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO);
+ TYPES_LIVE_AUDIO.add(TYPE_LIVE_AUDIO);
}
@Before
@@ -173,7 +181,7 @@ public class MediaRouterManagerTest {
@Test
public void testOnRoutesRemoved() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
addRouterCallback(new RouteCallback());
addManagerCallback(new MediaRouter2Manager.Callback() {
@@ -195,14 +203,14 @@ public class MediaRouterManagerTest {
}
/**
- * Tests if we get proper routes for application that has special control category.
+ * Tests if we get proper routes for application that has special route type.
*/
@Test
- public void testControlCategory() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
+ public void testRouteType() throws Exception {
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_SPECIAL);
assertEquals(1, routes.size());
- assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
+ assertNotNull(routes.get(ROUTE_ID_SPECIAL_TYPE));
}
/**
@@ -211,7 +219,7 @@ public class MediaRouterManagerTest {
*/
@Test
public void testRouterOnSessionCreated() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
CountDownLatch latch = new CountDownLatch(1);
@@ -247,7 +255,7 @@ public class MediaRouterManagerTest {
@Ignore("TODO: test session created callback instead of onRouteSelected")
public void testManagerOnRouteSelected() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
addRouterCallback(new RouteCallback());
addManagerCallback(new MediaRouter2Manager.Callback() {
@@ -277,7 +285,7 @@ public class MediaRouterManagerTest {
public void testGetActiveRoutes() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
addRouterCallback(new RouteCallback());
addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
@@ -313,7 +321,7 @@ public class MediaRouterManagerTest {
@Test
@Ignore("TODO: enable when session is released")
public void testSingleProviderSelect() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
addRouterCallback(new RouteCallback());
awaitOnRouteChangedManager(
@@ -338,7 +346,7 @@ public class MediaRouterManagerTest {
@Test
public void testControlVolumeWithManager() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
int originalVolume = volRoute.getVolume();
@@ -357,7 +365,7 @@ public class MediaRouterManagerTest {
@Test
public void testVolumeHandling() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
@@ -367,11 +375,11 @@ public class MediaRouterManagerTest {
assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
}
- Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> controlCategories)
+ Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeTypes)
throws Exception {
CountDownLatch latch = new CountDownLatch(2);
- // A dummy callback is required to send control category info.
+ // A dummy callback is required to send route type info.
RouteCallback routeCallback = new RouteCallback();
MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
@Override
@@ -386,16 +394,16 @@ public class MediaRouterManagerTest {
}
@Override
- public void onControlCategoriesChanged(String packageName, List<String> categories) {
+ public void onControlCategoriesChanged(String packageName, List<String> routeTypes) {
if (TextUtils.equals(mPackageName, packageName)
- && controlCategories.equals(categories)) {
+ && routeTypes.equals(routeTypes)) {
latch.countDown();
}
}
};
mManager.registerCallback(mExecutor, managerCallback);
- mRouter2.setControlCategories(controlCategories);
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback,
+ new RouteDiscoveryRequest.Builder(routeTypes, true).build());
try {
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
return createRouteMap(mManager.getAvailableRoutes(mPackageName));
@@ -430,7 +438,6 @@ public class MediaRouterManagerTest {
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
for (MediaRoute2Info route : routes) {
- // intentionally not using route.getUniqueId() for convenience.
routeMap.put(route.getId(), route);
}
return routeMap;
@@ -443,7 +450,7 @@ public class MediaRouterManagerTest {
private void addRouterCallback(RouteCallback routeCallback) {
mRouteCallbacks.add(routeCallback);
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
}
private void addSessionCallback(SessionCallback sessionCallback) {
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java
new file mode 100644
index 000000000000..60d131a8fb7e
--- /dev/null
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaroutertest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.media.RouteDiscoveryRequest;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RouteDiscoveryRequestTest {
+ @Before
+ public void setUp() throws Exception { }
+
+ @After
+ public void tearDown() throws Exception { }
+
+ @Test
+ public void testEquality() {
+ List<String> testTypes = new ArrayList<>();
+ testTypes.add("TEST_TYPE_1");
+ testTypes.add("TEST_TYPE_2");
+ RouteDiscoveryRequest request = new RouteDiscoveryRequest.Builder(testTypes, true)
+ .build();
+
+ RouteDiscoveryRequest requestRebuilt = new RouteDiscoveryRequest.Builder(request)
+ .build();
+
+ assertEquals(request, requestRebuilt);
+
+ Parcel parcel = Parcel.obtain();
+ parcel.writeParcelable(request, 0);
+ parcel.setDataPosition(0);
+ RouteDiscoveryRequest requestFromParcel = parcel.readParcelable(null);
+
+ assertEquals(request, requestFromParcel);
+ }
+
+ @Test
+ public void testInequality() {
+ List<String> testTypes = new ArrayList<>();
+ testTypes.add("TEST_TYPE_1");
+ testTypes.add("TEST_TYPE_2");
+
+ List<String> testTypes2 = new ArrayList<>();
+ testTypes.add("TEST_TYPE_3");
+
+ RouteDiscoveryRequest request = new RouteDiscoveryRequest.Builder(testTypes, true)
+ .build();
+
+ RouteDiscoveryRequest requestTypes = new RouteDiscoveryRequest.Builder(request)
+ .setRouteTypes(testTypes2)
+ .build();
+ assertNotEquals(request, requestTypes);
+
+ RouteDiscoveryRequest requestActiveScan = new RouteDiscoveryRequest.Builder(request)
+ .setActiveScan(false)
+ .build();
+ assertNotEquals(request, requestActiveScan);
+ }
+}
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteSessionTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteSessionTest.java
index 2e81a646b0db..9971fc3bbe9f 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteSessionTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteSessionTest.java
@@ -29,6 +29,7 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class RouteSessionTest {
+ private static final String TEST_SESSION_ID = "test_session_id";
private static final String TEST_PACKAGE_NAME = "com.android.mediaroutertest";
private static final String TEST_CONTROL_CATEGORY = "com.android.mediaroutertest.category";
@@ -36,17 +37,17 @@ public class RouteSessionTest {
@Test
public void testValidity() {
- RouteSessionInfo emptyPackageSession = new RouteSessionInfo.Builder(1,
+ RouteSessionInfo emptyPackageSession = new RouteSessionInfo.Builder(TEST_SESSION_ID,
"",
TEST_CONTROL_CATEGORY)
.addSelectedRoute(TEST_ROUTE_ID1)
.build();
- RouteSessionInfo emptyCategorySession = new RouteSessionInfo.Builder(1,
+ RouteSessionInfo emptyCategorySession = new RouteSessionInfo.Builder(TEST_SESSION_ID,
TEST_PACKAGE_NAME, "")
.addSelectedRoute(TEST_ROUTE_ID1)
.build();
- RouteSessionInfo emptySelectedRouteSession = new RouteSessionInfo.Builder(1,
+ RouteSessionInfo emptySelectedRouteSession = new RouteSessionInfo.Builder(TEST_SESSION_ID,
TEST_PACKAGE_NAME, TEST_CONTROL_CATEGORY)
.build();
@@ -54,9 +55,9 @@ public class RouteSessionTest {
.addSelectedRoute(TEST_ROUTE_ID1)
.build();
- assertFalse(emptySelectedRouteSession.isValid());
assertFalse(emptyPackageSession.isValid());
assertFalse(emptyCategorySession.isValid());
+ assertFalse(emptySelectedRouteSession.isValid());
assertTrue(validSession.isValid());
}
}
diff --git a/mms/OWNERS b/mms/OWNERS
index ba00d5d75010..befc320b949c 100644
--- a/mms/OWNERS
+++ b/mms/OWNERS
@@ -12,3 +12,5 @@ satk@google.com
shuoq@google.com
refuhoo@google.com
nazaninb@google.com
+sarahchin@google.com
+dbright@google.com \ No newline at end of file
diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java
index 65542673a607..24ea3cfc5a75 100644
--- a/mms/java/android/telephony/MmsManager.java
+++ b/mms/java/android/telephony/MmsManager.java
@@ -16,8 +16,11 @@
package android.telephony;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityThread;
import android.app.PendingIntent;
+import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
@@ -27,22 +30,16 @@ import com.android.internal.telephony.IMms;
/**
* Manages MMS operations such as sending multimedia messages.
- * Get this object by calling the static method {@link #getInstance()}.
- * @hide
*/
-public class MmsManager {
+public final class MmsManager {
private static final String TAG = "MmsManager";
-
- /** Singleton object constructed during class initialization. */
- private static final MmsManager sInstance = new MmsManager();
+ private final Context mContext;
/**
- * Get the MmsManager singleton instance.
- *
- * @return the {@link MmsManager} singleton instance.
+ * @hide
*/
- public static MmsManager getInstance() {
- return sInstance;
+ public MmsManager(@NonNull Context context) {
+ mContext = context;
}
/**
@@ -56,8 +53,9 @@ public class MmsManager {
* @param sentIntent if not NULL this <code>PendingIntent</code> is broadcast when the message
* is successfully sent, or failed
*/
- public void sendMultimediaMessage(int subId, Uri contentUri, String locationUrl,
- Bundle configOverrides, PendingIntent sentIntent) {
+ public void sendMultimediaMessage(int subId, @NonNull Uri contentUri,
+ @Nullable String locationUrl, @Nullable Bundle configOverrides,
+ @Nullable PendingIntent sentIntent) {
try {
final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
if (iMms == null) {
@@ -84,8 +82,9 @@ public class MmsManager {
* broadcast when the message is downloaded, or the download is failed
* @throws IllegalArgumentException if locationUrl or contentUri is empty
*/
- public void downloadMultimediaMessage(int subId, String locationUrl, Uri contentUri,
- Bundle configOverrides, PendingIntent downloadedIntent) {
+ public void downloadMultimediaMessage(int subId, @NonNull String locationUrl,
+ @NonNull Uri contentUri, @Nullable Bundle configOverrides,
+ @Nullable PendingIntent downloadedIntent) {
try {
final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
if (iMms == null) {
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
index 1aebeaf1e7e8..26c7f8d709e7 100644
--- a/native/graphics/jni/bitmap.cpp
+++ b/native/graphics/jni/bitmap.cpp
@@ -16,6 +16,7 @@
#include <android/bitmap.h>
#include <android/graphics/bitmap.h>
+#include <android/data_space.h>
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
AndroidBitmapInfo* info) {
@@ -29,6 +30,15 @@ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
return ANDROID_BITMAP_RESULT_SUCCESS;
}
+int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap) {
+ if (NULL == env || NULL == jbitmap) {
+ return ADATASPACE_UNKNOWN; // Or return a real error?
+ }
+
+ android::graphics::Bitmap bitmap(env, jbitmap);
+ return bitmap.getDataSpace();
+}
+
int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) {
if (NULL == env || NULL == jbitmap) {
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt
index a601d8af2830..6adb95520d6c 100644
--- a/native/graphics/jni/libjnigraphics.map.txt
+++ b/native/graphics/jni/libjnigraphics.map.txt
@@ -1,6 +1,7 @@
LIBJNIGRAPHICS {
global:
AndroidBitmap_getInfo;
+ AndroidBitmap_getDataSpace;
AndroidBitmap_lockPixels;
AndroidBitmap_unlockPixels;
local:
diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java
index 728e6e18cc31..90b46fd5901a 100644
--- a/opengl/java/android/opengl/EGL14.java
+++ b/opengl/java/android/opengl/EGL14.java
@@ -18,11 +18,11 @@
package android.opengl;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.SurfaceTexture;
import android.view.Surface;
-import android.view.SurfaceView;
import android.view.SurfaceHolder;
+import android.view.SurfaceView;
/**
* EGL 1.4
diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java
index d66e7ac84a3b..e853e4447daa 100644
--- a/opengl/java/android/opengl/GLES20.java
+++ b/opengl/java/android/opengl/GLES20.java
@@ -19,7 +19,7 @@
package android.opengl;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/** OpenGL ES 2.0
*/
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 8a3e6a0b0fd5..75131b0f6b9c 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -16,7 +16,7 @@
package android.opengl;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Trace;
import android.util.AttributeSet;
diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java
index 8a2517062d4d..ea571c7311a1 100644
--- a/opengl/java/javax/microedition/khronos/egl/EGL10.java
+++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java
@@ -16,8 +16,7 @@
package javax.microedition.khronos.egl;
-import android.annotation.UnsupportedAppUsage;
-import java.lang.String;
+import android.compat.annotation.UnsupportedAppUsage;
public interface EGL10 extends EGL {
int EGL_SUCCESS = 0x3000;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index ed945e7d4e72..f7802d205a3a 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -18,6 +18,7 @@ package com.android.systemui.car;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.logging.NotifLog;
@@ -40,8 +41,9 @@ public class CarNotificationEntryManager extends NotificationEntryManager {
NotifLog notifLog,
NotificationGroupManager groupManager,
NotificationRankingManager rankingManager,
- KeyguardEnvironment keyguardEnvironment) {
- super(notifLog, groupManager, rankingManager, keyguardEnvironment);
+ KeyguardEnvironment keyguardEnvironment,
+ FeatureFlags featureFlags) {
+ super(notifLog, groupManager, rankingManager, keyguardEnvironment, featureFlags);
}
@Override
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 1e19786f5d41..ec445d4dcbee 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -160,7 +160,7 @@ public class ExternalStorageProvider extends FileSystemProvider {
final int userId = UserHandle.myUserId();
final List<VolumeInfo> volumes = mStorageManager.getVolumes();
for (VolumeInfo volume : volumes) {
- if (!volume.isMountedReadable()) continue;
+ if (!volume.isMountedReadable() || volume.getMountUserId() != userId) continue;
final String rootId;
final String title;
@@ -192,9 +192,8 @@ public class ExternalStorageProvider extends FileSystemProvider {
title = mStorageManager.getBestVolumeDescription(privateVol);
storageUuid = StorageManager.convert(privateVol.fsUuid);
}
- } else if ((volume.getType() == VolumeInfo.TYPE_PUBLIC
- || volume.getType() == VolumeInfo.TYPE_STUB)
- && volume.getMountUserId() == userId) {
+ } else if (volume.getType() == VolumeInfo.TYPE_PUBLIC
+ || volume.getType() == VolumeInfo.TYPE_STUB) {
rootId = volume.getFsUuid();
title = mStorageManager.getBestVolumeDescription(volume);
storageUuid = null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index a2bd210b67a6..a784e04ee6a0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
@@ -148,17 +151,18 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.connect(device);
+ if (mService == null) {
+ return false;
+ }
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
- // Downgrade priority as user is disconnecting the headset.
- if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService == null) {
+ return false;
}
- return mService.disconnect(device);
+
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
@@ -182,12 +186,12 @@ public class A2dpProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
@@ -197,11 +201,11 @@ public class A2dpProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
}
boolean isA2dpPlaying() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index bc03c343a909..8ca5a74652dc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothA2dpSink;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
@@ -116,18 +119,15 @@ final class A2dpSinkProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.connect(device);
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
public boolean disconnect(BluetoothDevice device) {
if (mService == null) {
return false;
}
- // Downgrade priority as user is disconnecting the headset.
- if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- }
- return mService.disconnect(device);
+
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
@@ -141,12 +141,12 @@ final class A2dpSinkProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
@@ -156,11 +156,11 @@ final class A2dpSinkProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 560cb3b9b5b4..d65b5da22056 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -112,18 +115,15 @@ public class HeadsetProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.connect(device);
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
public boolean disconnect(BluetoothDevice device) {
if (mService == null) {
return false;
}
- // Downgrade priority as user is disconnecting the headset.
- if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- }
- return mService.disconnect(device);
+
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
@@ -165,12 +165,12 @@ public class HeadsetProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
@@ -180,11 +180,11 @@ public class HeadsetProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index b4b55f363020..9f1af669c708 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -146,17 +149,18 @@ public class HearingAidProfile implements LocalBluetoothProfile {
}
public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.connect(device);
+ if (mService == null) {
+ return false;
+ }
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
- // Downgrade priority as user is disconnecting the hearing aid.
- if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService == null) {
+ return false;
}
- return mService.disconnect(device);
+
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
@@ -180,12 +184,12 @@ public class HearingAidProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
@@ -195,11 +199,11 @@ public class HearingAidProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index a372e23654e0..678f2e37c6bf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -126,7 +129,7 @@ final class HfpClientProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.connect(device);
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
@Override
@@ -134,11 +137,8 @@ final class HfpClientProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- // Downgrade priority as user is disconnecting the headset.
- if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- }
- return mService.disconnect(device);
+
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
@Override
@@ -154,13 +154,13 @@ final class HfpClientProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
@Override
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
@@ -171,11 +171,11 @@ final class HfpClientProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 975a1e67af5b..588083e73481 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -99,13 +102,17 @@ public class HidProfile implements LocalBluetoothProfile {
}
public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.connect(device);
+ if (mService == null) {
+ return false;
+ }
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.disconnect(device);
+ if (mService == null) {
+ return false;
+ }
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
@@ -119,12 +126,12 @@ public class HidProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getConnectionPolicy(device) != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return mService.getConnectionPolicy(device) != CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
@@ -132,11 +139,11 @@ public class HidProfile implements LocalBluetoothProfile {
public void setPreferred(BluetoothDevice device, boolean preferred) {
if (mService == null) return;
if (preferred) {
- if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 95139a1bfab9..7d121aaa1ad1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -115,18 +118,15 @@ public final class MapClientProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.connect(device);
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
public boolean disconnect(BluetoothDevice device) {
if (mService == null) {
return false;
}
- // Downgrade priority as user is disconnecting.
- if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- }
- return mService.disconnect(device);
+
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
@@ -140,12 +140,12 @@ public final class MapClientProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
@@ -155,11 +155,11 @@ public final class MapClientProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 31a0eea56b42..a96a4e73feea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -16,6 +16,8 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -119,10 +121,8 @@ public class MapProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- }
- return mService.disconnect(device);
+
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
@@ -136,12 +136,12 @@ public class MapProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
@@ -155,7 +155,7 @@ public class MapProfile implements LocalBluetoothProfile {
mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 4ea0df621bea..56267fc596cf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -129,7 +132,7 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
return false;
}
Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress());
- return mService.connect(device);
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
public boolean disconnect(BluetoothDevice device) {
@@ -137,7 +140,7 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.disconnect(device);
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
@@ -151,12 +154,12 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
@@ -166,11 +169,11 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index 3f920a8cf1dd..f7c0bf5c8c9d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -16,6 +16,8 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -96,8 +98,10 @@ public class PbapServerProfile implements LocalBluetoothProfile {
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.disconnect(device);
+ if (mService == null) {
+ return false;
+ }
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index 0ca4d6195a32..3022c5b566eb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -112,17 +115,15 @@ final class SapProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.connect(device);
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
public boolean disconnect(BluetoothDevice device) {
if (mService == null) {
return false;
}
- if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- }
- return mService.disconnect(device);
+
+ return mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
@@ -136,12 +137,12 @@ final class SapProfile implements LocalBluetoothProfile {
if (mService == null) {
return false;
}
- return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
}
public int getPreferred(BluetoothDevice device) {
if (mService == null) {
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ return CONNECTION_POLICY_FORBIDDEN;
}
return mService.getConnectionPolicy(device);
}
@@ -151,11 +152,11 @@ final class SapProfile implements LocalBluetoothProfile {
return;
}
if (preferred) {
- if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
}
} else {
- mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 5b4ef3a47386..70b56ed0b391 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -194,6 +194,14 @@ public class LocalMediaManager implements BluetoothCallback {
}
}
+ void dispatchDeviceAttributesChanged() {
+ synchronized (mCallbacks) {
+ for (DeviceCallback callback : mCallbacks) {
+ callback.onDeviceAttributesChanged();
+ }
+ }
+ }
+
/**
* Stop scan MediaDevice
*/
@@ -306,14 +314,12 @@ public class LocalMediaManager implements BluetoothCallback {
}
mCurrentConnectedDevice = connectDevice;
updatePhoneMediaDeviceSummary();
- dispatchDeviceListUpdate();
+ dispatchDeviceAttributesChanged();
}
@Override
public void onDeviceAttributesChanged() {
- addPhoneDeviceIfNecessary();
- removePhoneMediaDeviceIfNecessary();
- dispatchDeviceListUpdate();
+ dispatchDeviceAttributesChanged();
}
}
@@ -327,7 +333,7 @@ public class LocalMediaManager implements BluetoothCallback {
*
* @param devices MediaDevice list
*/
- void onDeviceListUpdate(List<MediaDevice> devices);
+ default void onDeviceListUpdate(List<MediaDevice> devices) {};
/**
* Callback for notifying the connected device is changed.
@@ -338,6 +344,12 @@ public class LocalMediaManager implements BluetoothCallback {
* {@link MediaDeviceState#STATE_CONNECTING},
* {@link MediaDeviceState#STATE_DISCONNECTED}
*/
- void onSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state);
+ default void onSelectedDeviceStateChanged(MediaDevice device,
+ @MediaDeviceState int state) {};
+
+ /**
+ * Callback for notifying the device attributes is changed.
+ */
+ default void onDeviceAttributesChanged() {};
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
index 976445eb8c04..ccb6646cf683 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
@@ -67,13 +70,13 @@ public class A2dpSinkProfileTest {
@Test
public void connect_shouldConnectBluetoothA2dpSink() {
mProfile.connect(mBluetoothDevice);
- verify(mService).connect(mBluetoothDevice);
+ verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_ALLOWED);
}
@Test
public void disconnect_shouldDisconnectBluetoothA2dpSink() {
mProfile.disconnect(mBluetoothDevice);
- verify(mService).disconnect(mBluetoothDevice);
+ verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_FORBIDDEN);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
index 69c020dd5c08..91807609df1a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
@@ -67,13 +70,13 @@ public class HfpClientProfileTest {
@Test
public void connect_shouldConnectBluetoothHeadsetClient() {
mProfile.connect(mBluetoothDevice);
- verify(mService).connect(mBluetoothDevice);
+ verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_ALLOWED);
}
@Test
public void disconnect_shouldDisconnectBluetoothHeadsetClient() {
mProfile.disconnect(mBluetoothDevice);
- verify(mService).disconnect(mBluetoothDevice);
+ verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_FORBIDDEN);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
index 6f667094a5aa..1425c381256b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
@@ -67,13 +70,13 @@ public class MapClientProfileTest {
@Test
public void connect_shouldConnectBluetoothMapClient() {
mProfile.connect(mBluetoothDevice);
- verify(mService).connect(mBluetoothDevice);
+ verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_ALLOWED);
}
@Test
public void disconnect_shouldDisconnectBluetoothMapClient() {
mProfile.disconnect(mBluetoothDevice);
- verify(mService).disconnect(mBluetoothDevice);
+ verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_FORBIDDEN);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
index b21ec9c3e52a..15f560bef73e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
@@ -67,13 +70,13 @@ public class PbapClientProfileTest {
@Test
public void connect_shouldConnectBluetoothPbapClient() {
mProfile.connect(mBluetoothDevice);
- verify(mService).connect(mBluetoothDevice);
+ verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_ALLOWED);
}
@Test
public void disconnect_shouldDisconnectBluetoothPbapClient() {
mProfile.disconnect(mBluetoothDevice);
- verify(mService).disconnect(mBluetoothDevice);
+ verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_FORBIDDEN);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
index ec880345f6f0..4f978a822890 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
@@ -16,6 +16,9 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
@@ -66,13 +69,13 @@ public class SapProfileTest {
@Test
public void connect_shouldConnectBluetoothSap() {
mProfile.connect(mBluetoothDevice);
- verify(mService).connect(mBluetoothDevice);
+ verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_ALLOWED);
}
@Test
public void disconnect_shouldDisconnectBluetoothSap() {
mProfile.disconnect(mBluetoothDevice);
- verify(mService).disconnect(mBluetoothDevice);
+ verify(mService).setConnectionPolicy(mBluetoothDevice, CONNECTION_POLICY_FORBIDDEN);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 98bb74ad0718..894aa78a978e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -355,7 +355,7 @@ public class LocalMediaManagerTest {
mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_2);
assertThat(mLocalMediaManager.getCurrentConnectedDevice()).isEqualTo(device2);
- verify(mCallback).onDeviceListUpdate(any());
+ verify(mCallback).onDeviceAttributesChanged();
}
@Test
@@ -373,7 +373,7 @@ public class LocalMediaManagerTest {
mLocalMediaManager.registerCallback(mCallback);
mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_1);
- verify(mCallback, never()).onDeviceListUpdate(any());
+ verify(mCallback, never()).onDeviceAttributesChanged();
}
@Test
@@ -382,6 +382,6 @@ public class LocalMediaManagerTest {
mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged();
- verify(mCallback).onDeviceListUpdate(any());
+ verify(mCallback).onDeviceAttributesChanged();
}
}
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index f40d3a160513..96a98dca8a5b 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -8,6 +8,7 @@ android_app {
libs: [
"telephony-common",
"ims-common",
+ "unsupportedappusage",
],
static_libs: [
"junit",
@@ -40,6 +41,7 @@ android_test {
libs: [
"android.test.base",
"android.test.mock",
+ "unsupportedappusage",
],
resource_dirs: ["res"],
aaptflags: [
diff --git a/packages/SettingsProvider/res/values/overlayable.xml b/packages/SettingsProvider/res/values/overlayable.xml
deleted file mode 100644
index dc41a77d0e2d..000000000000
--- a/packages/SettingsProvider/res/values/overlayable.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!-- 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.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <overlayable name="SettingsToNotRestore">
- <policy type="product|system|vendor">
- <item type="array" name="restore_blocked_device_specific_settings" />
- <item type="array" name="restore_blocked_global_settings" />
- <item type="array" name="restore_blocked_secure_settings" />
- <item type="array" name="restore_blocked_system_settings" />
- </policy>
- </overlayable>
-</resources>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 049b9f0e903e..5636cc8a3ca3 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -16,7 +16,7 @@
package android.provider.settings.backup;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.provider.Settings;
/** Information relating to the Secure settings which should be backed up */
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 89b19de8dfcb..3f5b0daa06a7 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -16,7 +16,7 @@
package android.provider.settings.backup;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.provider.Settings;
/** Information about the system settings to back up */
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 94ab0f11927d..c5d4fa9f1b40 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -25,7 +25,7 @@ import static android.provider.settings.validators.SettingsValidators.URI_VALIDA
import static android.provider.settings.validators.SettingsValidators.VIBRATION_INTENSITY_VALIDATOR;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.hardware.display.ColorDisplayManager;
import android.os.BatteryManager;
diff --git a/packages/SystemUI/docs/broadcasts.md b/packages/SystemUI/docs/broadcasts.md
index 56a637fe588c..28657f28e53b 100644
--- a/packages/SystemUI/docs/broadcasts.md
+++ b/packages/SystemUI/docs/broadcasts.md
@@ -42,24 +42,29 @@ Acquire the dispatcher by using `@Inject` to obtain a `BroadcastDispatcher`. The
```kotlin
/**
- * Register a receiver for broadcast with the dispatcher
- *
- * @param receiver A receiver to dispatch the [Intent]
- * @param filter A filter to determine what broadcasts should be dispatched to this receiver.
- * It will only take into account actions and categories for filtering. It must
- * have at least one action.
- * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. By default, it is the
- * main handler. Pass `null` to use the default.
- * @param user A user handle to determine which broadcast should be dispatched to this receiver.
- * By default, it is the current user.
- * @throws IllegalArgumentException if the filter has other constraints that are not actions or
- * categories or the filter has no actions.
- */
+ * Register a receiver for broadcast with the dispatcher
+ *
+ * @param receiver A receiver to dispatch the [Intent]
+ * @param filter A filter to determine what broadcasts should be dispatched to this receiver.
+ * It will only take into account actions and categories for filtering. It must
+ * have at least one action.
+ * @param executor An executor to dispatch [BroadcastReceiver.onReceive]. Pass null to use an
+ * executor in the main thread (default).
+ * @param user A user handle to determine which broadcast should be dispatched to this receiver.
+ * By default, it is the current user.
+ * @throws IllegalArgumentException if the filter has other constraints that are not actions or
+ * categories or the filter has no actions.
+ */
@JvmOverloads
-fun registerReceiver(BroadcastReceiver, IntentFilter, Handler? = mainHandler, UserHandle = context.user)
+fun registerReceiver(
+ BroadcastReceiver,
+ IntentFilter,
+ Executor? = context.mainExecutor,
+ UserHandle = context.user
+) {
```
-All subscriptions are done with the same overloaded method. As specified in the doc, in order to pass a `UserHandle` with the default `Handler`, pass `null` for the `Handler`.
+All subscriptions are done with the same overloaded method. As specified in the doc, in order to pass a `UserHandle` with the default `Executor`, pass `null` for the `Executor`.
In the same way as with `Context`, subscribing the same `BroadcastReceiver` for the same user using different filters will result on two subscriptions, not in replacing the filter.
diff --git a/packages/SystemUI/res/layout/media_carousel.xml b/packages/SystemUI/res/layout/media_carousel.xml
new file mode 100644
index 000000000000..e91f840fe238
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_carousel.xml
@@ -0,0 +1,35 @@
+<?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
+ -->
+
+<!-- Carousel for media controls -->
+<HorizontalScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_media_height"
+ android:padding="@dimen/qs_media_padding"
+ android:scrollbars="none"
+ android:visibility="gone"
+ >
+ <LinearLayout
+ android:id="@+id/media_carousel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <!-- QSMediaPlayers will be added here dynamically -->
+ </LinearLayout>
+</HorizontalScrollView>
diff --git a/packages/SystemUI/res/layout/people_strip.xml b/packages/SystemUI/res/layout/people_strip.xml
index f0ac08bdad37..982aa8ef6d16 100644
--- a/packages/SystemUI/res/layout/people_strip.xml
+++ b/packages/SystemUI/res/layout/people_strip.xml
@@ -18,7 +18,10 @@
<com.android.systemui.statusbar.notification.stack.PeopleHubView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="105dp">
+ android:layout_height="@dimen/notification_section_header_height"
+ android:focusable="true"
+ android:clickable="true"
+>
<com.android.systemui.statusbar.notification.row.NotificationBackgroundView
android:id="@+id/backgroundNormal"
@@ -34,199 +37,56 @@
android:id="@+id/people_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="12dp"
- android:paddingBottom="12dp"
android:gravity="center"
android:orientation="horizontal">
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_marginStart="@dimen/notification_section_header_padding_left"
+ android:gravity="start"
+ android:textAlignment="gravity"
+ android:text="@string/notification_section_header_conversations"
+ android:textSize="12sp"
+ android:textColor="@color/notification_section_header_label_color"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
/>
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginEnd="8dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
</LinearLayout>
@@ -236,4 +96,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
-</com.android.systemui.statusbar.notification.stack.PeopleHubView> \ No newline at end of file
+</com.android.systemui.statusbar.notification.stack.PeopleHubView>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 52c0a26f09ba..4f532b7b751d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1163,6 +1163,9 @@
<!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
<string name="notification_section_header_gentle">Silent notifications</string>
+ <!-- Section title for conversational notifications. [CHAR LIMIT=40] -->
+ <string name="notification_section_header_conversations">Conversations</string>
+
<!-- Content description for accessibility: Tapping this button will dismiss all gentle notifications [CHAR LIMIT=NONE] -->
<string name="accessibility_notification_section_header_gentle_clear_all">Clear all silent notifications</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 431862f1cc11..a58e3d78bb08 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1638,7 +1638,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- broadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mHandler);
+ broadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler);
final IntentFilter allUserFilter = new IntentFilter();
allUserFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
@@ -1649,8 +1649,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
allUserFilter.addAction(ACTION_USER_UNLOCKED);
allUserFilter.addAction(ACTION_USER_STOPPED);
allUserFilter.addAction(ACTION_USER_REMOVED);
- broadcastDispatcher.registerReceiver(mBroadcastAllReceiver, allUserFilter, mHandler,
- UserHandle.ALL);
+ broadcastDispatcher.registerReceiverWithHandler(mBroadcastAllReceiver, allUserFilter,
+ mHandler, UserHandle.ALL);
mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
try {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index eecc54c678c0..bbe972dea11f 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -121,6 +121,7 @@ import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.leak.LeakReporter;
import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.wm.DisplayImeController;
import com.android.systemui.wm.DisplayWindowController;
import com.android.systemui.wm.SystemWindows;
@@ -321,6 +322,7 @@ public class Dependency {
@Inject Lazy<StatusBar> mStatusBar;
@Inject Lazy<DisplayWindowController> mDisplayWindowController;
@Inject Lazy<SystemWindows> mSystemWindows;
+ @Inject Lazy<DisplayImeController> mDisplayImeController;
@Inject
public Dependency() {
@@ -509,6 +511,7 @@ public class Dependency {
mProviders.put(StatusBar.class, mStatusBar::get);
mProviders.put(DisplayWindowController.class, mDisplayWindowController::get);
mProviders.put(SystemWindows.class, mSystemWindows::get);
+ mProviders.put(DisplayImeController.class, mDisplayImeController::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/DumpController.kt b/packages/SystemUI/src/com/android/systemui/DumpController.kt
index 8c7075bee6cc..f14c4cd8e6c6 100644
--- a/packages/SystemUI/src/com/android/systemui/DumpController.kt
+++ b/packages/SystemUI/src/com/android/systemui/DumpController.kt
@@ -30,6 +30,14 @@ import javax.inject.Singleton
/**
* Controller that allows any [Dumpable] to subscribe and be dumped along with other SystemUI
* dependencies.
+ *
+ * To dump a specific dumpable on-demand:
+ *
+ * ```
+ * $ adb shell dumpsys activity service com.android.systemui/.SystemUIService dependency DumpController <tag1>,<tag2>,<tag3>
+ * ```
+ *
+ * Where tag1, tag2, etc. are the tags of the dumpables you want to dump.
*/
@Singleton
class DumpController @Inject constructor() : Dumpable {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 0e736dcd11a8..c533755c76da 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -266,7 +266,7 @@ public class ScreenDecorations extends SystemUI implements Tunable {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
- mBroadcastDispatcher.registerReceiver(mIntentReceiver, filter, mHandler);
+ mBroadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter, mHandler);
mOverlay.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index 8cb0cc5db1d3..cedf7c354ccc 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -20,6 +20,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.IntentFilter
import android.os.Handler
+import android.os.HandlerExecutor
import android.os.Looper
import android.os.Message
import android.os.UserHandle
@@ -32,13 +33,14 @@ import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import java.io.FileDescriptor
import java.io.PrintWriter
+import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Singleton
data class ReceiverData(
val receiver: BroadcastReceiver,
val filter: IntentFilter,
- val handler: Handler,
+ val executor: Executor,
val user: UserHandle
)
@@ -76,24 +78,49 @@ open class BroadcastDispatcher @Inject constructor (
* @param filter A filter to determine what broadcasts should be dispatched to this receiver.
* It will only take into account actions and categories for filtering. It must
* have at least one action.
- * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. By default, it is the
- * main handler. Pass `null` to use the default.
+ * @param handler A handler to dispatch [BroadcastReceiver.onReceive].
* @param user A user handle to determine which broadcast should be dispatched to this receiver.
* By default, it is the current user.
* @throws IllegalArgumentException if the filter has other constraints that are not actions or
* categories or the filter has no actions.
*/
+ @Deprecated(message = "Replacing Handler for Executor in SystemUI",
+ replaceWith = ReplaceWith("registerReceiver(receiver, filter, executor, user)"))
@JvmOverloads
- fun registerReceiver(
+ fun registerReceiverWithHandler(
receiver: BroadcastReceiver,
filter: IntentFilter,
- handler: Handler? = mainHandler,
+ handler: Handler,
user: UserHandle = context.user
) {
+ registerReceiver(receiver, filter, HandlerExecutor(handler), user)
+ }
+
+ /**
+ * Register a receiver for broadcast with the dispatcher
+ *
+ * @param receiver A receiver to dispatch the [Intent]
+ * @param filter A filter to determine what broadcasts should be dispatched to this receiver.
+ * It will only take into account actions and categories for filtering. It must
+ * have at least one action.
+ * @param executor An executor to dispatch [BroadcastReceiver.onReceive]. Pass null to use an
+ * executor in the main thread (default).
+ * @param user A user handle to determine which broadcast should be dispatched to this receiver.
+ * By default, it is the current user.
+ * @throws IllegalArgumentException if the filter has other constraints that are not actions or
+ * categories or the filter has no actions.
+ */
+ @JvmOverloads
+ fun registerReceiver(
+ receiver: BroadcastReceiver,
+ filter: IntentFilter,
+ executor: Executor? = context.mainExecutor,
+ user: UserHandle = context.user
+ ) {
checkFilter(filter)
this.handler
.obtainMessage(MSG_ADD_RECEIVER,
- ReceiverData(receiver, filter, handler ?: mainHandler, user))
+ ReceiverData(receiver, filter, executor ?: context.mainExecutor, user))
.sendToTarget()
}
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
index b2942bb14c6b..0c631aacab82 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
@@ -193,7 +193,7 @@ class UserBroadcastDispatcher(
it.filter.hasAction(intent.action) &&
it.filter.matchCategories(intent.categories) == null }
?.forEach {
- it.handler.post {
+ it.executor.execute {
if (DEBUG) Log.w(TAG,
"[$index] Dispatching ${intent.action} to ${it.receiver}")
it.receiver.pendingResult = pendingResult
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 7cd29ea48199..d835ee1865bf 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -344,11 +344,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mSavedBubbleKeysPerUser = new SparseSetArray<>();
mCurrentUserId = mNotifUserManager.getCurrentUserId();
mNotifUserManager.addUserChangedListener(
- newUserId -> {
- saveBubbles(mCurrentUserId);
- mBubbleData.dismissAll(DISMISS_USER_CHANGED);
- restoreBubbles(newUserId);
- mCurrentUserId = newUserId;
+ new NotificationLockscreenUserManager.UserChangedListener() {
+ @Override
+ public void onUserChanged(int newUserId) {
+ BubbleController.this.saveBubbles(mCurrentUserId);
+ mBubbleData.dismissAll(DISMISS_USER_CHANGED);
+ BubbleController.this.restoreBubbles(newUserId);
+ mCurrentUserId = newUserId;
+ }
});
mUserCreatedBubbles = new HashSet<>();
@@ -743,9 +746,16 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
return !isAutogroupSummary;
} else {
// If it's not a user dismiss it's a cancel.
+ for (int i = 0; i < bubbleChildren.size(); i++) {
+ // First check if any of these are user-created (i.e. experimental bubbles)
+ if (mUserCreatedBubbles.contains(bubbleChildren.get(i).getKey())) {
+ // Experimental bubble! Intercept the removal.
+ return true;
+ }
+ }
+ // Not an experimental bubble, safe to remove.
mBubbleData.removeSuppressedSummary(groupKey);
-
- // Remove any associated bubble children.
+ // Remove any associated bubble children with the summary.
for (int i = 0; i < bubbleChildren.size(); i++) {
Bubble bubbleChild = bubbleChildren.get(i);
mBubbleData.notificationEntryRemoved(bubbleChild.getEntry(),
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 59d68bca93c3..6528f3762473 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -97,13 +97,11 @@ public class ExpandedAnimationController
private boolean mSpringingBubbleToTouch = false;
private int mExpandedViewPadding;
- private float mLauncherGridDiff;
public ExpandedAnimationController(Point displaySize, int expandedViewPadding,
int orientation) {
updateOrientation(orientation, displaySize);
mExpandedViewPadding = expandedViewPadding;
- mLauncherGridDiff = 30f;
}
/**
@@ -569,15 +567,7 @@ public class ExpandedAnimationController
* @return Space between bubbles in row above expanded view.
*/
private float getSpaceBetweenBubbles() {
- /**
- * Ordered left to right:
- * Screen edge
- * [mExpandedViewPadding]
- * Expanded view edge
- * [launcherGridDiff] --- arbitrary value until launcher exports widths
- * Launcher's app icon grid edge that we must match
- */
- final float rowMargins = (mExpandedViewPadding + mLauncherGridDiff) * 2;
+ final float rowMargins = mExpandedViewPadding * 2;
final float maxRowWidth = getWidthForDisplayingBubbles() - rowMargins;
final float totalBubbleWidth = mBubblesMaxRendered * mBubbleSizePx;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 8d10552332ba..53a23b89f943 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -20,7 +20,6 @@ import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
import android.app.INotificationManager;
import android.content.Context;
-import android.content.pm.IPackageManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
@@ -115,13 +114,6 @@ public class DependencyProvider {
/** */
@Singleton
@Provides
- public IPackageManager provideIPackageManager() {
- return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
- }
-
- /** */
- @Singleton
- @Provides
public LayoutInflater providerLayoutInflater(Context context) {
return LayoutInflater.from(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
index bb12b53fec4c..26337b1f24b1 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
@@ -27,6 +27,7 @@ import android.app.NotificationManager;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.pm.IPackageManager;
import android.content.res.Resources;
import android.hardware.SensorPrivacyManager;
import android.os.Handler;
@@ -123,6 +124,13 @@ public class SystemServicesModule {
return WindowManagerGlobal.getWindowManagerService();
}
+ /** */
+ @Singleton
+ @Provides
+ public IPackageManager provideIPackageManager() {
+ return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ }
+
@Singleton
@Provides
static KeyguardManager provideKeyguardManager(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index c9faf69cfd6f..4e887262659e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -91,7 +91,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
if (mDebuggable) {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_AOD_BRIGHTNESS);
- mBroadcastDispatcher.registerReceiver(this, filter, handler, UserHandle.ALL);
+ mBroadcastDispatcher.registerReceiverWithHandler(this, filter, handler, UserHandle.ALL);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 59ac329e1983..48750fa5e769 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -233,7 +233,7 @@ public class PowerUI extends SystemUI implements CommandQueue.Callbacks {
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_USER_SWITCHED);
- mBroadcastDispatcher.registerReceiver(this, filter, mHandler);
+ mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
index f710f7fc47e2..f66a1ece1868 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
@@ -68,7 +68,7 @@ class DoubleLineTileLayout(context: Context) : ViewGroup(context), QSPanel.QSTil
override fun updateResources(): Boolean {
with(mContext.resources) {
smallTileSize = getDimensionPixelSize(R.dimen.qs_quick_tile_size)
- cellMarginHorizontal = getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal)
+ cellMarginHorizontal = getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) / 2
cellMarginVertical = getDimensionPixelSize(R.dimen.new_qs_vertical_margin)
}
requestLayout()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index f7e4c794836e..1077834e7146 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -124,7 +124,7 @@ public class QSMediaPlayer {
}
}
});
- btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_replay));
+ btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play));
btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
btn.setVisibility(View.VISIBLE);
@@ -199,8 +199,7 @@ public class QSMediaPlayer {
List<ResolveInfo> info = pm.queryBroadcastReceiversAsUser(it, 0, mContext.getUser());
if (info != null) {
for (ResolveInfo inf : info) {
- if (inf.activityInfo.packageName.equals(notif.contentIntent.getCreatorPackage())) {
- Log.d(TAG, "Found receiver for package: " + inf);
+ if (inf.activityInfo.packageName.equals(mController.getPackageName())) {
mRecvComponent = inf.getComponentInfo().getComponentName();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 51e352b30019..35b8312ba25c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -184,21 +184,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
// Add media carousel
if (useQsMediaPlayer(context)) {
- HorizontalScrollView mediaScrollView = new HorizontalScrollView(mContext);
- mediaScrollView.setHorizontalScrollBarEnabled(false);
- int playerHeight = (int) getResources().getDimension(R.dimen.qs_media_height);
- int padding = (int) getResources().getDimension(R.dimen.qs_media_padding);
- LayoutParams lpView = new LayoutParams(LayoutParams.MATCH_PARENT, playerHeight);
- lpView.setMarginStart(padding);
- lpView.setMarginEnd(padding);
- addView(mediaScrollView, lpView);
-
- LayoutParams lpCarousel = new LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.WRAP_CONTENT);
- mMediaCarousel = new LinearLayout(mContext);
- mMediaCarousel.setOrientation(LinearLayout.HORIZONTAL);
- mediaScrollView.addView(mMediaCarousel, lpCarousel);
- mediaScrollView.setVisibility(View.GONE);
+ HorizontalScrollView mediaScrollView = (HorizontalScrollView) LayoutInflater.from(
+ mContext).inflate(R.layout.media_carousel, this, false);
+ mMediaCarousel = mediaScrollView.findViewById(R.id.media_carousel);
+ addView(mediaScrollView);
} else {
mMediaCarousel = null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
index d40e25064352..cec1cb2fb53b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
@@ -106,7 +106,7 @@ public class QuickQSMediaPlayer {
}
}
});
- btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_replay));
+ btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play));
btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
btn.setVisibility(View.VISIBLE);
}
@@ -136,14 +136,25 @@ public class QuickQSMediaPlayer {
* @param actionsContainer a LinearLayout containing the media action buttons
* @param actionsToShow indices of which actions to display in the mini player
* (max 3: Notification.MediaStyle.MAX_MEDIA_BUTTONS_IN_COMPACT)
+ * @param contentIntent Intent to send when user taps on the view
*/
public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
- View actionsContainer, int[] actionsToShow) {
- Log.d(TAG, "Setting media session: " + token);
+ View actionsContainer, int[] actionsToShow, PendingIntent contentIntent) {
mToken = token;
mForegroundColor = iconColor;
mBackgroundColor = bgColor;
- mController = new MediaController(mContext, token);
+
+ String oldPackage = "";
+ if (mController != null) {
+ oldPackage = mController.getPackageName();
+ }
+ MediaController controller = new MediaController(mContext, token);
+ boolean samePlayer = mToken.equals(token) && oldPackage.equals(controller.getPackageName());
+ if (mController != null && !samePlayer && !isPlaying(controller)) {
+ // Only update if this is a different session and currently playing
+ return;
+ }
+ mController = controller;
MediaMetadata mMediaMetadata = mController.getMetadata();
// Try to find a receiver for the media button that matches this app
@@ -153,7 +164,6 @@ public class QuickQSMediaPlayer {
if (info != null) {
for (ResolveInfo inf : info) {
if (inf.activityInfo.packageName.equals(mController.getPackageName())) {
- Log.d(TAG, "Found receiver for package: " + inf);
mRecvComponent = inf.getComponentInfo().getComponentName();
}
}
@@ -165,6 +175,16 @@ public class QuickQSMediaPlayer {
return;
}
+ // Action
+ mMediaNotifView.setOnClickListener(v -> {
+ try {
+ contentIntent.send();
+ mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Pending intent was canceled: " + e.getMessage());
+ }
+ });
+
// Album art
addAlbumArtBackground(mMediaMetadata, mBackgroundColor);
@@ -237,12 +257,12 @@ public class QuickQSMediaPlayer {
* Check whether the media controlled by this player is currently playing
* @return whether it is playing, or false if no controller information
*/
- public boolean isPlaying() {
- if (mController == null) {
+ public boolean isPlaying(MediaController controller) {
+ if (controller == null) {
return false;
}
- PlaybackState state = mController.getPlaybackState();
+ PlaybackState state = controller.getPlaybackState();
if (state == null) {
return false;
}
@@ -261,12 +281,11 @@ public class QuickQSMediaPlayer {
private void addAlbumArtBackground(MediaMetadata metadata, int bgColor) {
Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
- if (albumArt != null) {
- Rect bounds = new Rect();
- mMediaNotifView.getBoundsOnScreen(bounds);
- int width = bounds.width();
- int height = bounds.height();
-
+ Rect bounds = new Rect();
+ mMediaNotifView.getBoundsOnScreen(bounds);
+ int width = bounds.width();
+ int height = bounds.height();
+ if (albumArt != null && width > 0 && height > 0) {
Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
Bitmap scaled = scaleBitmap(original, width, height);
Canvas canvas = new Canvas(scaled);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index db52e7d37a92..b05d4fdf7db7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -85,20 +85,19 @@ public class QuickQSPanel extends QSPanel {
mHorizontalLinearLayout.setClipChildren(false);
mHorizontalLinearLayout.setClipToPadding(false);
- LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
-
mTileLayout = new DoubleLineTileLayout(context);
mMediaTileLayout = mTileLayout;
mRegularTileLayout = new HeaderTileLayout(context);
+ LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
lp.setMarginEnd(10);
lp.setMarginStart(0);
mHorizontalLinearLayout.addView((View) mTileLayout, lp);
mMediaPlayer = new QuickQSMediaPlayer(mContext, mHorizontalLinearLayout);
-
- lp.setMarginEnd(0);
- lp.setMarginStart(10);
- mHorizontalLinearLayout.addView(mMediaPlayer.getView(), lp);
+ LayoutParams lp2 = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
+ lp2.setMarginEnd(0);
+ lp2.setMarginStart(25);
+ mHorizontalLinearLayout.addView(mMediaPlayer.getView(), lp2);
sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index bbff117c6f81..ad79cadcc12d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -322,7 +322,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
try {
mUserReceiverRegistered.set(true);
- mBroadcastDispatcher.registerReceiver(this, filter, mHandler, mUser);
+ mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler, mUser);
} catch (Exception ex) {
mUserReceiverRegistered.set(false);
Log.e(TAG, "Could not register unlock receiver", ex);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
index 077d2602e43f..9599d77bf65a 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
@@ -98,7 +98,8 @@ public abstract class CurrentUserTracker {
if (!mReceiverRegistered) {
mCurrentUserId = ActivityManager.getCurrentUser();
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
- mBroadcastDispatcher.registerReceiver(this, filter, null, UserHandle.ALL);
+ mBroadcastDispatcher.registerReceiver(this, filter, null,
+ UserHandle.ALL);
mReceiverRegistered = true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 2005d794c9d3..ac05c53c38dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -40,7 +40,7 @@ import javax.inject.Singleton;
* You will probably need to restart systemui for the changes to be picked up:
*
* {@code
- * $ adb shell am crash com.android.systemui
+ * $ adb shell am restart com.android.systemui
* }
*/
@Singleton
@@ -59,6 +59,11 @@ public class FeatureFlags {
return getDeviceConfigFlag("notification.newpipeline.enabled", false);
}
+ public boolean isNewNotifPipelineRenderingEnabled() {
+ return isNewNotifPipelineEnabled()
+ && getDeviceConfigFlag("notification.newpipeline.rendering", false);
+ }
+
private void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
synchronized (mCachedDeviceConfigFlags) {
for (String key : properties.getKeyset()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index ff4ce9492082..ebf7c2d58c2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -49,6 +49,12 @@ public interface NotificationLockscreenUserManager {
/** Adds a listener to be notified when the current user changes. */
void addUserChangedListener(UserChangedListener listener);
+ /**
+ * Removes a listener previously registered with
+ * {@link #addUserChangedListener(UserChangedListener)}
+ */
+ void removeUserChangedListener(UserChangedListener listener);
+
SparseArray<UserInfo> getCurrentProfiles();
void setLockscreenPublicMode(boolean isProfilePublic, int userId);
@@ -79,6 +85,7 @@ public interface NotificationLockscreenUserManager {
/** Notified when the current user changes. */
interface UserChangedListener {
- void onUserChanged(int userId);
+ default void onUserChanged(int userId) {}
+ default void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 2e369b3295b8..976531d8b49d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -117,51 +117,63 @@ public class NotificationLockscreenUserManagerImpl implements
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- updateCurrentProfilesCache();
- Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
-
- updateLockscreenNotificationSetting();
- updatePublicMode();
- // The filtering needs to happen before the update call below in order to make sure
- // the presenter has the updated notifications from the new user
- getEntryManager().reapplyFilterAndSort("user switched");
- mPresenter.onUserSwitched(mCurrentUserId);
-
- for (UserChangedListener listener : mListeners) {
- listener.onUserChanged(mCurrentUserId);
- }
- } else if (Intent.ACTION_USER_ADDED.equals(action)) {
- updateCurrentProfilesCache();
- } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
- // Start the overview connection to the launcher service
- Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
- } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
- final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
- final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
- if (intentSender != null) {
- try {
- mContext.startIntentSender(intentSender, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
+ switch (action) {
+ case Intent.ACTION_USER_SWITCHED:
+ mCurrentUserId = intent.getIntExtra(
+ Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+ updateCurrentProfilesCache();
+
+ Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+
+ updateLockscreenNotificationSetting();
+ updatePublicMode();
+ // The filtering needs to happen before the update call below in order to
+ // make sure
+ // the presenter has the updated notifications from the new user
+ getEntryManager().reapplyFilterAndSort("user switched");
+ mPresenter.onUserSwitched(mCurrentUserId);
+
+ for (UserChangedListener listener : mListeners) {
+ listener.onUserChanged(mCurrentUserId);
}
- }
- if (notificationKey != null) {
- NotificationEntry entry =
- getEntryManager().getActiveNotificationUnfiltered(notificationKey);
- final int count = getEntryManager().getActiveNotificationsCount();
- final int rank = entry != null ? entry.getRanking().getRank() : 0;
- NotificationVisibility.NotificationLocation location =
- NotificationLogger.getNotificationLocation(entry);
- final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
- rank, count, true, location);
- try {
- mBarService.onNotificationClick(notificationKey, nv);
- } catch (RemoteException exception) {
- /* ignore */
+ break;
+ case Intent.ACTION_USER_ADDED:
+ case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
+ case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
+ updateCurrentProfilesCache();
+ break;
+ case Intent.ACTION_USER_UNLOCKED:
+ // Start the overview connection to the launcher service
+ Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
+ break;
+ case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION:
+ final IntentSender intentSender = intent.getParcelableExtra(
+ Intent.EXTRA_INTENT);
+ final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
+ if (intentSender != null) {
+ try {
+ mContext.startIntentSender(intentSender, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ /* ignore */
+ }
}
- }
+ if (notificationKey != null) {
+ NotificationEntry entry =
+ getEntryManager().getActiveNotificationUnfiltered(notificationKey);
+ final int count = getEntryManager().getActiveNotificationsCount();
+ final int rank = entry != null ? entry.getRanking().getRank() : 0;
+ NotificationVisibility.NotificationLocation location =
+ NotificationLogger.getNotificationLocation(entry);
+ final NotificationVisibility nv = NotificationVisibility.obtain(
+ notificationKey,
+ rank, count, true, location);
+ try {
+ mBarService.onNotificationClick(notificationKey, nv);
+ } catch (RemoteException exception) {
+ /* ignore */
+ }
+ }
+ break;
}
}
};
@@ -266,6 +278,8 @@ public class NotificationLockscreenUserManagerImpl implements
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
mBroadcastDispatcher.registerReceiver(mBaseBroadcastReceiver, filter);
IntentFilter internalFilter = new IntentFilter();
@@ -489,6 +503,11 @@ public class NotificationLockscreenUserManagerImpl implements
}
}
}
+ mMainHandler.post(() -> {
+ for (UserChangedListener listener : mListeners) {
+ listener.onCurrentProfilesChanged(mCurrentProfiles);
+ }
+ });
}
public boolean isAnyProfilePublicMode() {
@@ -555,6 +574,11 @@ public class NotificationLockscreenUserManagerImpl implements
mListeners.add(listener);
}
+ @Override
+ public void removeUserChangedListener(UserChangedListener listener) {
+ mListeners.remove(listener);
+ }
+
// public void updatePublicMode() {
// //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
// // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 33d97a150048..a2578ab3cfa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -34,6 +34,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
@@ -131,6 +132,7 @@ public class NotificationEntryManager implements
private final KeyguardEnvironment mKeyguardEnvironment;
private final NotificationGroupManager mGroupManager;
private final NotificationRankingManager mRankingManager;
+ private final FeatureFlags mFeatureFlags;
private NotificationPresenter mPresenter;
private RankingMap mLatestRankingMap;
@@ -170,11 +172,13 @@ public class NotificationEntryManager implements
NotifLog notifLog,
NotificationGroupManager groupManager,
NotificationRankingManager rankingManager,
- KeyguardEnvironment keyguardEnvironment) {
+ KeyguardEnvironment keyguardEnvironment,
+ FeatureFlags featureFlags) {
mNotifLog = notifLog;
mGroupManager = groupManager;
mRankingManager = rankingManager;
mKeyguardEnvironment = keyguardEnvironment;
+ mFeatureFlags = featureFlags;
}
/** Once called, the NEM will start processing notification events from system server. */
@@ -290,6 +294,10 @@ public class NotificationEntryManager implements
* WARNING: this will call back into us. Don't hold any locks.
*/
@Override
+ public void handleInflationException(NotificationEntry n, Exception e) {
+ handleInflationException(n.getSbn(), e);
+ }
+
public void handleInflationException(StatusBarNotification n, Exception e) {
removeNotificationInternal(
n.getKey(), null, null, true /* forceRemove */, false /* removedByUser */,
@@ -529,9 +537,12 @@ public class NotificationEntryManager implements
NotificationEntry entry = new NotificationEntry(notification, ranking);
Dependency.get(LeakDetector.class).trackInstance(entry);
+
// Construct the expanded view.
- requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
- REASON_CANCEL));
+ if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
+ REASON_CANCEL));
+ }
abortExistingInflation(key, "addNotification");
mPendingNotifications.put(key, entry);
@@ -574,8 +585,11 @@ public class NotificationEntryManager implements
listener.onPreEntryUpdated(entry);
}
- requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
- REASON_CANCEL));
+ if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
+ REASON_CANCEL));
+ }
+
updateNotifications("updateNotificationInternal");
if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
index ec1efa58868e..b960b42b3e2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
@@ -24,7 +24,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
-import java.util.Objects;
/**
* Represents a set of grouped notifications. The final notification list is usually a mix of
@@ -58,22 +57,15 @@ public class GroupEntry extends ListEntry {
@VisibleForTesting
public void setSummary(@Nullable NotificationEntry summary) {
- if (!Objects.equals(mSummary, summary)) {
- mSummary = summary;
- onGroupingUpdated();
- }
+ mSummary = summary;
}
void clearChildren() {
- if (mChildren.size() != 0) {
- mChildren.clear();
- onGroupingUpdated();
- }
+ mChildren.clear();
}
void addChild(NotificationEntry child) {
mChildren.add(child);
- onGroupingUpdated();
}
void sortChildren(Comparator<? super NotificationEntry> c) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index 601b3e053e8e..dc68c4bdba78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -18,38 +18,20 @@ package com.android.systemui.statusbar.notification.collection;
import android.annotation.Nullable;
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.notification.collection.provider.DerivedMember;
-import com.android.systemui.statusbar.notification.collection.provider.IsHighPriorityProvider;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
/**
* Abstract superclass for top-level entries, i.e. things that can appear in the final notification
* list shown to users. In practice, this means either GroupEntries or NotificationEntries.
*/
public abstract class ListEntry {
private final String mKey;
- private final IsHighPriorityProvider mIsHighPriorityProvider = new IsHighPriorityProvider();
- private final List<DerivedMember> mDerivedMemberList = Arrays.asList(mIsHighPriorityProvider);
@Nullable private GroupEntry mParent;
@Nullable private GroupEntry mPreviousParent;
private int mSection;
int mFirstAddedIteration = -1;
- // TODO: (b/145659174) remove groupManager when moving to NewNotifPipeline. Logic
- // replaced in GroupEntry and NotifListBuilderImpl
- private final NotificationGroupManager mGroupManager;
-
ListEntry(String key) {
mKey = key;
-
- // TODO: (b/145659174) remove
- mGroupManager = Dependency.get(NotificationGroupManager.class);
}
public String getKey() {
@@ -68,11 +50,7 @@ public abstract class ListEntry {
}
void setParent(@Nullable GroupEntry parent) {
- if (!Objects.equals(mParent, parent)) {
- invalidateParent();
- mParent = parent;
- onGroupingUpdated();
- }
+ mParent = parent;
}
@Nullable public GroupEntry getPreviousParent() {
@@ -91,58 +69,4 @@ public abstract class ListEntry {
void setSection(int section) {
mSection = section;
}
-
- /**
- * Resets the cached values of DerivedMembers.
- */
- void invalidateDerivedMembers() {
- for (int i = 0; i < mDerivedMemberList.size(); i++) {
- mDerivedMemberList.get(i).invalidate();
- }
- }
-
- /**
- * Whether this notification is shown to the user as a high priority notification: visible on
- * the lock screen/status bar and in the top section in the shade.
- */
- public boolean isHighPriority() {
- return mIsHighPriorityProvider.get(this);
- }
-
- private void invalidateParent() {
- // invalidate our parent (GroupEntry) since DerivedMembers may be dependent on children
- if (getParent() != null) {
- getParent().invalidateDerivedMembers();
- }
-
- // TODO: (b/145659174) remove
- final NotificationEntry notifEntry = getRepresentativeEntry();
- if (notifEntry != null && mGroupManager.isGroupChild(notifEntry.getSbn())) {
- NotificationEntry summary = mGroupManager.getLogicalGroupSummary(notifEntry.getSbn());
- if (summary != null) {
- summary.invalidateDerivedMembers();
- }
- }
- }
-
- void onGroupingUpdated() {
- for (int i = 0; i < mDerivedMemberList.size(); i++) {
- mDerivedMemberList.get(i).onGroupingUpdated();
- }
- invalidateParent();
- }
-
- void onSbnUpdated() {
- for (int i = 0; i < mDerivedMemberList.size(); i++) {
- mDerivedMemberList.get(i).onSbnUpdated();
- }
- invalidateParent();
- }
-
- void onRankingUpdated() {
- for (int i = 0; i < mDerivedMemberList.size(); i++) {
- mDerivedMemberList.get(i).onRankingUpdated();
- }
- invalidateParent();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 873cdbc91d25..856b75b7e36c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -299,6 +299,14 @@ public class NotifCollection {
if (!isLifetimeExtended(entry)) {
Ranking ranking = requireRanking(rankingMap, entry.getKey());
entry.setRanking(ranking);
+
+ // TODO: (b/145659174) update the sbn's overrideGroupKey in
+ // NotificationEntry.setRanking instead of here once we fully migrate to the
+ // NewNotifPipeline
+ final String newOverrideGroupKey = ranking.getOverrideGroupKey();
+ if (!Objects.equals(entry.getSbn().getOverrideGroupKey(), newOverrideGroupKey)) {
+ entry.getSbn().setOverrideGroupKey(newOverrideGroupKey);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java
new file mode 100644
index 000000000000..fc04827a9d6a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+import com.android.systemui.statusbar.notification.collection.coordinator.PreparationCoordinator;
+
+/**
+ * Used by the {@link PreparationCoordinator}. When notifications are added or updated, the
+ * NotifInflater is asked to (re)inflated and prepare their views. This inflation occurs off the
+ * main thread. When the inflation is finished, NotifInflater will trigger its InflationCallback.
+ */
+public interface NotifInflater {
+
+ /**
+ * Callback used when inflation is finished.
+ */
+ void setInflationCallback(InflationCallback callback);
+
+ /**
+ * Called to rebind the entry's views.
+ */
+ void rebindViews(NotificationEntry entry);
+
+ /**
+ * Called to inflate the views of an entry. Views are not considered inflated until all of its
+ * views are bound. Once all views are inflated, the InflationCallback is triggered.
+ */
+ void inflateViews(NotificationEntry entry);
+
+ /**
+ * Request to stop the inflation of an entry. For example, called when a notification is
+ * removed and no longer needs to be inflated.
+ */
+ void abortInflation(NotificationEntry entry);
+
+ /**
+ * Callback once all the views are inflated and bound for a given NotificationEntry.
+ */
+ interface InflationCallback {
+ void onInflationFinished(NotificationEntry entry);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
new file mode 100644
index 000000000000..0d175574f16b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
+
+import android.os.RemoteException;
+import android.service.notification.NotificationStats;
+import android.service.notification.StatusBarNotification;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Handles notification inflating, rebinding, and inflation aborting.
+ *
+ * Currently a wrapper for NotificationRowBinderImpl.
+ */
+@Singleton
+public class NotifInflaterImpl implements NotifInflater {
+
+ private final IStatusBarService mStatusBarService;
+ private final NotifCollection mNotifCollection;
+
+ private NotificationRowBinderImpl mNotificationRowBinder;
+ private InflationCallback mExternalInflationCallback;
+
+ @Inject
+ public NotifInflaterImpl(
+ IStatusBarService statusBarService,
+ NotifCollection notifCollection) {
+ mStatusBarService = statusBarService;
+ mNotifCollection = notifCollection;
+ }
+
+ /**
+ * Attaches the row binder for inflation.
+ */
+ public void setRowBinder(NotificationRowBinderImpl rowBinder) {
+ mNotificationRowBinder = rowBinder;
+ mNotificationRowBinder.setInflationCallback(mInflationCallback);
+ }
+
+ @Override
+ public void setInflationCallback(InflationCallback callback) {
+ mExternalInflationCallback = callback;
+ }
+
+ @Override
+ public void rebindViews(NotificationEntry entry) {
+ inflateViews(entry);
+ }
+
+ /**
+ * Called to inflate the views of an entry. Views are not considered inflated until all of its
+ * views are bound.
+ */
+ @Override
+ public void inflateViews(NotificationEntry entry) {
+ try {
+ entry.setHasInflationError(false);
+ requireBinder().inflateViews(entry, getDismissCallback(entry));
+ } catch (InflationException e) {
+ // logged in mInflationCallback.handleInflationException
+ }
+ }
+
+ @Override
+ public void abortInflation(NotificationEntry entry) {
+ entry.abortTask();
+ }
+
+ private Runnable getDismissCallback(NotificationEntry entry) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
+ /**
+ * TODO: determine dismissal surface (ie: shade / headsup / aod)
+ * see {@link NotificationLogger#logNotificationClear}
+ */
+ mNotifCollection.dismissNotification(
+ entry,
+ 0,
+ new DismissedByUserStats(
+ dismissalSurface,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(entry.getKey(),
+ entry.getRanking().getRank(),
+ mNotifCollection.getNotifs().size(),
+ true,
+ NotificationLogger.getNotificationLocation(entry))
+ ));
+ }
+ };
+ }
+
+ private NotificationRowBinderImpl requireBinder() {
+ if (mNotificationRowBinder == null) {
+ throw new RuntimeException("NotificationRowBinder must be attached before using "
+ + "NotifInflaterImpl.");
+ }
+ return mNotificationRowBinder;
+ }
+
+ private final NotificationContentInflater.InflationCallback mInflationCallback =
+ new NotificationContentInflater.InflationCallback() {
+ @Override
+ public void handleInflationException(
+ NotificationEntry entry,
+ Exception e) {
+ entry.setHasInflationError(true);
+ try {
+ final StatusBarNotification sbn = entry.getSbn();
+ // report notification inflation errors back up
+ // to notification delegates
+ mStatusBarService.onNotificationError(
+ sbn.getPackageName(),
+ sbn.getTag(),
+ sbn.getId(),
+ sbn.getUid(),
+ sbn.getInitialPid(),
+ e.getMessage(),
+ sbn.getUserId());
+ } catch (RemoteException ex) {
+ }
+ }
+
+ @Override
+ public void onAsyncInflationFinished(
+ NotificationEntry entry,
+ int inflatedFlags) {
+ if (mExternalInflationCallback != null) {
+ mExternalInflationCallback.onInflationFinished(entry);
+ }
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 4f4fb240162d..7301fe1df398 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -102,6 +102,9 @@ public final class NotificationEntry extends ListEntry {
/** If this was a group child that was promoted to the top level, then who did the promoting. */
@Nullable NotifPromoter mNotifPromoter;
+ /** If this notification had an issue with inflating. Only used with the NewNotifPipeline **/
+ private boolean mHasInflationError;
+
/*
* Old members
@@ -201,11 +204,8 @@ public final class NotificationEntry extends ListEntry {
+ " doesn't match existing key " + mKey);
}
- if (!Objects.equals(mSbn, sbn)) {
- mSbn = sbn;
- mBubbleMetadata = mSbn.getNotification().getBubbleMetadata();
- onSbnUpdated();
- }
+ mSbn = sbn;
+ mBubbleMetadata = mSbn.getNotification().getBubbleMetadata();
}
/**
@@ -230,10 +230,7 @@ public final class NotificationEntry extends ListEntry {
+ " doesn't match existing key " + mKey);
}
- if (!Objects.equals(mRanking, ranking)) {
- mRanking = ranking;
- onRankingUpdated();
- }
+ mRanking = ranking;
}
/*
@@ -576,6 +573,18 @@ public final class NotificationEntry extends ListEntry {
remoteInputTextWhenReset = null;
}
+ void setHasInflationError(boolean hasError) {
+ mHasInflationError = hasError;
+ }
+
+ /**
+ * Whether this notification had an error when attempting to inflate. This is only used in
+ * the NewNotifPipeline
+ */
+ public boolean hasInflationError() {
+ return mHasInflationError;
+ }
+
public void setHasSentReply() {
hasSentReply = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 7010943559ba..3bbd722517f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -24,6 +24,7 @@ import android.service.notification.StatusBarNotification
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.notification.NotificationFilter
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.logging.NotifEvent
import com.android.systemui.statusbar.notification.logging.NotifLog
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
@@ -54,7 +55,8 @@ open class NotificationRankingManager @Inject constructor(
private val notifFilter: NotificationFilter,
private val notifLog: NotifLog,
sectionsFeatureManager: NotificationSectionsFeatureManager,
- private val peopleNotificationIdentifier: PeopleNotificationIdentifier
+ private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
+ private val highPriorityProvider: HighPriorityProvider
) {
var rankingMap: RankingMap? = null
@@ -81,6 +83,9 @@ open class NotificationRankingManager @Inject constructor(
val aHeadsUp = a.isRowHeadsUp
val bHeadsUp = b.isRowHeadsUp
+ val aIsHighPriority = a.isHighPriority()
+ val bIsHighPriority = b.isHighPriority()
+
when {
usePeopleFiltering && aIsPeople != bIsPeople -> if (aIsPeople) -1 else 1
aHeadsUp != bHeadsUp -> if (aHeadsUp) -1 else 1
@@ -90,8 +95,8 @@ open class NotificationRankingManager @Inject constructor(
aMedia != bMedia -> if (aMedia) -1 else 1
// Upsort PRIORITY_MAX system notifications
aSystemMax != bSystemMax -> if (aSystemMax) -1 else 1
- a.isHighPriority != b.isHighPriority ->
- -1 * a.isHighPriority.compareTo(b.isHighPriority)
+ aIsHighPriority != bIsHighPriority ->
+ -1 * aIsHighPriority.compareTo(bIsHighPriority)
aRank != bRank -> aRank - bRank
else -> nb.notification.`when`.compareTo(na.notification.`when`)
}
@@ -154,7 +159,7 @@ open class NotificationRankingManager @Inject constructor(
) {
if (usePeopleFiltering && entry.isPeopleNotification()) {
entry.bucket = BUCKET_PEOPLE
- } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority) {
+ } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority()) {
entry.bucket = BUCKET_ALERTING
} else {
entry.bucket = BUCKET_SILENT
@@ -178,10 +183,6 @@ open class NotificationRankingManager @Inject constructor(
// TODO: notify group manager here?
groupManager.onEntryUpdated(entry, oldSbn)
}
-
- // TODO: (b/145659174) remove after moving to new NotifPipeline
- // (should be able to remove all groupManager code post-migration)
- entry.invalidateDerivedMembers()
}
}
}
@@ -191,6 +192,9 @@ open class NotificationRankingManager @Inject constructor(
sbn.isPeopleNotification()
private fun StatusBarNotification.isPeopleNotification() =
peopleNotificationIdentifier.isPeopleNotification(this)
+
+ private fun NotificationEntry.isHighPriority() =
+ highPriorityProvider.isHighPriority(this)
}
// Convenience functions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 6c93618e5395..6dc647d33046 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -109,16 +109,18 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
public void setUpWithPresenter(NotificationPresenter presenter,
NotificationListContainer listContainer,
HeadsUpManager headsUpManager,
- NotificationContentInflater.InflationCallback inflationCallback,
BindRowCallback bindRowCallback) {
mPresenter = presenter;
mListContainer = listContainer;
mHeadsUpManager = headsUpManager;
- mInflationCallback = inflationCallback;
mBindRowCallback = bindRowCallback;
mOnAppOpsClickListener = mGutsManager::openGuts;
}
+ public void setInflationCallback(NotificationContentInflater.InflationCallback callback) {
+ mInflationCallback = callback;
+ }
+
public void setNotificationClicker(NotificationClicker clicker) {
mNotificationClicker = clicker;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 9312c2260d46..db107f531e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import javax.inject.Inject;
@@ -62,6 +63,7 @@ public class KeyguardCoordinator implements Coordinator {
private final BroadcastDispatcher mBroadcastDispatcher;
private final StatusBarStateController mStatusBarStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final HighPriorityProvider mHighPriorityProvider;
@Inject
public KeyguardCoordinator(
@@ -71,15 +73,16 @@ public class KeyguardCoordinator implements Coordinator {
NotificationLockscreenUserManager lockscreenUserManager,
BroadcastDispatcher broadcastDispatcher,
StatusBarStateController statusBarStateController,
- KeyguardUpdateMonitor keyguardUpdateMonitor) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ HighPriorityProvider highPriorityProvider) {
mContext = context;
mMainHandler = mainThreadHandler;
mKeyguardStateController = keyguardStateController;
mLockscreenUserManager = lockscreenUserManager;
-
mBroadcastDispatcher = broadcastDispatcher;
mStatusBarStateController = statusBarStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mHighPriorityProvider = highPriorityProvider;
}
@Override
@@ -151,7 +154,7 @@ public class KeyguardCoordinator implements Coordinator {
}
if (NotificationUtils.useNewInterruptionModel(mContext)
&& hideSilentNotificationsOnLockscreen()) {
- return entry.isHighPriority();
+ return mHighPriorityProvider.isHighPriority(entry);
} else {
return entry.getRepresentativeEntry() != null
&& !entry.getRepresentativeEntry().getRanking().isAmbient();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 132471933bb2..eeb54abf92b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
@@ -45,14 +46,19 @@ public class NotifCoordinators implements Dumpable {
*/
@Inject
public NotifCoordinators(
+ FeatureFlags featureFlags,
KeyguardCoordinator keyguardCoordinator,
RankingCoordinator rankingCoordinator,
ForegroundCoordinator foregroundCoordinator,
- DeviceProvisionedCoordinator deviceProvisionedCoordinator) {
+ DeviceProvisionedCoordinator deviceProvisionedCoordinator,
+ PreparationCoordinator preparationCoordinator) {
mCoordinators.add(keyguardCoordinator);
mCoordinators.add(rankingCoordinator);
mCoordinators.add(foregroundCoordinator);
mCoordinators.add(deviceProvisionedCoordinator);
+ if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mCoordinators.add(preparationCoordinator);
+ }
// TODO: add new Coordinators here! (b/145134683, b/112656837)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
new file mode 100644
index 000000000000..a14f0e1cf631
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.NotifInflater;
+import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.logging.NotifEvent;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Kicks off notification inflation and view rebinding when a notification is added or updated.
+ * Aborts inflation when a notification is removed.
+ *
+ * If a notification is not done inflating, this coordinator will filter the notification out
+ * from the NotifListBuilder.
+ */
+@Singleton
+public class PreparationCoordinator implements Coordinator {
+ private static final String TAG = "PreparationCoordinator";
+
+ private final NotifLog mNotifLog;
+ private final NotifInflater mNotifInflater;
+ private final List<NotificationEntry> mPendingNotifications = new ArrayList<>();
+
+ @Inject
+ public PreparationCoordinator(NotifLog notifLog, NotifInflaterImpl notifInflater) {
+ mNotifLog = notifLog;
+ mNotifInflater = notifInflater;
+ mNotifInflater.setInflationCallback(mInflationCallback);
+ }
+
+ @Override
+ public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+ notifCollection.addCollectionListener(mNotifCollectionListener);
+ notifListBuilder.addPreRenderFilter(mNotifInflationErrorFilter);
+ notifListBuilder.addPreRenderFilter(mNotifInflatingFilter);
+ }
+
+ private final NotifCollectionListener mNotifCollectionListener = new NotifCollectionListener() {
+ @Override
+ public void onEntryAdded(NotificationEntry entry) {
+ inflateEntry(entry, "entryAdded");
+ }
+
+ @Override
+ public void onEntryUpdated(NotificationEntry entry) {
+ rebind(entry, "entryUpdated");
+ }
+
+ @Override
+ public void onEntryRemoved(NotificationEntry entry, int reason, boolean removedByUser) {
+ abortInflation(entry, "entryRemoved reason=" + reason);
+ }
+ };
+
+ private final NotifFilter mNotifInflationErrorFilter = new NotifFilter(
+ TAG + "InflationError") {
+ /**
+ * Filters out notifications that threw an error when attempting to inflate.
+ */
+ @Override
+ public boolean shouldFilterOut(NotificationEntry entry, long now) {
+ if (entry.hasInflationError()) {
+ mPendingNotifications.remove(entry);
+ return true;
+ }
+ return false;
+ }
+ };
+
+ private final NotifFilter mNotifInflatingFilter = new NotifFilter(TAG + "Inflating") {
+ /**
+ * Filters out notifications that haven't been inflated yet
+ */
+ @Override
+ public boolean shouldFilterOut(NotificationEntry entry, long now) {
+ return mPendingNotifications.contains(entry);
+ }
+ };
+
+ private final NotifInflater.InflationCallback mInflationCallback =
+ new NotifInflater.InflationCallback() {
+ @Override
+ public void onInflationFinished(NotificationEntry entry) {
+ mNotifLog.log(NotifEvent.INFLATED, entry);
+ mPendingNotifications.remove(entry);
+ mNotifInflatingFilter.invalidateList();
+ }
+ };
+
+ private void inflateEntry(NotificationEntry entry, String reason) {
+ abortInflation(entry, reason);
+ mPendingNotifications.add(entry);
+ mNotifInflater.inflateViews(entry);
+ }
+
+ private void rebind(NotificationEntry entry, String reason) {
+ mNotifInflater.rebindViews(entry);
+ }
+
+ private void abortInflation(NotificationEntry entry, String reason) {
+ mNotifLog.log(NotifEvent.INFLATION_ABORTED, reason);
+ entry.abortTask();
+ mPendingNotifications.remove(entry);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
index 5e0bd4fdcf23..8d3d0ff43deb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
@@ -20,9 +20,12 @@ import android.util.Log;
import com.android.systemui.DumpController;
import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators;
import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
@@ -41,7 +44,9 @@ public class NewNotifPipeline implements Dumpable {
private final NotifCollection mNotifCollection;
private final NotifListBuilderImpl mNotifPipeline;
private final NotifCoordinators mNotifPluggableCoordinators;
+ private final NotifInflaterImpl mNotifInflater;
private final DumpController mDumpController;
+ private final FeatureFlags mFeatureFlags;
private final FakePipelineConsumer mFakePipelineConsumer = new FakePipelineConsumer();
@@ -51,20 +56,30 @@ public class NewNotifPipeline implements Dumpable {
NotifCollection notifCollection,
NotifListBuilderImpl notifPipeline,
NotifCoordinators notifCoordinators,
- DumpController dumpController) {
+ NotifInflaterImpl notifInflater,
+ DumpController dumpController,
+ FeatureFlags featureFlags) {
mGroupCoalescer = groupCoalescer;
mNotifCollection = notifCollection;
mNotifPipeline = notifPipeline;
mNotifPluggableCoordinators = notifCoordinators;
mDumpController = dumpController;
+ mNotifInflater = notifInflater;
+ mFeatureFlags = featureFlags;
}
/** Hooks the new pipeline up to NotificationManager */
public void initialize(
- NotificationListener notificationService) {
+ NotificationListener notificationService,
+ NotificationRowBinderImpl rowBinder) {
mDumpController.registerDumpable("NotifPipeline", this);
+ // Setup inflation
+ if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mNotifInflater.setRowBinder(rowBinder);
+ }
+
// Wire up coordinators
mFakePipelineConsumer.attach(mNotifPipeline);
mNotifPluggableCoordinators.attach(mNotifCollection, mNotifPipeline);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DerivedMember.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DerivedMember.java
deleted file mode 100644
index 815e6f7eaa46..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DerivedMember.java
+++ /dev/null
@@ -1,62 +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 com.android.systemui.statusbar.notification.collection.provider;
-/**
- * Caches a computed value until invalidate() is called
- * @param <Parent> Object used to computeValue
- * @param <Value> type of value to cache until invalidate is called
- */
-public abstract class DerivedMember<Parent, Value> {
- private Value mValue;
- protected abstract Value computeValue(Parent parent);
-
- /**
- * Gets the last cached value, else recomputes the value.
- */
- public Value get(Parent parent) {
- if (mValue == null) {
- mValue = computeValue(parent);
- }
- return mValue;
- }
-
- /**
- * Resets the cached value.
- * Next time "get" is called, the value is recomputed.
- */
- public void invalidate() {
- mValue = null;
- }
-
- /**
- * Called when a NotificationEntry's status bar notification has updated.
- * Derived members can invalidate here.
- */
- public void onSbnUpdated() {}
-
- /**
- * Called when a NotificationEntry's Ranking has updated.
- * Derived members can invalidate here.
- */
- public void onRankingUpdated() {}
-
- /**
- * Called when a ListEntry's grouping information (parent or children) has changed.
- * Derived members can invalidate here.
- */
- public void onGroupingUpdated() {}
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
new file mode 100644
index 000000000000..3cc5e62c0bda
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.provider;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Determines whether a notification is considered 'high priority'.
+ *
+ * Notifications that are high priority are visible on the lock screen/status bar and in the top
+ * section in the shade.
+ */
+@Singleton
+public class HighPriorityProvider {
+ private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+
+ @Inject
+ public HighPriorityProvider(PeopleNotificationIdentifier peopleNotificationIdentifier) {
+ mPeopleNotificationIdentifier = peopleNotificationIdentifier;
+ }
+
+ /**
+ * @return true if the ListEntry is high priority, else false
+ *
+ * A NotificationEntry is considered high priority if it:
+ * - has importance greater than or equal to IMPORTANCE_DEFAULT
+ * OR
+ * - their importance has NOT been set to a low priority option by the user AND the
+ * notification fulfills one of the following:
+ * - has a person associated with it
+ * - has a media session associated with it
+ * - has messaging style
+ *
+ * A GroupEntry is considered high priority if its representativeEntry (summary) or children are
+ * high priority
+ */
+ public boolean isHighPriority(ListEntry entry) {
+ if (entry == null) {
+ return false;
+ }
+
+ final NotificationEntry notifEntry = entry.getRepresentativeEntry();
+ return notifEntry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
+ || hasHighPriorityCharacteristics(notifEntry)
+ || hasHighPriorityChild(entry);
+ }
+
+
+ private boolean hasHighPriorityChild(ListEntry entry) {
+ if (entry instanceof GroupEntry) {
+ for (NotificationEntry child : ((GroupEntry) entry).getChildren()) {
+ if (isHighPriority(child)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean hasHighPriorityCharacteristics(NotificationEntry entry) {
+ return !hasUserSetImportance(entry)
+ && (isImportantOngoing(entry)
+ || entry.getSbn().getNotification().hasMediaSession()
+ || isPeopleNotification(entry)
+ || isMessagingStyle(entry));
+ }
+
+ private boolean isImportantOngoing(NotificationEntry entry) {
+ return entry.getSbn().getNotification().isForegroundService()
+ && entry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_LOW;
+ }
+
+ private boolean isMessagingStyle(NotificationEntry entry) {
+ return Notification.MessagingStyle.class.equals(
+ entry.getSbn().getNotification().getNotificationStyle());
+ }
+
+ private boolean isPeopleNotification(NotificationEntry entry) {
+ return mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn());
+ }
+
+ private boolean hasUserSetImportance(NotificationEntry entry) {
+ return entry.getRanking().getChannel() != null
+ && entry.getRanking().getChannel().hasUserSetImportance();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProvider.java
deleted file mode 100644
index 76e256b9be2d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProvider.java
+++ /dev/null
@@ -1,148 +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 com.android.systemui.statusbar.notification.collection.provider;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.Person;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.ListEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Whether the ListEntry is shown to the user as a high priority notification: visible on
- * the lock screen/status bar and in the top section in the shade.
- *
- * A NotificationEntry is considered high priority if it:
- * - has importance greater than or equal to IMPORTANCE_DEFAULT
- * OR
- * - their importance has NOT been set to a low priority option by the user AND the notification
- * fulfills one of the following:
- * - has a person associated with it
- * - has a media session associated with it
- * - has messaging style
- *
- * A GroupEntry is considered high priority if its representativeEntry (summary) or children are
- * high priority
- */
-public class IsHighPriorityProvider extends DerivedMember<ListEntry, Boolean> {
- // TODO: (b/145659174) remove groupManager when moving to NewNotifPipeline. Logic
- // replaced in GroupEntry and NotifListBuilderImpl
- private final NotificationGroupManager mGroupManager;
-
-
- public IsHighPriorityProvider() {
- // TODO: (b/145659174) remove
- mGroupManager = Dependency.get(NotificationGroupManager.class);
- }
-
- @Override
- protected Boolean computeValue(ListEntry entry) {
- if (entry == null) {
- return false;
- }
-
- return isHighPriority(entry);
- }
-
- private boolean isHighPriority(ListEntry listEntry) {
- // requires groups have been set (AFTER PipelineState.STATE_TRANSFORMING)
- final NotificationEntry notifEntry = listEntry.getRepresentativeEntry();
- return notifEntry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
- || hasHighPriorityCharacteristics(notifEntry)
- || hasHighPriorityChild(listEntry);
-
- }
-
- private boolean hasHighPriorityChild(ListEntry entry) {
- // TODO: (b/145659174) remove
- if (entry instanceof NotificationEntry) {
- NotificationEntry notifEntry = (NotificationEntry) entry;
- if (mGroupManager.isSummaryOfGroup(notifEntry.getSbn())) {
- List<NotificationEntry> logicalChildren =
- mGroupManager.getLogicalChildren(notifEntry.getSbn());
- for (NotificationEntry child : logicalChildren) {
- if (child.isHighPriority()) {
- return true;
- }
- }
- }
- }
-
- if (entry instanceof GroupEntry) {
- for (NotificationEntry child : ((GroupEntry) entry).getChildren()) {
- if (child.isHighPriority()) {
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean hasHighPriorityCharacteristics(NotificationEntry entry) {
- return !hasUserSetImportance(entry)
- && (isImportantOngoing(entry)
- || entry.getSbn().getNotification().hasMediaSession()
- || hasPerson(entry)
- || isMessagingStyle(entry));
- }
-
- private boolean isImportantOngoing(NotificationEntry entry) {
- return entry.getSbn().getNotification().isForegroundService()
- && entry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_LOW;
- }
-
- private boolean isMessagingStyle(NotificationEntry entry) {
- return Notification.MessagingStyle.class.equals(
- entry.getSbn().getNotification().getNotificationStyle());
- }
-
- private boolean hasPerson(NotificationEntry entry) {
- // TODO: cache favorite and recent contacts to check contact affinity
- Notification notification = entry.getSbn().getNotification();
- ArrayList<Person> people = notification.extras != null
- ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
- : new ArrayList<>();
- return people != null && !people.isEmpty();
- }
-
- private boolean hasUserSetImportance(NotificationEntry entry) {
- return entry.getRanking().getChannel() != null
- && entry.getRanking().getChannel().hasUserSetImportance();
- }
-
- @Override
- public void onSbnUpdated() {
- invalidate();
- }
-
- @Override
- public void onRankingUpdated() {
- invalidate();
- }
-
- @Override
- public void onGroupingUpdated() {
- invalidate();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 3e1b5bd0571e..89e5f5596291 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -294,6 +294,9 @@ public class NotificationLogger implements StateListener {
}
}
+ /**
+ * Logs Notification inflation error
+ */
private void logNotificationError(
StatusBarNotification notification,
Exception exception) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
index 2c0c9420a8c4..e81d361f58f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
@@ -37,7 +37,8 @@ data class PersonModel(
val key: PersonKey,
val name: CharSequence,
val avatar: Drawable,
- val clickIntent: PendingIntent
+ val clickIntent: PendingIntent,
+ val userId: Int
)
/** Unique identifier for a Person in PeopleHub. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
index 784673e64ff8..88b41471a063 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
@@ -17,28 +17,27 @@
package com.android.systemui.statusbar.notification.people
import android.app.Notification
-import android.content.Context
-import android.graphics.Canvas
-import android.graphics.ColorFilter
-import android.graphics.PixelFormat
-import android.graphics.drawable.BitmapDrawable
+import android.content.pm.UserInfo
import android.graphics.drawable.Drawable
-import android.os.UserHandle
+import android.os.UserManager
import android.service.notification.StatusBarNotification
-import android.util.TypedValue
+import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import com.android.internal.statusbar.NotificationVisibility
import com.android.internal.widget.MessagingGroup
-import com.android.launcher3.icons.BaseIconFactory
import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.NotificationPersonExtractorPlugin
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.notification.NotificationEntryListener
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.policy.ExtensionController
import java.util.ArrayDeque
+import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Singleton
@@ -52,8 +51,7 @@ interface NotificationPersonExtractor {
@Singleton
class NotificationPersonExtractorPluginBoundary @Inject constructor(
- extensionController: ExtensionController,
- private val context: Context
+ extensionController: ExtensionController
) : NotificationPersonExtractor {
private var plugin: NotificationPersonExtractorPlugin? = null
@@ -70,9 +68,8 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor(
}
override fun extractPerson(sbn: StatusBarNotification) =
- plugin?.extractPerson(sbn)?.let { data ->
- val badged = addBadgeToDrawable(data.avatar, context, sbn.packageName, sbn.user)
- PersonModel(data.key, data.name, badged, data.clickIntent)
+ plugin?.extractPerson(sbn)?.run {
+ PersonModel(key, name, avatar, clickIntent, sbn.user.identifier)
}
override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn)
@@ -84,11 +81,16 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor(
@Singleton
class PeopleHubDataSourceImpl @Inject constructor(
private val notificationEntryManager: NotificationEntryManager,
- private val peopleHubManager: PeopleHubManager,
- private val extractor: NotificationPersonExtractor
+ private val extractor: NotificationPersonExtractor,
+ private val userManager: UserManager,
+ @Background private val bgExecutor: Executor,
+ @Main private val mainExecutor: Executor,
+ private val notifLockscreenUserMgr: NotificationLockscreenUserManager
) : DataSource<PeopleHubModel> {
+ private var userChangeSubscription: Subscription? = null
private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>()
+ private val peopleHubManagerForUser = SparseArray<PeopleHubManager>()
private val notificationEntryListener = object : NotificationEntryListener {
override fun onEntryInflated(entry: NotificationEntry, inflatedFlags: Int) =
@@ -106,31 +108,56 @@ class PeopleHubDataSourceImpl @Inject constructor(
}
private fun removeVisibleEntry(entry: NotificationEntry) {
- val key = extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey()
- if (key?.let(peopleHubManager::removeActivePerson) == true) {
- updateUi()
+ (extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey())?.let { key ->
+ val userId = entry.sbn.user.identifier
+ bgExecutor.execute {
+ val parentId = userManager.getProfileParent(userId)?.id ?: userId
+ mainExecutor.execute {
+ if (peopleHubManagerForUser[parentId]?.removeActivePerson(key) == true) {
+ updateUi()
+ }
+ }
+ }
}
}
private fun addVisibleEntry(entry: NotificationEntry) {
- val personModel = extractor.extractPerson(entry.sbn) ?: entry.extractPerson()
- if (personModel?.let(peopleHubManager::addActivePerson) == true) {
- updateUi()
+ (extractor.extractPerson(entry.sbn) ?: entry.extractPerson())?.let { personModel ->
+ val userId = entry.sbn.user.identifier
+ bgExecutor.execute {
+ val parentId = userManager.getProfileParent(userId)?.id ?: userId
+ mainExecutor.execute {
+ val manager = peopleHubManagerForUser[parentId]
+ ?: PeopleHubManager().also { peopleHubManagerForUser.put(parentId, it) }
+ if (manager.addActivePerson(personModel)) {
+ updateUi()
+ }
+ }
+ }
}
}
override fun registerListener(listener: DataListener<PeopleHubModel>): Subscription {
- val registerWithNotificationEntryManager = dataListeners.isEmpty()
+ val register = dataListeners.isEmpty()
dataListeners.add(listener)
- if (registerWithNotificationEntryManager) {
+ if (register) {
+ userChangeSubscription = notifLockscreenUserMgr.registerListener(
+ object : NotificationLockscreenUserManager.UserChangedListener {
+ override fun onUserChanged(userId: Int) = updateUi()
+ override fun onCurrentProfilesChanged(
+ currentProfiles: SparseArray<UserInfo>?
+ ) = updateUi()
+ })
notificationEntryManager.addNotificationEntryListener(notificationEntryListener)
} else {
- listener.onDataChanged(peopleHubManager.getPeopleHubModel())
+ getPeopleHubModelForCurrentUser()?.let(listener::onDataChanged)
}
return object : Subscription {
override fun unsubscribe() {
dataListeners.remove(listener)
if (dataListeners.isEmpty()) {
+ userChangeSubscription?.unsubscribe()
+ userChangeSubscription = null
notificationEntryManager
.removeNotificationEntryListener(notificationEntryListener)
}
@@ -138,16 +165,36 @@ class PeopleHubDataSourceImpl @Inject constructor(
}
}
+ private fun getPeopleHubModelForCurrentUser(): PeopleHubModel? {
+ val currentUserId = notifLockscreenUserMgr.currentUserId
+ val model = peopleHubManagerForUser[currentUserId]?.getPeopleHubModel()
+ ?: return null
+ val currentProfiles = notifLockscreenUserMgr.currentProfiles
+ return model.copy(people = model.people.filter { person ->
+ currentProfiles[person.userId]?.isQuietModeEnabled == false
+ })
+ }
+
private fun updateUi() {
- val model = peopleHubManager.getPeopleHubModel()
+ val model = getPeopleHubModelForCurrentUser() ?: return
for (listener in dataListeners) {
listener.onDataChanged(model)
}
}
}
-@Singleton
-class PeopleHubManager @Inject constructor() {
+private fun NotificationLockscreenUserManager.registerListener(
+ listener: NotificationLockscreenUserManager.UserChangedListener
+): Subscription {
+ addUserChangedListener(listener)
+ return object : Subscription {
+ override fun unsubscribe() {
+ removeUserChangedListener(listener)
+ }
+ }
+}
+
+class PeopleHubManager {
private val activePeople = mutableMapOf<PersonKey, PersonModel>()
private val inactivePeople = ArrayDeque<PersonModel>(MAX_STORED_INACTIVE_PEOPLE)
@@ -157,7 +204,7 @@ class PeopleHubManager @Inject constructor() {
if (inactivePeople.size >= MAX_STORED_INACTIVE_PEOPLE) {
inactivePeople.removeLast()
}
- inactivePeople.push(data)
+ inactivePeople.add(data)
return true
}
return false
@@ -190,63 +237,7 @@ private fun NotificationEntry.extractPerson(): PersonModel? {
?: extras.getString(Notification.EXTRA_TITLE)
?: return null
val drawable = extractAvatarFromRow(this) ?: return null
- val badgedAvatar = addBadgeToDrawable(drawable, row.context, sbn.packageName, sbn.user)
- return PersonModel(key, name, badgedAvatar, clickIntent)
-}
-
-private fun addBadgeToDrawable(
- drawable: Drawable,
- context: Context,
- packageName: String,
- user: UserHandle
-): Drawable {
- val pm = context.packageManager
- val appInfo = pm.getApplicationInfoAsUser(packageName, 0, user)
- return object : Drawable() {
- override fun draw(canvas: Canvas) {
- val iconBounds = getBounds()
- val factory = object : BaseIconFactory(
- context,
- 0 /* unused */,
- iconBounds.width(),
- true) {}
- val badge = factory.createBadgedIconBitmap(
- appInfo.loadIcon(pm),
- user,
- true,
- appInfo.isInstantApp,
- null)
- val badgeDrawable = BitmapDrawable(context.resources, badge.icon)
- .apply {
- alpha = drawable.alpha
- colorFilter = drawable.colorFilter
- val badgeWidth = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- 15f,
- context.resources.displayMetrics
- ).toInt()
- setBounds(
- iconBounds.left + (iconBounds.width() - badgeWidth),
- iconBounds.top + (iconBounds.height() - badgeWidth),
- iconBounds.right,
- iconBounds.bottom)
- }
- drawable.bounds = iconBounds
- drawable.draw(canvas)
- badgeDrawable.draw(canvas)
- }
-
- override fun setAlpha(alpha: Int) {
- drawable.alpha = alpha
- }
-
- override fun setColorFilter(colorFilter: ColorFilter?) {
- drawable.colorFilter = colorFilter
- }
-
- @PixelFormat.Opacity
- override fun getOpacity(): Int = PixelFormat.OPAQUE
- }
+ return PersonModel(key, name, drawable, clickIntent, sbn.user.identifier)
}
fun extractAvatarFromRow(entry: NotificationEntry): Drawable? =
@@ -272,4 +263,4 @@ private fun NotificationEntry.extractPersonKey(): PersonKey? =
if (isMessagingNotification()) key else null
private fun NotificationEntry.isMessagingNotification() =
- sbn.notification.notificationStyle == Notification.MessagingStyle::class.java \ No newline at end of file
+ sbn.notification.notificationStyle == Notification.MessagingStyle::class.java
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 172b72e9b0fc..30f22ac5e161 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -397,7 +397,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
existingWrapper.onReinflated();
}
} catch (Exception e) {
- handleInflationError(runningInflations, e, row.getEntry().getSbn(), callback);
+ handleInflationError(runningInflations, e, row.getEntry(), callback);
// Add a running inflation to make sure we don't trigger callbacks.
// Safe to do because only happens in tests.
runningInflations.put(inflationId, new CancellationSignal());
@@ -448,7 +448,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
onViewApplied(newView);
} catch (Exception anotherException) {
runningInflations.remove(inflationId);
- handleInflationError(runningInflations, e, row.getEntry().getSbn(),
+ handleInflationError(runningInflations, e, row.getEntry(),
callback);
}
}
@@ -474,7 +474,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
private static void handleInflationError(
HashMap<Integer, CancellationSignal> runningInflations, Exception e,
- StatusBarNotification notification, @Nullable InflationCallback callback) {
+ NotificationEntry notification, @Nullable InflationCallback callback) {
Assert.isMainThread();
runningInflations.values().forEach(CancellationSignal::cancel);
if (callback != null) {
@@ -707,7 +707,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
+ Integer.toHexString(sbn.getId());
Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
if (mCallback != null) {
- mCallback.handleInflationException(sbn,
+ mCallback.handleInflationException(mRow.getEntry(),
new InflationException("Couldn't inflate contentViews" + e));
}
}
@@ -729,7 +729,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
}
@Override
- public void handleInflationException(StatusBarNotification notification, Exception e) {
+ public void handleInflationException(NotificationEntry entry, Exception e) {
handleError(e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 6f2abba128d6..779a224ecb62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -53,6 +53,7 @@ import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -81,6 +82,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
private final Context mContext;
private final VisualStabilityManager mVisualStabilityManager;
private final AccessibilityManager mAccessibilityManager;
+ private final HighPriorityProvider mHighPriorityProvider;
// Dependencies:
private final NotificationLockscreenUserManager mLockscreenUserManager =
@@ -109,12 +111,14 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
@Inject
public NotificationGutsManager(Context context, VisualStabilityManager visualStabilityManager,
Lazy<StatusBar> statusBarLazy, @Main Handler mainHandler,
- AccessibilityManager accessibilityManager) {
+ AccessibilityManager accessibilityManager,
+ HighPriorityProvider highPriorityProvider) {
mContext = context;
mVisualStabilityManager = visualStabilityManager;
mStatusBarLazy = statusBarLazy;
mMainHandler = mainHandler;
mAccessibilityManager = accessibilityManager;
+ mHighPriorityProvider = highPriorityProvider;
}
public void setUpWithPresenter(NotificationPresenter presenter,
@@ -331,8 +335,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
row.getIsNonblockable(),
isForBlockingHelper,
row.getEntry().getImportance(),
- row.getEntry().isHighPriority());
-
+ mHighPriorityProvider.isHighPriority(row.getEntry()));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index b4ccb567504a..edfd1b4d3c85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -46,6 +46,7 @@ import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
@@ -269,7 +270,8 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
}
mAppOpsItem = createAppOpsItem(mContext);
if (mIsUsingBidirectionalSwipe) {
- mInfoItem = createInfoItem(mContext, !mParent.getEntry().isHighPriority());
+ mInfoItem = createInfoItem(mContext,
+ mParent.getEntry().getBucket() == NotificationSectionsManager.BUCKET_SILENT);
} else {
mInfoItem = createInfoItem(mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
index 2fe54c00bb06..9b95bff4921c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.row;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.service.notification.StatusBarNotification;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -138,10 +137,10 @@ public interface NotificationRowContentBinder {
/**
* Callback for when there is an inflation exception
*
- * @param notification notification which failed to inflate content
+ * @param entry notification which failed to inflate content
* @param e exception
*/
- void handleInflationException(StatusBarNotification notification, Exception e);
+ void handleInflationException(NotificationEntry entry, Exception e);
/**
* Callback for after the content views finish inflating.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 352ba0f75a32..76fdfc6fbabc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -28,6 +28,7 @@ import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.metrics.LogMaker;
import android.os.Handler;
+import android.service.notification.StatusBarNotification;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -176,27 +177,30 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
final MediaSession.Token token = mRow.getEntry().getSbn().getNotification().extras
.getParcelable(Notification.EXTRA_MEDIA_SESSION);
- if (Utils.useQsMediaPlayer(mContext)) {
+ if (Utils.useQsMediaPlayer(mContext) && token != null) {
final int[] compactActions = mRow.getEntry().getSbn().getNotification().extras
.getIntArray(Notification.EXTRA_COMPACT_ACTIONS);
int tintColor = getNotificationHeader().getOriginalIconColor();
StatusBarWindowController ctrl = Dependency.get(StatusBarWindowController.class);
QuickQSPanel panel = ctrl.getStatusBarView().findViewById(
com.android.systemui.R.id.quick_qs_panel);
+ StatusBarNotification sbn = mRow.getEntry().getSbn();
+ Notification notif = sbn.getNotification();
panel.getMediaPlayer().setMediaSession(token,
- mRow.getEntry().getSbn().getNotification().getSmallIcon(),
+ notif.getSmallIcon(),
tintColor,
mBackgroundColor,
mActions,
- compactActions);
+ compactActions,
+ notif.contentIntent);
QSPanel bigPanel = ctrl.getStatusBarView().findViewById(
com.android.systemui.R.id.quick_settings_panel);
bigPanel.addMediaSession(token,
- mRow.getEntry().getSbn().getNotification().getSmallIcon(),
+ notif.getSmallIcon(),
tintColor,
mBackgroundColor,
mActions,
- mRow.getEntry().getSbn());
+ sbn);
}
boolean showCompactSeekbar = mMediaManager.getShowCompactMediaSeekbar();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 2761689ec409..09c1fad423d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -187,18 +187,18 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
@Override
public boolean beginsSection(@NonNull View view, @Nullable View previous) {
boolean begin = false;
- if (view instanceof ExpandableNotificationRow) {
- if (previous instanceof ExpandableNotificationRow) {
+ if (view instanceof ActivatableNotificationView) {
+ if (previous instanceof ActivatableNotificationView) {
// If we're drawing the first non-person notification, break out a section
- ExpandableNotificationRow curr = (ExpandableNotificationRow) view;
- ExpandableNotificationRow prev = (ExpandableNotificationRow) previous;
+ ActivatableNotificationView curr = (ActivatableNotificationView) view;
+ ActivatableNotificationView prev = (ActivatableNotificationView) previous;
- begin = curr.getEntry().getBucket() != prev.getEntry().getBucket();
+ begin = getBucket(curr) != getBucket(prev);
}
}
if (!begin) {
- begin = view == mGentleHeader || previous == mPeopleHubView;
+ begin = view == mGentleHeader || view == mPeopleHubView;
}
return begin;
@@ -230,29 +230,42 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
return;
}
- int lastPersonIndex = -1;
- int firstGentleNotifIndex = -1;
+ boolean peopleNotificationsPresent = false;
+ int firstNonHeadsUpIndex = -1;
+ int firstGentleIndex = -1;
+ int notifCount = 0;
final int n = mParent.getChildCount();
for (int i = 0; i < n; i++) {
View child = mParent.getChildAt(i);
- if (child instanceof ExpandableNotificationRow
- && child.getVisibility() != View.GONE) {
+ if (child instanceof ExpandableNotificationRow && child.getVisibility() != View.GONE) {
+ notifCount++;
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ if (firstNonHeadsUpIndex == -1 && !row.isHeadsUp()) {
+ firstNonHeadsUpIndex = i;
+ }
if (row.getEntry().getBucket() == BUCKET_PEOPLE) {
- lastPersonIndex = i;
+ peopleNotificationsPresent = true;
}
if (row.getEntry().getBucket() == BUCKET_SILENT) {
- firstGentleNotifIndex = i;
+ firstGentleIndex = i;
break;
}
}
}
+ if (firstNonHeadsUpIndex == -1) {
+ firstNonHeadsUpIndex = firstGentleIndex != -1 ? firstGentleIndex : notifCount;
+ }
+
// make room for peopleHub
- firstGentleNotifIndex += adjustPeopleHubVisibilityAndPosition(lastPersonIndex);
+ int offset = adjustPeopleHubVisibilityAndPosition(
+ firstNonHeadsUpIndex, peopleNotificationsPresent);
+ if (firstGentleIndex != -1) {
+ firstGentleIndex += offset;
+ }
- adjustGentleHeaderVisibilityAndPosition(firstGentleNotifIndex);
+ adjustGentleHeaderVisibilityAndPosition(firstGentleIndex);
mGentleHeader.setAreThereDismissableGentleNotifs(
mParent.hasActiveClearableNotifications(ROWS_GENTLE));
@@ -294,13 +307,15 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
}
}
- private int adjustPeopleHubVisibilityAndPosition(int lastPersonIndex) {
- final boolean showPeopleHeader = mPeopleHubVisible
- && mNumberOfSections > 2
- && mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
+ private int adjustPeopleHubVisibilityAndPosition(
+ int targetIndex, boolean peopleNotificationsPresent) {
+ final boolean showPeopleHeader = mNumberOfSections > 2
+ && mStatusBarStateController.getState() != StatusBarState.KEYGUARD
+ && (peopleNotificationsPresent || mPeopleHubVisible);
final int currentHubIndex = mParent.indexOfChild(mPeopleHubView);
final boolean currentlyVisible = currentHubIndex >= 0;
- int targetIndex = lastPersonIndex + 1;
+
+ mPeopleHubView.setCanSwipe(showPeopleHeader && !peopleNotificationsPresent);
if (!showPeopleHeader) {
if (currentlyVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 6d0fcc386281..4845ea16020b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -31,6 +31,7 @@ import com.android.systemui.SwipeHelper;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeActionHelper {
@@ -298,8 +299,8 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
@Override
public Animator getViewTranslationAnimator(View v, float target,
ValueAnimator.AnimatorUpdateListener listener) {
- if (v instanceof SwipeableView) {
- return ((SwipeableView) v).getTranslateViewAnimator(target, listener);
+ if (v instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
} else {
return superGetViewTranslationAnimator(v, target, listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index a0796060e9d8..e5717aeefdcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -16,38 +16,22 @@
package com.android.systemui.statusbar.notification.stack
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.ObjectAnimator
-import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
-import android.util.FloatProperty
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.TextView
import com.android.systemui.R
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin
import com.android.systemui.statusbar.notification.people.DataListener
import com.android.systemui.statusbar.notification.people.PersonViewModel
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
-private val TRANSLATE_CONTENT = object : FloatProperty<PeopleHubView>("translate") {
- override fun setValue(view: PeopleHubView, value: Float) {
- view.translation = value
- }
-
- override fun get(view: PeopleHubView) = view.translation
-}
-
class PeopleHubView(context: Context, attrs: AttributeSet) :
ActivatableNotificationView(context, attrs), SwipeableView {
private lateinit var contents: ViewGroup
private lateinit var personControllers: List<PersonDataListenerImpl>
- private var translateAnim: ObjectAnimator? = null
val personViewAdapters: Sequence<DataListener<PersonViewModel?>>
get() = personControllers.asSequence()
@@ -56,9 +40,10 @@ class PeopleHubView(context: Context, attrs: AttributeSet) :
super.onFinishInflate()
contents = requireViewById(R.id.people_list)
personControllers = (0 until contents.childCount)
+ .reversed()
.asSequence()
.mapNotNull { idx ->
- (contents.getChildAt(idx) as? LinearLayout)?.let(::PersonDataListenerImpl)
+ (contents.getChildAt(idx) as? ImageView)?.let(::PersonDataListenerImpl)
}
.toList()
}
@@ -69,41 +54,32 @@ class PeopleHubView(context: Context, attrs: AttributeSet) :
override fun createMenu(): NotificationMenuRowPlugin? = null
- override fun getTranslateViewAnimator(
- leftTarget: Float,
- listener: ValueAnimator.AnimatorUpdateListener?
- ): Animator =
- ObjectAnimator
- .ofFloat(this, TRANSLATE_CONTENT, leftTarget)
- .apply {
- listener?.let { addUpdateListener(listener) }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(anim: Animator) {
- translateAnim = null
- }
- })
- }
- .also {
- translateAnim?.cancel()
- translateAnim = it
- }
-
override fun resetTranslation() {
- translateAnim?.cancel()
translationX = 0f
}
- private inner class PersonDataListenerImpl(val viewGroup: ViewGroup) :
- DataListener<PersonViewModel?> {
+ override fun setTranslation(translation: Float) {
+ if (canSwipe) {
+ super.setTranslation(translation)
+ }
+ }
- val nameView = viewGroup.requireViewById<TextView>(R.id.person_name)
- val avatarView = viewGroup.requireViewById<ImageView>(R.id.person_icon)
+ var canSwipe: Boolean = true
+ set(value) {
+ if (field != value) {
+ if (field) {
+ resetTranslation()
+ }
+ field = value
+ }
+ }
+
+ private inner class PersonDataListenerImpl(val avatarView: ImageView) :
+ DataListener<PersonViewModel?> {
override fun onDataChanged(data: PersonViewModel?) {
- viewGroup.visibility = data?.let { View.VISIBLE } ?: View.INVISIBLE
- nameView.text = data?.name
avatarView.setImageDrawable(data?.icon)
- viewGroup.setOnClickListener { data?.onClick?.invoke() }
+ avatarView.setOnClickListener { data?.onClick?.invoke() }
}
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
index 6c6ef61cfdaf..49e59a2e7200 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar.notification.stack;
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-
import androidx.annotation.Nullable;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -32,10 +29,6 @@ public interface SwipeableView {
/** Optionally creates a menu for this view. */
@Nullable NotificationMenuRowPlugin createMenu();
- /** Animator for translating the view, simulating a swipe. */
- Animator getTranslateViewAnimator(
- float leftTarget, ValueAnimator.AnimatorUpdateListener listener);
-
/** Sets the translation amount for an in-progress swipe. */
void setTranslation(float translate);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index f7d52b5f5ab0..ad1aa8370495 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -98,7 +98,12 @@ class KeyguardBypassController : Dumpable {
bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
}
}, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
- lockscreenUserManager.addUserChangedListener { pendingUnlockType = null }
+ lockscreenUserManager.addUserChangedListener(
+ object : NotificationLockscreenUserManager.UserChangedListener {
+ override fun onUserChanged(userId: Int) {
+ pendingUnlockType = null
+ }
+ })
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index a3b1b5f8360b..a6842badc153 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -366,8 +366,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_USER_SWITCHED);
- mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, Handler.getMain(),
- UserHandle.ALL);
+ mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter,
+ Handler.getMain(), UserHandle.ALL);
notifyNavigationBarScreenOn();
mOverviewProxyService.addCallback(mOverviewProxyListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9dc8fbf900b6..0f3af095f7be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -24,8 +24,6 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
-import com.android.internal.annotations.VisibleForTesting;
-
public class NotificationPanelView extends PanelView {
private static final boolean DEBUG = false;
@@ -38,14 +36,10 @@ public class NotificationPanelView extends PanelView {
static final String COUNTER_PANEL_OPEN = "panel_open";
static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
- @VisibleForTesting
- protected KeyguardAffordanceHelper mAffordanceHelper;
-
- private int mOldLayoutDirection;
-
private int mCurrentPanelAlpha;
private final Paint mAlphaPaint = new Paint();
private boolean mDozing;
+ private RtlChangeListener mRtlChangeListener;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -57,9 +51,8 @@ public class NotificationPanelView extends PanelView {
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
- if (layoutDirection != mOldLayoutDirection) {
- mAffordanceHelper.onRtlPropertiesChanged();
- mOldLayoutDirection = layoutDirection;
+ if (mRtlChangeListener != null) {
+ mRtlChangeListener.onRtlPropertielsChanged(layoutDirection);
}
}
@@ -95,4 +88,11 @@ public class NotificationPanelView extends PanelView {
return !mDozing;
}
+ void setRtlChangeListener(RtlChangeListener listener) {
+ mRtlChangeListener = listener;
+ }
+
+ interface RtlChangeListener {
+ void onRtlPropertielsChanged(int layoutDirection);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index bbde25bb482e..90ec2a076e87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -449,6 +449,7 @@ public class NotificationPanelViewController extends PanelViewController {
private PluginManager mPluginManager;
private FrameLayout mPluginFrame;
private NPVPluginManager mNPVPluginManager;
+ private int mOldLayoutDirection;
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@@ -603,6 +604,13 @@ public class NotificationPanelViewController extends PanelViewController {
}
}, HomeControlsPlugin.class, false);
+
+ mView.setRtlChangeListener(layoutDirection -> {
+ if (layoutDirection != mOldLayoutDirection) {
+ mAffordanceHelper.onRtlPropertiesChanged();
+ mOldLayoutDirection = layoutDirection;
+ }
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 5b34aa7781c1..00e38f814dff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -179,7 +179,7 @@ public class PhoneStatusBarPolicy
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
- broadcastDispatcher.registerReceiver(mIntentReceiver, filter, mHandler);
+ broadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter, mHandler);
// listen for user / profile change.
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 277a7613aafb..ccc86b1f8c5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1272,7 +1272,11 @@ public class StatusBar extends SystemUI implements DemoMode,
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
- mEntryManager.setRowBinder(rowBinder);
+ if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mEntryManager.setRowBinder(rowBinder);
+ rowBinder.setInflationCallback(mEntryManager);
+ }
+
mRemoteInputUriController.attach(mEntryManager);
rowBinder.setNotificationClicker(new NotificationClicker(
@@ -1282,7 +1286,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationListController.bind();
if (mFeatureFlags.isNewNotifPipelineEnabled()) {
- mNewNotifPipeline.get().initialize(mNotificationListener);
+ mNewNotifPipeline.get().initialize(mNotificationListener, rowBinder);
}
mEntryManager.attach(mNotificationListener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 0fd0dabbc3f2..12a65169e1df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -217,7 +217,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mEntryManager.addNotificationLifetimeExtenders(
remoteInputManager.getLifetimeExtenders());
notificationRowBinder.setUpWithPresenter(this, notifListContainer, mHeadsUpManager,
- mEntryManager, this);
+ this);
mNotificationInterruptionStateProvider.setUpWithPresenter(
this, mHeadsUpManager, this::canHeadsUp);
mLockscreenUserManager.setUpWithPresenter(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index ddacc3aedce0..4f0af9e166c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -188,7 +188,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
// NOTE: This receiver could run before this method returns, as it's not dispatching
// on the main thread and BroadcastDispatcher may not need to register with Context.
// The receiver will return immediately if the view does not have a Handler yet.
- mBroadcastDispatcher.registerReceiver(mIntentReceiver, filter,
+ mBroadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter,
Dependency.get(Dependency.TIME_TICK_HANDLER), UserHandle.ALL);
Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
StatusBarIconController.ICON_BLACKLIST);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index 2e26711a3578..b4c154aa28cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -96,7 +96,7 @@ public class DateView extends TextView {
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
- mBroadcastDispatcher.registerReceiver(mIntentReceiver, filter,
+ mBroadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter,
Dependency.get(Dependency.TIME_TICK_HANDLER));
updateClock();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 570f153a62c0..cb40d7752f53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -79,7 +79,8 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
IntentFilter filter = new IntentFilter();
filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
filter.addAction(LocationManager.MODE_CHANGED_ACTION);
- mBroadcastDispatcher.registerReceiver(this, filter, new Handler(bgLooper), UserHandle.ALL);
+ mBroadcastDispatcher.registerReceiverWithHandler(this, filter,
+ new Handler(bgLooper), UserHandle.ALL);
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mStatusBarManager
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index f640d039ad31..679fa7e2b016 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -326,7 +326,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
- mBroadcastDispatcher.registerReceiver(this, filter, mReceiverHandler);
+ mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler);
mListening = true;
updateMobileControllers();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 019ef3bca709..312c4ac75bfa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -126,7 +126,8 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi
IntentFilter filter = new IntentFilter();
filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
- broadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, bgHandler, UserHandle.ALL);
+ broadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, bgHandler,
+ UserHandle.ALL);
// TODO: re-register network callback on user change.
mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 7758aba52918..31b9952afe94 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -88,7 +88,7 @@ public class ThemeOverlayController extends SystemUI {
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
- mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
+ mBroadcastDispatcher.registerReceiverWithHandler(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index a4ed31d95b2b..112ae6f3758a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -1008,7 +1008,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- mBroadcastDispatcher.registerReceiver(this, filter, mWorker);
+ mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mWorker);
}
public void destroy() {
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
new file mode 100644
index 000000000000..d413308d4573
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -0,0 +1,333 @@
+/*
+ * 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 com.android.systemui.wm;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.res.Configuration;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.IDisplayWindowInsetsController;
+import android.view.InsetsSource;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.WindowInsets;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Manages IME control at the display-level. This occurs when IME comes up in multi-window mode.
+ */
+@Singleton
+public class DisplayImeController implements DisplayWindowController.DisplayWindowListener {
+ private static final String TAG = "DisplayImeController";
+
+ static final int ANIMATION_DURATION_SHOW_MS = 275;
+ static final int ANIMATION_DURATION_HIDE_MS = 340;
+ static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ private static final int DIRECTION_NONE = 0;
+ private static final int DIRECTION_SHOW = 1;
+ private static final int DIRECTION_HIDE = 2;
+
+ SystemWindows mSystemWindows;
+ final Handler mHandler;
+
+ final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
+
+ final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
+
+ @Inject
+ DisplayImeController(SystemWindows syswin, DisplayWindowController displayController,
+ @Main Handler mainHandler) {
+ mHandler = mainHandler;
+ mSystemWindows = syswin;
+ displayController.addDisplayWindowListener(this);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ // Add's a system-ui window-manager specifically for ime. This type is special because
+ // WM will defer IME inset handling to it in multi-window scenarious.
+ PerDisplay pd = new PerDisplay(displayId,
+ mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation());
+ try {
+ mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, pd);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to set insets controller on display " + displayId);
+ }
+ mImePerDisplay.put(displayId, pd);
+ }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ PerDisplay pd = mImePerDisplay.get(displayId);
+ if (pd == null) {
+ return;
+ }
+ if (mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation()
+ != pd.mRotation && isImeShowing(displayId)) {
+ pd.startAnimation(true);
+ }
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ try {
+ mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, null);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
+ }
+ mImePerDisplay.remove(displayId);
+ }
+
+ private boolean isImeShowing(int displayId) {
+ PerDisplay pd = mImePerDisplay.get(displayId);
+ if (pd == null) {
+ return false;
+ }
+ final InsetsSource imeSource = pd.mInsetsState.getSource(InsetsState.ITYPE_IME);
+ return imeSource != null && pd.mImeSourceControl != null && imeSource.isVisible();
+ }
+
+ private void dispatchPositionChanged(int displayId, int imeTop,
+ SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImePositionChanged(displayId, imeTop, t);
+ }
+ }
+ }
+
+ private void dispatchStartPositioning(int displayId, int imeTop, int finalImeTop,
+ boolean show, SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImeStartPositioning(displayId, imeTop, finalImeTop, show, t);
+ }
+ }
+ }
+
+ private void dispatchEndPositioning(int displayId, int imeTop, boolean show,
+ SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImeEndPositioning(displayId, imeTop, show, t);
+ }
+ }
+ }
+
+ /**
+ * Adds an {@link ImePositionProcessor} to be called during ime position updates.
+ */
+ public void addPositionProcessor(ImePositionProcessor processor) {
+ synchronized (mPositionProcessors) {
+ if (mPositionProcessors.contains(processor)) {
+ return;
+ }
+ mPositionProcessors.add(processor);
+ }
+ }
+
+ /**
+ * Removes an {@link ImePositionProcessor} to be called during ime position updates.
+ */
+ public void removePositionProcessor(ImePositionProcessor processor) {
+ synchronized (mPositionProcessors) {
+ mPositionProcessors.remove(processor);
+ }
+ }
+
+ class PerDisplay extends IDisplayWindowInsetsController.Stub {
+ final int mDisplayId;
+ final InsetsState mInsetsState = new InsetsState();
+ InsetsSourceControl mImeSourceControl = null;
+ int mAnimationDirection = DIRECTION_NONE;
+ ValueAnimator mAnimation = null;
+ int mRotation = Surface.ROTATION_0;
+
+ PerDisplay(int displayId, int initialRotation) {
+ mDisplayId = displayId;
+ mRotation = initialRotation;
+ }
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ if (mInsetsState.equals(insetsState)) {
+ return;
+ }
+ mInsetsState.set(insetsState, true /* copySources */);
+ }
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {
+ insetsChanged(insetsState);
+ if (activeControls != null) {
+ for (InsetsSourceControl activeControl : activeControls) {
+ if (activeControl == null) {
+ continue;
+ }
+ if (activeControl.getType() == InsetsState.ITYPE_IME) {
+ mImeSourceControl = activeControl;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void showInsets(int types, boolean fromIme) {
+ if ((types & WindowInsets.Type.ime()) == 0) {
+ return;
+ }
+ startAnimation(true /* show */);
+ }
+
+ @Override
+ public void hideInsets(int types, boolean fromIme) {
+ if ((types & WindowInsets.Type.ime()) == 0) {
+ return;
+ }
+ startAnimation(false /* show */);
+ }
+
+ /**
+ * Sends the local visibility state back to window manager. Needed for legacy adjustForIme.
+ */
+ private void setVisibleDirectly(boolean visible) {
+ mInsetsState.getSource(InsetsState.ITYPE_IME).setVisible(visible);
+ try {
+ mSystemWindows.mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState);
+ } catch (RemoteException e) {
+ }
+ }
+
+ private int imeTop(InsetsSource imeSource, float surfaceOffset) {
+ return imeSource.getFrame().top + (int) surfaceOffset;
+ }
+
+ private void startAnimation(final boolean show) {
+ final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
+ if (imeSource == null || mImeSourceControl == null) {
+ return;
+ }
+ if ((mAnimationDirection == DIRECTION_SHOW && show)
+ || (mAnimationDirection == DIRECTION_HIDE && !show)) {
+ return;
+ }
+ if (mAnimationDirection != DIRECTION_NONE) {
+ mAnimation.end();
+ mAnimationDirection = DIRECTION_NONE;
+ }
+ mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
+ mHandler.post(() -> {
+ final float defaultY = mImeSourceControl.getSurfacePosition().y;
+ final float x = mImeSourceControl.getSurfacePosition().x;
+ final float startY = show ? defaultY + imeSource.getFrame().height() : defaultY;
+ final float endY = show ? defaultY : defaultY + imeSource.getFrame().height();
+ mAnimation = ValueAnimator.ofFloat(startY, endY);
+ mAnimation.setDuration(
+ show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS);
+
+ mAnimation.addUpdateListener(animation -> {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ float value = (float) animation.getAnimatedValue();
+ t.setPosition(mImeSourceControl.getLeash(), x, value);
+ dispatchPositionChanged(mDisplayId, imeTop(imeSource, value), t);
+ t.apply();
+ t.close();
+ });
+ mAnimation.setInterpolator(INTERPOLATOR);
+ mAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setPosition(mImeSourceControl.getLeash(), x, startY);
+ dispatchStartPositioning(mDisplayId, imeTop(imeSource, startY),
+ imeTop(imeSource, endY), mAnimationDirection == DIRECTION_SHOW,
+ t);
+ if (mAnimationDirection == DIRECTION_SHOW) {
+ t.show(mImeSourceControl.getLeash());
+ }
+ t.apply();
+ t.close();
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setPosition(mImeSourceControl.getLeash(), x, endY);
+ dispatchEndPositioning(mDisplayId, imeTop(imeSource, endY),
+ mAnimationDirection == DIRECTION_SHOW, t);
+ if (mAnimationDirection == DIRECTION_HIDE) {
+ t.hide(mImeSourceControl.getLeash());
+ }
+ t.apply();
+ t.close();
+
+ mAnimationDirection = DIRECTION_NONE;
+ mAnimation = null;
+ }
+ });
+ if (!show) {
+ // When going away, queue up insets change first, otherwise any bounds changes
+ // can have a "flicker" of ime-provided insets.
+ setVisibleDirectly(false /* visible */);
+ }
+ mAnimation.start();
+ if (show) {
+ // When showing away, queue up insets change last, otherwise any bounds changes
+ // can have a "flicker" of ime-provided insets.
+ setVisibleDirectly(true /* visible */);
+ }
+ });
+ }
+ }
+
+ /**
+ * Allows other things to synchronize with the ime position
+ */
+ public interface ImePositionProcessor {
+ /**
+ * Called when the IME position is starting to animate.
+ */
+ void onImeStartPositioning(int displayId, int imeTop, int finalImeTop, boolean showing,
+ SurfaceControl.Transaction t);
+
+ /**
+ * Called when the ime position changed. This is expected to be a synchronous call on the
+ * animation thread. Operations can be added to the transaction to be applied in sync.
+ */
+ void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t);
+
+ /**
+ * Called when the IME position is done animating.
+ */
+ void onImeEndPositioning(int displayId, int imeTop, boolean showing,
+ SurfaceControl.Transaction t);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index b70fdbd4a2d8..eccf09633f16 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -19,7 +19,7 @@ package com.android.keyguard;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.DATA_ROAMING_ENABLE;
-import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
+import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertFalse;
@@ -83,14 +83,14 @@ public class CarrierTextControllerTest extends SysuiTestCase {
private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
private static final int TEST_CARRIER_ID = 1;
private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, null,
TEST_CARRIER_ID, 0);
private static final SubscriptionInfo TEST_SUBSCRIPTION_NULL = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, null, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", DATA_ROAMING_DISABLE,
+ TEST_CARRIER, null, NAME_SOURCE_DEFAULT, 0xFFFFFF, "", DATA_ROAMING_DISABLE,
null, null, null, null, false, null, "");
private static final SubscriptionInfo TEST_SUBSCRIPTION_ROAMING = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_ENABLE, null, null, null, null, false, null, "");
@Mock
private WifiManager mWifiManager;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 40ea6ddbbe38..2e0fb3bc850d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -17,7 +17,7 @@
package com.android.keyguard;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
-import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
+import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
import static com.google.common.truth.Truth.assertThat;
@@ -84,11 +84,11 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private static final int TEST_CARRIER_ID = 1;
private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(1, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
TEST_CARRIER_ID, 0);
private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(2, "", 0,
- TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
TEST_CARRIER_ID, 0);
@Mock
@@ -150,10 +150,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void testReceiversRegistered() {
- verify(mBroadcastDispatcher, atLeastOnce()).registerReceiver(
+ verify(mBroadcastDispatcher, atLeastOnce()).registerReceiverWithHandler(
eq(mKeyguardUpdateMonitor.mBroadcastReceiver),
any(IntentFilter.class), any(Handler.class));
- verify(mBroadcastDispatcher, atLeastOnce()).registerReceiver(
+ verify(mBroadcastDispatcher, atLeastOnce()).registerReceiverWithHandler(
eq(mKeyguardUpdateMonitor.mBroadcastAllReceiver),
any(IntentFilter.class), any(Handler.class), eq(UserHandle.ALL));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
index 42fbf59fef44..22b18373e81d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -27,6 +27,8 @@ import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
import junit.framework.Assert.assertSame
import org.junit.Before
import org.junit.Test
@@ -39,6 +41,7 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import java.util.concurrent.Executor
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
@@ -73,6 +76,8 @@ class BroadcastDispatcherTest : SysuiTestCase() {
@Mock
private lateinit var mockHandler: Handler
+ private lateinit var executor: Executor
+
@Captor
private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData>
@@ -83,6 +88,7 @@ class BroadcastDispatcherTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
testableLooper = TestableLooper.get(this)
+ executor = FakeExecutor(FakeSystemClock())
broadcastDispatcher = TestBroadcastDispatcher(
mockContext,
@@ -98,8 +104,9 @@ class BroadcastDispatcherTest : SysuiTestCase() {
@Test
fun testAddingReceiverToCorrectUBR() {
- broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user0)
- broadcastDispatcher.registerReceiver(
+ broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
+ mockHandler, user0)
+ broadcastDispatcher.registerReceiverWithHandler(
broadcastReceiverOther, intentFilterOther, mockHandler, user1)
testableLooper.processAllMessages()
@@ -115,9 +122,29 @@ class BroadcastDispatcherTest : SysuiTestCase() {
}
@Test
+ fun testAddingReceiverToCorrectUBR_executor() {
+ broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, executor, user0)
+ broadcastDispatcher.registerReceiver(
+ broadcastReceiverOther, intentFilterOther, executor, user1)
+
+ testableLooper.processAllMessages()
+
+ verify(mockUBRUser0).registerReceiver(capture(argumentCaptor))
+
+ assertSame(broadcastReceiver, argumentCaptor.value.receiver)
+ assertSame(intentFilter, argumentCaptor.value.filter)
+
+ verify(mockUBRUser1).registerReceiver(capture(argumentCaptor))
+ assertSame(broadcastReceiverOther, argumentCaptor.value.receiver)
+ assertSame(intentFilterOther, argumentCaptor.value.filter)
+ }
+
+ @Test
fun testRemovingReceiversRemovesFromAllUBR() {
- broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user0)
- broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user1)
+ broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
+ mockHandler, user0)
+ broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
+ mockHandler, user1)
broadcastDispatcher.unregisterReceiver(broadcastReceiver)
@@ -129,8 +156,10 @@ class BroadcastDispatcherTest : SysuiTestCase() {
@Test
fun testRemoveReceiverFromUser() {
- broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user0)
- broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user1)
+ broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
+ mockHandler, user0)
+ broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
+ mockHandler, user1)
broadcastDispatcher.unregisterReceiverForUser(broadcastReceiver, user0)
@@ -143,8 +172,8 @@ class BroadcastDispatcherTest : SysuiTestCase() {
@Test
fun testRegisterCurrentAsActualUser() {
setUserMock(mockContext, user1)
- broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler,
- UserHandle.CURRENT)
+ broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
+ mockHandler, UserHandle.CURRENT)
testableLooper.processAllMessages()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
index 21ed15517752..7821ae29592e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
@@ -26,6 +26,8 @@ import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
@@ -69,8 +71,6 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
@Mock
private lateinit var mockContext: Context
@Mock
- private lateinit var mockHandler: Handler
- @Mock
private lateinit var mPendingResult: BroadcastReceiver.PendingResult
@Captor
@@ -81,12 +81,14 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
private lateinit var intentFilter: IntentFilter
private lateinit var intentFilterOther: IntentFilter
private lateinit var handler: Handler
+ private lateinit var fakeExecutor: FakeExecutor
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
testableLooper = TestableLooper.get(this)
handler = Handler(testableLooper.looper)
+ fakeExecutor = FakeExecutor(FakeSystemClock())
userBroadcastDispatcher = UserBroadcastDispatcher(
mockContext, USER_ID, handler, testableLooper.looper)
@@ -108,7 +110,7 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
intentFilter = IntentFilter(ACTION_1)
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE))
+ ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
testableLooper.processAllMessages()
assertTrue(userBroadcastDispatcher.isRegistered())
@@ -128,7 +130,7 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
intentFilter = IntentFilter(ACTION_1)
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE))
+ ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
testableLooper.processAllMessages()
reset(mockContext)
@@ -151,9 +153,9 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
}
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE))
+ ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiverOther, intentFilterOther, mockHandler, USER_HANDLE))
+ ReceiverData(broadcastReceiverOther, intentFilterOther, fakeExecutor, USER_HANDLE))
testableLooper.processAllMessages()
assertTrue(userBroadcastDispatcher.isRegistered())
@@ -179,14 +181,15 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
intentFilterOther = IntentFilter(ACTION_2)
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE))
+ ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiverOther, intentFilterOther, handler, USER_HANDLE))
+ ReceiverData(broadcastReceiverOther, intentFilterOther, fakeExecutor, USER_HANDLE))
val intent = Intent(ACTION_2)
userBroadcastDispatcher.onReceive(mockContext, intent)
testableLooper.processAllMessages()
+ fakeExecutor.runAllReady()
verify(broadcastReceiver, never()).onReceive(any(), any())
verify(broadcastReceiverOther).onReceive(mockContext, intent)
@@ -198,14 +201,15 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
intentFilterOther = IntentFilter(ACTION_2)
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE))
+ ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiver, intentFilterOther, handler, USER_HANDLE))
+ ReceiverData(broadcastReceiver, intentFilterOther, fakeExecutor, USER_HANDLE))
val intent = Intent(ACTION_2)
userBroadcastDispatcher.onReceive(mockContext, intent)
testableLooper.processAllMessages()
+ fakeExecutor.runAllReady()
verify(broadcastReceiver).onReceive(mockContext, intent)
}
@@ -218,14 +222,15 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
intentFilterOther.addCategory(CATEGORY_2)
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE))
+ ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiverOther, intentFilterOther, handler, USER_HANDLE))
+ ReceiverData(broadcastReceiverOther, intentFilterOther, fakeExecutor, USER_HANDLE))
val intent = Intent(ACTION_1)
userBroadcastDispatcher.onReceive(mockContext, intent)
testableLooper.processAllMessages()
+ fakeExecutor.runAllReady()
verify(broadcastReceiver).onReceive(mockContext, intent)
verify(broadcastReceiverOther).onReceive(mockContext, intent)
@@ -235,12 +240,13 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
fun testPendingResult() {
intentFilter = IntentFilter(ACTION_1)
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE))
+ ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
val intent = Intent(ACTION_1)
userBroadcastDispatcher.onReceive(mockContext, intent)
testableLooper.processAllMessages()
+ fakeExecutor.runAllReady()
verify(broadcastReceiver).onReceive(mockContext, intent)
verify(broadcastReceiver).pendingResult = mPendingResult
@@ -250,15 +256,16 @@ class UserBroadcastDispatcherTest : SysuiTestCase() {
fun testRemoveReceiverReferences() {
intentFilter = IntentFilter(ACTION_1)
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE))
+ ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
intentFilterOther = IntentFilter(ACTION_1)
intentFilterOther.addAction(ACTION_2)
userBroadcastDispatcher.registerReceiver(
- ReceiverData(broadcastReceiverOther, intentFilterOther, handler, USER_HANDLE))
+ ReceiverData(broadcastReceiverOther, intentFilterOther, fakeExecutor, USER_HANDLE))
userBroadcastDispatcher.unregisterReceiver(broadcastReceiver)
testableLooper.processAllMessages()
+ fakeExecutor.runAllReady()
assertFalse(userBroadcastDispatcher.isReceiverReferenceHeld(broadcastReceiver))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 167f361b341a..548da8e1f2aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -110,7 +110,7 @@ public class PowerUITest extends SysuiTestCase {
@Test
public void testReceiverIsRegisteredToDispatcherOnStart() {
mPowerUI.start();
- verify(mBroadcastDispatcher).registerReceiver(
+ verify(mBroadcastDispatcher).registerReceiverWithHandler(
any(BroadcastReceiver.class),
any(IntentFilter.class),
any(Handler.class)); //PowerUI does not call with User
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 40b0ba9bf633..77659df738c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -345,7 +345,7 @@ public class NotificationTestHelper {
NotificationContentInflater.InflationCallback callback =
new NotificationContentInflater.InflationCallback() {
@Override
- public void handleInflationException(StatusBarNotification notification,
+ public void handleInflationException(NotificationEntry entry,
Exception e) {
countDownLatch.countDown();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index f55ea4ff8ef2..cd33cf922482 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -65,6 +65,7 @@ import com.android.systemui.ForegroundServiceController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -82,6 +83,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
@@ -143,6 +145,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Mock private RowInflaterTask mAsyncInflationTask;
@Mock private NotificationRowBinder mMockedRowBinder;
@Mock private NotifLog mNotifLog;
+ @Mock private FeatureFlags mFeatureFlags;
private int mId;
private NotificationEntry mEntry;
@@ -219,6 +222,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntry.expandedIcon = mock(StatusBarIconView.class);
+ when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false);
+ when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
mEntryManager = new TestableNotificationEntryManager(
mNotifLog,
mGroupManager,
@@ -229,8 +234,10 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mock(NotificationFilter.class),
mNotifLog,
mock(NotificationSectionsFeatureManager.class),
- mock(PeopleNotificationIdentifier.class)),
- mEnvironment
+ mock(PeopleNotificationIdentifier.class),
+ mock(HighPriorityProvider.class)),
+ mEnvironment,
+ mFeatureFlags
);
mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
mEntryManager.addNotificationEntryListener(mEntryListener);
@@ -242,7 +249,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mock(StatusBarStateController.class),
mock(NotificationLogger.class));
notificationRowBinder.setUpWithPresenter(
- mPresenter, mListContainer, mHeadsUpManager, mEntryManager, mBindCallback);
+ mPresenter, mListContainer, mHeadsUpManager, mBindCallback);
+ notificationRowBinder.setInflationCallback(mEntryManager);
notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
mEntryManager.setRowBinder(notificationRowBinder);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
index 34beefe9843b..1afee120e495 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification
+import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
@@ -33,8 +34,9 @@ class TestableNotificationEntryManager(
log: NotifLog,
gm: NotificationGroupManager,
rm: NotificationRankingManager,
- ke: KeyguardEnvironment
-) : NotificationEntryManager(log, gm, rm, ke) {
+ ke: KeyguardEnvironment,
+ ff: FeatureFlags
+) : NotificationEntryManager(log, gm, rm, ke, ff) {
public var countDownLatch: CountDownLatch = CountDownLatch(1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java
deleted file mode 100644
index a06d6c1e593b..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java
+++ /dev/null
@@ -1,148 +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 com.android.systemui.statusbar.notification.collection;
-
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.testing.AndroidTestingRunner;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.RankingBuilder;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class GroupEntryTest extends SysuiTestCase {
- @Test
- public void testIsHighPriority_addChild() {
- // GIVEN a GroupEntry with a lowPrioritySummary and no children
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
- final NotificationEntry lowPrioritySummary = createNotifEntry(false);
- setSummary(parentEntry, lowPrioritySummary);
- assertFalse(parentEntry.isHighPriority());
-
- // WHEN we add a high priority child and invalidate derived members
- addChild(parentEntry, createNotifEntry(true));
- parentEntry.invalidateDerivedMembers();
-
- // THEN the GroupEntry's priority is updated to high even though the summary is still low
- // priority
- assertTrue(parentEntry.isHighPriority());
- assertFalse(lowPrioritySummary.isHighPriority());
- }
-
- @Test
- public void testIsHighPriority_clearChildren() {
- // GIVEN a GroupEntry with a lowPrioritySummary and high priority children
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
- setSummary(parentEntry, createNotifEntry(false));
- addChild(parentEntry, createNotifEntry(true));
- addChild(parentEntry, createNotifEntry(true));
- addChild(parentEntry, createNotifEntry(true));
- assertTrue(parentEntry.isHighPriority());
-
- // WHEN we clear the children and invalidate derived members
- parentEntry.clearChildren();
- parentEntry.invalidateDerivedMembers();
-
- // THEN the parentEntry isn't high priority anymore
- assertFalse(parentEntry.isHighPriority());
- }
-
- @Test
- public void testIsHighPriority_summaryUpdated() {
- // GIVEN a GroupEntry with a lowPrioritySummary and no children
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
- final NotificationEntry lowPrioritySummary = createNotifEntry(false);
- setSummary(parentEntry, lowPrioritySummary);
- assertFalse(parentEntry.isHighPriority());
-
- // WHEN the summary changes to high priority and invalidates its derived members
- lowPrioritySummary.setRanking(
- new RankingBuilder()
- .setKey(lowPrioritySummary.getKey())
- .setImportance(IMPORTANCE_HIGH)
- .build());
- lowPrioritySummary.invalidateDerivedMembers();
- assertTrue(lowPrioritySummary.isHighPriority());
-
- // THEN the GroupEntry's priority is updated to high
- assertTrue(parentEntry.isHighPriority());
- }
-
- @Test
- public void testIsHighPriority_checkChildrenToCalculatePriority() {
- // GIVEN:
- // GroupEntry = parentEntry, summary = lowPrioritySummary
- // NotificationEntry = lowPriorityChild
- // NotificationEntry = highPriorityChild
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
- setSummary(parentEntry, createNotifEntry(false));
- addChild(parentEntry, createNotifEntry(false));
- addChild(parentEntry, createNotifEntry(true));
-
- // THEN the GroupEntry parentEntry is high priority since it has a high priority child
- assertTrue(parentEntry.isHighPriority());
- }
-
- @Test
- public void testIsHighPriority_childEntryRankingUpdated() {
- // GIVEN:
- // GroupEntry = parentEntry, summary = lowPrioritySummary
- // NotificationEntry = lowPriorityChild
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
- final NotificationEntry lowPriorityChild = createNotifEntry(false);
- setSummary(parentEntry, createNotifEntry(false));
- addChild(parentEntry, lowPriorityChild);
-
- // WHEN the child entry ranking changes to high priority and invalidates its derived members
- lowPriorityChild.setRanking(
- new RankingBuilder()
- .setKey(lowPriorityChild.getKey())
- .setImportance(IMPORTANCE_HIGH)
- .build());
- lowPriorityChild.invalidateDerivedMembers();
-
- // THEN the parent entry's high priority value is updated - but not the parent's summary
- assertTrue(parentEntry.isHighPriority());
- assertFalse(parentEntry.getSummary().isHighPriority());
- }
-
- private NotificationEntry createNotifEntry(boolean highPriority) {
- return new NotificationEntryBuilder()
- .setImportance(highPriority ? IMPORTANCE_HIGH : IMPORTANCE_MIN)
- .build();
- }
-
- private void setSummary(GroupEntry parent, NotificationEntry summary) {
- parent.setSummary(summary);
- summary.setParent(parent);
- }
-
- private void addChild(GroupEntry parent, NotificationEntry child) {
- parent.addChild(child);
- child.setParent(parent);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
new file mode 100644
index 000000000000..93909dc4d330
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class HighPriorityProviderTest extends SysuiTestCase {
+ @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+ private HighPriorityProvider mHighPriorityProvider;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mHighPriorityProvider = new HighPriorityProvider(mPeopleNotificationIdentifier);
+ }
+
+ @Test
+ public void highImportance() {
+ // GIVEN notification has high importance
+ final NotificationEntry entry = new NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .build();
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+
+ // THEN it has high priority
+ assertTrue(mHighPriorityProvider.isHighPriority(entry));
+ }
+
+ @Test
+ public void peopleNotification() {
+ // GIVEN notification is low importance and is a people notification
+ final Notification notification = new Notification.Builder(mContext, "test")
+ .build();
+ final NotificationEntry entry = new NotificationEntryBuilder()
+ .setNotification(notification)
+ .setImportance(IMPORTANCE_LOW)
+ .build();
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(true);
+
+ // THEN it has high priority
+ assertTrue(mHighPriorityProvider.isHighPriority(entry));
+ }
+
+ @Test
+ public void messagingStyle() {
+ // GIVEN notification is low importance but has messaging style
+ final Notification notification = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle(""))
+ .build();
+ final NotificationEntry entry = new NotificationEntryBuilder()
+ .setNotification(notification)
+ .build();
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+
+ // THEN it has high priority
+ assertTrue(mHighPriorityProvider.isHighPriority(entry));
+ }
+
+ @Test
+ public void lowImportanceForeground() {
+ // GIVEN notification is low importance and is associated with a foreground service
+ final Notification notification = mock(Notification.class);
+ when(notification.isForegroundService()).thenReturn(true);
+
+ final NotificationEntry entry = new NotificationEntryBuilder()
+ .setNotification(notification)
+ .setImportance(IMPORTANCE_LOW)
+ .build();
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+
+ // THEN it has high priority
+ assertTrue(mHighPriorityProvider.isHighPriority(entry));
+ }
+
+ @Test
+ public void minImportanceForeground() {
+ // GIVEN notification is low importance and is associated with a foreground service
+ final Notification notification = mock(Notification.class);
+ when(notification.isForegroundService()).thenReturn(true);
+
+ final NotificationEntry entry = new NotificationEntryBuilder()
+ .setNotification(notification)
+ .setImportance(IMPORTANCE_MIN)
+ .build();
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+
+ // THEN it does NOT have high priority
+ assertFalse(mHighPriorityProvider.isHighPriority(entry));
+ }
+
+ @Test
+ public void userChangeTrumpsHighPriorityCharacteristics() {
+ // GIVEN notification has high priority characteristics but the user changed the importance
+ // to less than IMPORTANCE_DEFAULT (ie: IMPORTANCE_LOW or IMPORTANCE_MIN)
+ final Notification notification = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle(""))
+ .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+ .build();
+ final NotificationChannel channel = new NotificationChannel("a", "a",
+ IMPORTANCE_LOW);
+ channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+
+ final NotificationEntry entry = new NotificationEntryBuilder()
+ .setNotification(notification)
+ .setChannel(channel)
+ .build();
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(true);
+
+ // THEN it does NOT have high priority
+ assertFalse(mHighPriorityProvider.isHighPriority(entry));
+ }
+
+ @Test
+ public void testIsHighPriority_summaryUpdated() {
+ // GIVEN a GroupEntry with a lowPrioritySummary and no children
+ final GroupEntry parentEntry = new GroupEntry("test_group_key");
+ final NotificationEntry lowPrioritySummary = createNotifEntry(false);
+ setSummary(parentEntry, lowPrioritySummary);
+ assertFalse(mHighPriorityProvider.isHighPriority(parentEntry));
+
+ // WHEN the summary changes to high priority
+ lowPrioritySummary.setRanking(
+ new RankingBuilder()
+ .setKey(lowPrioritySummary.getKey())
+ .setImportance(IMPORTANCE_HIGH)
+ .build());
+ assertTrue(mHighPriorityProvider.isHighPriority(lowPrioritySummary));
+
+ // THEN the GroupEntry's priority is updated to high
+ assertTrue(mHighPriorityProvider.isHighPriority(parentEntry));
+ }
+
+ @Test
+ public void testIsHighPriority_checkChildrenToCalculatePriority() {
+ // GIVEN:
+ // GroupEntry = parentEntry, summary = lowPrioritySummary
+ // NotificationEntry = lowPriorityChild
+ // NotificationEntry = highPriorityChild
+ final GroupEntry parentEntry = new GroupEntry("test_group_key");
+ setSummary(parentEntry, createNotifEntry(false));
+ addChild(parentEntry, createNotifEntry(false));
+ addChild(parentEntry, createNotifEntry(true));
+
+ // THEN the GroupEntry parentEntry is high priority since it has a high priority child
+ assertTrue(mHighPriorityProvider.isHighPriority(parentEntry));
+ }
+
+ @Test
+ public void testIsHighPriority_childEntryRankingUpdated() {
+ // GIVEN:
+ // GroupEntry = parentEntry, summary = lowPrioritySummary
+ // NotificationEntry = lowPriorityChild
+ final GroupEntry parentEntry = new GroupEntry("test_group_key");
+ final NotificationEntry lowPriorityChild = createNotifEntry(false);
+ setSummary(parentEntry, createNotifEntry(false));
+ addChild(parentEntry, lowPriorityChild);
+
+ // WHEN the child entry ranking changes to high priority
+ lowPriorityChild.setRanking(
+ new RankingBuilder()
+ .setKey(lowPriorityChild.getKey())
+ .setImportance(IMPORTANCE_HIGH)
+ .build());
+
+ // THEN the parent entry's high priority value is updated - but not the parent's summary
+ assertTrue(mHighPriorityProvider.isHighPriority(parentEntry));
+ assertFalse(mHighPriorityProvider.isHighPriority(parentEntry.getSummary()));
+ }
+
+ private NotificationEntry createNotifEntry(boolean highPriority) {
+ return new NotificationEntryBuilder()
+ .setImportance(highPriority ? IMPORTANCE_HIGH : IMPORTANCE_MIN)
+ .build();
+ }
+
+ private void setSummary(GroupEntry parent, NotificationEntry summary) {
+ parent.setSummary(summary);
+ summary.setParent(parent);
+ }
+
+ private void addChild(GroupEntry parent, NotificationEntry child) {
+ parent.addChild(child);
+ child.setParent(parent);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 0837a42ae700..28feacac8c44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -24,6 +24,7 @@ import static com.android.systemui.statusbar.notification.collection.NotifCollec
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -261,9 +262,13 @@ public class NotifCollectionTest extends SysuiTestCase {
.setRank(5)
.setExplanation("baz buzz")
.build();
+
+ // WHEN entry3's ranking update includes an update to its overrideGroupKey
+ final String newOverrideGroupKey = "newOverrideGroupKey";
Ranking newRanking3 = new RankingBuilder(notif3.ranking)
.setRank(6)
.setExplanation("Penguin pizza")
+ .setOverrideGroupKey(newOverrideGroupKey)
.build();
mNoMan.setRanking(notif1.sbn.getKey(), newRanking1);
@@ -275,6 +280,10 @@ public class NotifCollectionTest extends SysuiTestCase {
assertEquals(newRanking1, entry1.getRanking());
assertEquals(newRanking2, entry2.getRanking());
assertEquals(newRanking3, entry3.getRanking());
+
+ // THEN the entry3's overrideGroupKey is updated along with its groupKey
+ assertEquals(newOverrideGroupKey, entry3.getSbn().getOverrideGroupKey());
+ assertNotNull(entry3.getSbn().getGroupKey());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 39ae68a40291..5b0b66849027 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -21,8 +21,6 @@ import static android.app.Notification.CATEGORY_CALL;
import static android.app.Notification.CATEGORY_EVENT;
import static android.app.Notification.CATEGORY_MESSAGE;
import static android.app.Notification.CATEGORY_REMINDER;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
@@ -92,44 +90,6 @@ public class NotificationEntryTest extends SysuiTestCase {
}
@Test
- public void testIsHighPriority_notificationUpdates() {
- // GIVEN a notification with high importance
- final NotificationEntry entryHigh = new NotificationEntryBuilder()
- .setImportance(IMPORTANCE_HIGH)
- .build();
-
- // WHEN we get the value for the high priority entry, we're caching the high priority value
- assertTrue(entryHigh.isHighPriority());
-
- // WHEN we change the ranking and derived members (high priority) are invalidated
- entryHigh.setRanking(
- new RankingBuilder()
- .setKey(entryHigh.getKey())
- .setImportance(IMPORTANCE_MIN)
- .build());
- entryHigh.invalidateDerivedMembers();
-
- // THEN the priority is recalculated and is now low
- assertFalse(entryHigh.isHighPriority());
-
- // WHEN the sbn is updated to have messaging style (high priority characteristic)
- // AND the entry invalidates its derived members
- final Notification notification =
- new Notification.Builder(mContext, "test")
- .setStyle(new Notification.MessagingStyle(""))
- .build();
- final StatusBarNotification sbn = entryHigh.getSbn();
- entryHigh.setSbn(new StatusBarNotification(
- sbn.getPackageName(), sbn.getPackageName(),
- sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
- notification, sbn.getUser(), sbn.getOverrideGroupKey(), 0));
- entryHigh.invalidateDerivedMembers();
-
- // THEN the priority is recalculated and is now high
- assertTrue(entryHigh.isHighPriority());
- }
-
- @Test
public void testIsExemptFromDndVisualSuppression_foreground() {
mEntry.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 10450fa82cde..e27319103525 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -28,6 +28,7 @@ import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.notification.NotificationFilter
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.logging.NotifLog
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
@@ -62,7 +63,8 @@ class NotificationRankingManagerTest : SysuiTestCase() {
mock(NotificationFilter::class.java),
mock(NotifLog::class.java),
mock(NotificationSectionsFeatureManager::class.java),
- personNotificationIdentifier
+ personNotificationIdentifier,
+ HighPriorityProvider(personNotificationIdentifier)
)
}
@@ -182,7 +184,8 @@ class NotificationRankingManagerTest : SysuiTestCase() {
filter: NotificationFilter,
notifLog: NotifLog,
sectionsFeatureManager: NotificationSectionsFeatureManager,
- peopleNotificationIdentifier: PeopleNotificationIdentifier
+ peopleNotificationIdentifier: PeopleNotificationIdentifier,
+ highPriorityProvider: HighPriorityProvider
) : NotificationRankingManager(
mediaManager,
groupManager,
@@ -190,7 +193,8 @@ class NotificationRankingManagerTest : SysuiTestCase() {
filter,
notifLog,
sectionsFeatureManager,
- peopleNotificationIdentifier
+ peopleNotificationIdentifier,
+ highPriorityProvider
) {
fun applyTestRankingMap(r: RankingMap) {
rankingMap = r
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index 979b8a906ef0..f921cf969e61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -45,6 +45,7 @@ import com.android.systemui.statusbar.notification.collection.NotifListBuilderIm
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
@@ -66,6 +67,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock private HighPriorityProvider mHighPriorityProvider;
@Mock private NotifListBuilderImpl mNotifListBuilder;
private NotificationEntry mEntry;
@@ -78,7 +80,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
mKeyguardCoordinator = new KeyguardCoordinator(
mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
mBroadcastDispatcher, mStatusBarStateController,
- mKeyguardUpdateMonitor);
+ mKeyguardUpdateMonitor, mHighPriorityProvider);
mEntry = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java
deleted file mode 100644
index 6fa1a89515c3..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java
+++ /dev/null
@@ -1,184 +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 com.android.systemui.statusbar.notification.collection.provider;
-
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_LOW;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.Person;
-import android.testing.AndroidTestingRunner;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class IsHighPriorityProviderTest extends SysuiTestCase {
- private IsHighPriorityProvider mIsHighPriorityProvider;
-
- @Before
- public void setup() {
- mIsHighPriorityProvider = new IsHighPriorityProvider();
- }
-
- @Test
- public void testCache() {
- // GIVEN a notification with high importance
- final NotificationEntry entryHigh = new NotificationEntryBuilder()
- .setImportance(IMPORTANCE_HIGH)
- .build();
-
- // GIVEN notification with min importance
- final NotificationEntry entryMin = new NotificationEntryBuilder()
- .setImportance(IMPORTANCE_MIN)
- .build();
-
- // WHEN we get the value for the high priority entry
- assertTrue(mIsHighPriorityProvider.get(entryHigh));
-
- // THEN the value is cached, so even when passed an entryMin, we still get high priority
- assertTrue(mIsHighPriorityProvider.get(entryMin));
-
- // UNTIL the provider is invalidated
- mIsHighPriorityProvider.invalidate();
-
- // THEN the priority is recalculated
- assertFalse(mIsHighPriorityProvider.get(entryMin));
- }
-
- @Test
- public void highImportance() {
- // GIVEN notification has high importance
- final NotificationEntry entry = new NotificationEntryBuilder()
- .setImportance(IMPORTANCE_HIGH)
- .build();
-
- // THEN it has high priority
- assertTrue(mIsHighPriorityProvider.get(entry));
- }
-
- @Test
- public void peopleNotification() {
- // GIVEN notification is low importance but has a person associated with it
- final Notification notification = new Notification.Builder(mContext, "test")
- .addPerson(
- new Person.Builder()
- .setName("name")
- .setKey("abc")
- .setUri("uri")
- .setBot(true)
- .build())
- .build();
-
- final NotificationEntry entry = new NotificationEntryBuilder()
- .setNotification(notification)
- .setImportance(IMPORTANCE_LOW)
- .build();
-
- // THEN it has high priority
- assertTrue(mIsHighPriorityProvider.get(entry));
- }
-
- @Test
- public void messagingStyle() {
- // GIVEN notification is low importance but has messaging style
- final Notification notification = new Notification.Builder(mContext, "test")
- .setStyle(new Notification.MessagingStyle(""))
- .build();
-
- final NotificationEntry entry = new NotificationEntryBuilder()
- .setNotification(notification)
- .build();
-
- // THEN it has high priority
- assertTrue(mIsHighPriorityProvider.get(entry));
- }
-
- @Test
- public void lowImportanceForeground() {
- // GIVEN notification is low importance and is associated with a foreground service
- final Notification notification = mock(Notification.class);
- when(notification.isForegroundService()).thenReturn(true);
-
- final NotificationEntry entry = new NotificationEntryBuilder()
- .setNotification(notification)
- .setImportance(IMPORTANCE_LOW)
- .build();
-
- // THEN it has high priority
- assertTrue(mIsHighPriorityProvider.get(entry));
- }
-
- @Test
- public void minImportanceForeground() {
- // GIVEN notification is low importance and is associated with a foreground service
- final Notification notification = mock(Notification.class);
- when(notification.isForegroundService()).thenReturn(true);
-
- final NotificationEntry entry = new NotificationEntryBuilder()
- .setNotification(notification)
- .setImportance(IMPORTANCE_MIN)
- .build();
-
- // THEN it does NOT have high priority
- assertFalse(mIsHighPriorityProvider.get(entry));
- }
-
- @Test
- public void userChangeTrumpsHighPriorityCharacteristics() {
- // GIVEN notification has high priority characteristics but the user changed the importance
- // to less than IMPORTANCE_DEFAULT (ie: IMPORTANCE_LOW or IMPORTANCE_MIN)
- final Notification notification = new Notification.Builder(mContext, "test")
- .addPerson(
- new Person.Builder()
- .setName("name")
- .setKey("abc")
- .setUri("uri")
- .setBot(true)
- .build())
- .setStyle(new Notification.MessagingStyle(""))
- .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
- .build();
-
- final NotificationChannel channel = new NotificationChannel("a", "a",
- IMPORTANCE_LOW);
- channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
-
- final NotificationEntry entry = new NotificationEntryBuilder()
- .setNotification(notification)
- .setChannel(channel)
- .build();
-
- // THEN it does NOT have high priority
- assertFalse(mIsHighPriorityProvider.get(entry));
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
index 0764d0cd4b88..867a9b97d622 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -178,9 +178,10 @@ private fun <T> castNull(): T = null as T
private fun fakePersonModel(
id: String,
name: CharSequence,
- clickIntent: PendingIntent
+ clickIntent: PendingIntent,
+ userId: Int = 0
): PersonModel =
- PersonModel(id, name, mock(Drawable::class.java), clickIntent)
+ PersonModel(id, name, mock(Drawable::class.java), clickIntent, userId)
private fun fakePersonViewModel(name: CharSequence): PersonViewModel =
PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass))
@@ -207,4 +208,4 @@ class FakeDataListener<T> : DataListener<T> {
override fun onDataChanged(data: T) {
lastSeen = Maybe.Just(data)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index dc4e4980e443..f916fe5ad7fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -33,7 +33,6 @@ import android.content.Context;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
-import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.util.ArrayMap;
@@ -179,7 +178,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
true /* isNewView */, (v, p, r) -> true,
new InflationCallback() {
@Override
- public void handleInflationException(StatusBarNotification notification,
+ public void handleInflationException(NotificationEntry entry,
Exception e) {
countDownLatch.countDown();
throw new RuntimeException("No Exception expected");
@@ -261,7 +260,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
inflater.setInflateSynchronously(true);
InflationCallback callback = new InflationCallback() {
@Override
- public void handleInflationException(StatusBarNotification notification,
+ public void handleInflationException(NotificationEntry entry,
Exception e) {
if (!expectingException) {
exceptionHolder.setException(e);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index ccc9496368e9..4e27770982e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -70,6 +70,7 @@ import com.android.systemui.statusbar.NotificationTestHelper;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -113,6 +114,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@Mock private StatusBar mStatusBar;
@Mock private AccessibilityManager mAccessibilityManager;
+ @Mock private HighPriorityProvider mHighPriorityProvider;
@Before
public void setUp() {
@@ -128,7 +130,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager,
- () -> mStatusBar, mHandler, mAccessibilityManager);
+ () -> mStatusBar, mHandler, mAccessibilityManager, mHighPriorityProvider);
mGutsManager.setUpWithPresenter(mPresenter, mStackScroller,
mCheckSaveListener, mOnSettingsClickListener);
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
@@ -391,6 +393,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
.build();
when(row.getIsNonblockable()).thenReturn(false);
+ when(mHighPriorityProvider.isHighPriority(entry)).thenReturn(true);
StatusBarNotification statusBarNotification = entry.getSbn();
mGutsManager.initializeNotificationInfo(row, notificationInfoView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 003d80376c40..518b6703391e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -267,8 +267,6 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
ExpandableNotificationRow notifRow = mock(ExpandableNotificationRow.class,
RETURNS_DEEP_STUBS);
when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
- when(notifRow.getEntry().isHighPriority())
- .thenReturn(children[i] == ChildType.HIPRI);
when(notifRow.getEntry().getBucket()).thenReturn(
children[i] == ChildType.HIPRI ? BUCKET_ALERTING : BUCKET_SILENT);
when(notifRow.getParent()).thenReturn(mNssl);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 77a6a2602d8e..ea8d4ee20aab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -53,6 +53,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.EmptyShadeView;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -70,6 +71,7 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
@@ -164,9 +166,11 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mock(NotificationFilter.class),
mock(NotifLog.class),
mock(NotificationSectionsFeatureManager.class),
- mock(PeopleNotificationIdentifier.class)
+ mock(PeopleNotificationIdentifier.class),
+ mock(HighPriorityProvider.class)
),
- mock(NotificationEntryManager.KeyguardEnvironment.class));
+ mock(NotificationEntryManager.KeyguardEnvironment.class),
+ mock(FeatureFlags.class));
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 39afbe0a1a23..8f645b6bd3c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -190,7 +190,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
mFragments.dispatchResume();
processAllMessages();
- verify(mBroadcastDispatcher).registerReceiver(
+ verify(mBroadcastDispatcher).registerReceiverWithHandler(
any(BroadcastReceiver.class),
any(IntentFilter.class),
any(Handler.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 2854665aedb1..80aa6f6c49bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -69,7 +69,7 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
@Test
public void testRegisteredWithDispatcher() {
- verify(mBroadcastDispatcher).registerReceiver(any(BroadcastReceiver.class),
+ verify(mBroadcastDispatcher).registerReceiverWithHandler(any(BroadcastReceiver.class),
any(IntentFilter.class),
any(Handler.class)); // VolumeDialogControllerImpl does not call with user
}
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 0be853a81fb2..d297f3f84189 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -20,7 +20,7 @@ java_defaults {
srcs: [
"src/**/*.java",
":framework-tethering-shared-srcs",
- ":net-module-utils-srcs",
+ ":tethering-module-utils-srcs",
":services-tethering-shared-srcs",
],
static_libs: [
@@ -123,4 +123,5 @@ android_app {
use_embedded_native_libs: true,
// The permission configuration *must* be included to ensure security of the device
required: ["NetworkPermissionConfig"],
+ apex_available: ["com.android.tethering"],
}
diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml
index 87a8c3f5c68a..e99c2c529bd2 100644
--- a/packages/Tethering/AndroidManifest.xml
+++ b/packages/Tethering/AndroidManifest.xml
@@ -33,6 +33,7 @@
<uses-permission android:name="android.permission.MANAGE_USB" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+ <uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 5785707cb9c5..264ce440f59f 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -47,6 +47,16 @@ java_library {
libs: [
"android_system_stubs_current",
],
+
+ hostdex: true, // for hiddenapi check
+ visibility: [
+ "//frameworks/base/packages/Tethering:__subpackages__",
+ //TODO(b/147200698) remove below lines when the platform is built with stubs
+ "//frameworks/base",
+ "//frameworks/base/services",
+ "//frameworks/base/services/core",
+ ],
+ apex_available: ["com.android.tethering"],
}
filegroup {
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index a49ab85d2faf..11e57186c666 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -15,8 +15,6 @@
*/
package android.net;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-
import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager.OnTetheringEventCallback;
@@ -52,6 +50,103 @@ public class TetheringManager {
private TetheringConfigurationParcel mTetheringConfiguration;
private TetherStatesParcel mTetherStatesParcel;
+ /**
+ * Broadcast Action: A tetherable connection has come or gone.
+ * Uses {@code TetheringManager.EXTRA_AVAILABLE_TETHER},
+ * {@code TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY},
+ * {@code TetheringManager.EXTRA_ACTIVE_TETHER}, and
+ * {@code TetheringManager.EXTRA_ERRORED_TETHER} to indicate
+ * the current state of tethering. Each include a list of
+ * interface names in that state (may be empty).
+ */
+ public static final String ACTION_TETHER_STATE_CHANGED =
+ "android.net.conn.TETHER_STATE_CHANGED";
+
+ /**
+ * gives a String[] listing all the interfaces configured for
+ * tethering and currently available for tethering.
+ */
+ public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+
+ /**
+ * gives a String[] listing all the interfaces currently in local-only
+ * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
+ */
+ public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray";
+
+ /**
+ * gives a String[] listing all the interfaces currently tethered
+ * (ie, has DHCPv4 support and packets potentially forwarded/NATed)
+ */
+ public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+
+ /**
+ * gives a String[] listing all the interfaces we tried to tether and
+ * failed. Use {@link #getLastTetherError} to find the error code
+ * for any interfaces listed here.
+ */
+ public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+
+ /**
+ * Invalid tethering type.
+ * @see #startTethering.
+ */
+ public static final int TETHERING_INVALID = -1;
+
+ /**
+ * Wifi tethering type.
+ * @see #startTethering.
+ */
+ public static final int TETHERING_WIFI = 0;
+
+ /**
+ * USB tethering type.
+ * @see #startTethering.
+ */
+ public static final int TETHERING_USB = 1;
+
+ /**
+ * Bluetooth tethering type.
+ * @see #startTethering.
+ */
+ public static final int TETHERING_BLUETOOTH = 2;
+
+ /**
+ * Wifi P2p tethering type.
+ * Wifi P2p tethering is set through events automatically, and don't
+ * need to start from #startTethering.
+ */
+ public static final int TETHERING_WIFI_P2P = 3;
+
+ /**
+ * Extra used for communicating with the TetherService. Includes the type of tethering to
+ * enable if any.
+ */
+ public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+
+ /**
+ * Extra used for communicating with the TetherService. Includes the type of tethering for
+ * which to cancel provisioning.
+ */
+ public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
+
+ /**
+ * Extra used for communicating with the TetherService. True to schedule a recheck of tether
+ * provisioning.
+ */
+ public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+
+ /**
+ * Tells the TetherService to run a provision check now.
+ */
+ public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
+
+ /**
+ * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
+ * which will receive provisioning results. Can be left empty.
+ */
+ public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+
public static final int TETHER_ERROR_NO_ERROR = 0;
public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
@@ -470,7 +565,7 @@ public class TetheringManager {
* failed. Re-attempting to tether may cause them to reset to the Tethered
* state. Alternatively, causing the interface to be destroyed and recreated
* may cause them to reset to the available state.
- * {@link ConnectivityManager#getLastTetherError} can be used to get more
+ * {@link TetheringManager#getLastTetherError} can be used to get more
* information on the cause of the errors.
*
* @return an array of 0 or more String indicating the interface names
diff --git a/packages/Tethering/jarjar-rules.txt b/packages/Tethering/jarjar-rules.txt
index d93531bac58e..c6efa41e580a 100644
--- a/packages/Tethering/jarjar-rules.txt
+++ b/packages/Tethering/jarjar-rules.txt
@@ -11,6 +11,7 @@ rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering.
rule com.android.internal.util.Preconditions* com.android.networkstack.tethering.util.Preconditions@1
rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1
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
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index abfb33c7af9e..6ac467e39a9d 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -24,25 +24,24 @@ import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
import static android.net.util.NetworkConstants.asByte;
import static android.net.util.TetheringMessageBase.BASE_IPSERVER;
-import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkStackStatusCallback;
import android.net.INetworkStatsService;
-import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
+import android.net.TetheringManager;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.DhcpServingParamsParcelExt;
import android.net.dhcp.IDhcpServer;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
+import android.net.shared.NetdUtils;
+import android.net.shared.RouteUtils;
import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
-import android.net.util.NetdService;
import android.net.util.SharedLog;
-import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
@@ -119,7 +118,7 @@ public class IpServer extends StateMachine {
*
* @param who the calling instance of IpServer
* @param state one of STATE_*
- * @param lastError one of ConnectivityManager.TETHER_ERROR_*
+ * @param lastError one of TetheringManager.TETHER_ERROR_*
*/
public void updateInterfaceState(IpServer who, int state, int lastError) { }
@@ -144,10 +143,6 @@ public class IpServer extends StateMachine {
return InterfaceParams.getByName(ifName);
}
- public INetd getNetdService() {
- return NetdService.getInstance();
- }
-
/** Create a DhcpServer instance to be used by IpServer. */
public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
DhcpServerCallbacks cb);
@@ -180,7 +175,6 @@ public class IpServer extends StateMachine {
private final State mUnavailableState;
private final SharedLog mLog;
- private final INetworkManagementService mNMService;
private final INetd mNetd;
private final INetworkStatsService mStatsService;
private final Callback mCallback;
@@ -210,15 +204,15 @@ public class IpServer extends StateMachine {
private int mDhcpServerStartIndex = 0;
private IDhcpServer mDhcpServer;
private RaParams mLastRaParams;
+ private LinkAddress mIpv4Address;
public IpServer(
String ifaceName, Looper looper, int interfaceType, SharedLog log,
- INetworkManagementService nMService, INetworkStatsService statsService,
- Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
+ INetd netd, INetworkStatsService statsService, Callback callback,
+ boolean usingLegacyDhcp, Dependencies deps) {
super(ifaceName, looper);
mLog = log.forSubComponent(ifaceName);
- mNMService = nMService;
- mNetd = deps.getNetdService();
+ mNetd = netd;
mStatsService = statsService;
mCallback = callback;
mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog);
@@ -228,7 +222,7 @@ public class IpServer extends StateMachine {
mUsingLegacyDhcp = usingLegacyDhcp;
mDeps = deps;
resetLinkProperties();
- mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
mServingMode = STATE_AVAILABLE;
mInitialState = new InitialState();
@@ -249,7 +243,7 @@ public class IpServer extends StateMachine {
}
/**
- * Tethering downstream type. It would be one of ConnectivityManager#TETHERING_*.
+ * Tethering downstream type. It would be one of TetheringManager#TETHERING_*.
*/
public int interfaceType() {
return mInterfaceType;
@@ -347,13 +341,13 @@ public class IpServer extends StateMachine {
}
});
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw new IllegalStateException(e);
}
});
}
private void handleError() {
- mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
transitionTo(mInitialState);
}
}
@@ -388,14 +382,15 @@ public class IpServer extends StateMachine {
public void callback(int statusCode) {
if (statusCode != STATUS_SUCCESS) {
mLog.e("Error stopping DHCP server: " + statusCode);
- mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
// Not much more we can do here
}
}
});
mDhcpServer = null;
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ mLog.e("Error stopping DHCP", e);
+ // Not much more we can do here
}
}
}
@@ -414,85 +409,69 @@ public class IpServer extends StateMachine {
// NOTE: All of configureIPv4() will be refactored out of existence
// into calls to InterfaceController, shared with startIPv4().
mInterfaceCtrl.clearIPv4Address();
+ mIpv4Address = null;
}
- // TODO: Refactor this in terms of calls to InterfaceController.
private boolean configureIPv4(boolean enabled) {
if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
// TODO: Replace this hard-coded information with dynamically selected
// config passed down to us by a higher layer IP-coordinating element.
- String ipAsString = null;
+ final Inet4Address srvAddr;
int prefixLen = 0;
- if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
- ipAsString = USB_NEAR_IFACE_ADDR;
- prefixLen = USB_PREFIX_LENGTH;
- } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
- ipAsString = getRandomWifiIPv4Address();
- prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
- } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI_P2P) {
- ipAsString = WIFI_P2P_IFACE_ADDR;
- prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
- } else {
- // BT configures the interface elsewhere: only start DHCP.
- final Inet4Address srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR);
- return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
- }
-
- final LinkAddress linkAddr;
try {
- final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
- if (ifcg == null) {
- mLog.e("Received null interface config");
- return false;
- }
-
- InetAddress addr = parseNumericAddress(ipAsString);
- linkAddr = new LinkAddress(addr, prefixLen);
- ifcg.setLinkAddress(linkAddr);
- if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
- // The WiFi stack has ownership of the interface up/down state.
- // It is unclear whether the Bluetooth or USB stacks will manage their own
- // state.
- ifcg.ignoreInterfaceUpDownStatus();
+ if (mInterfaceType == TetheringManager.TETHERING_USB) {
+ srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR);
+ prefixLen = USB_PREFIX_LENGTH;
+ } else if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
+ srvAddr = (Inet4Address) parseNumericAddress(getRandomWifiIPv4Address());
+ prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
+ } else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
+ srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR);
+ prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
} else {
- if (enabled) {
- ifcg.setInterfaceUp();
- } else {
- ifcg.setInterfaceDown();
- }
+ // BT configures the interface elsewhere: only start DHCP.
+ // TODO: make all tethering types behave the same way, and delete the bluetooth
+ // code that calls into NetworkManagementService directly.
+ srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR);
+ mIpv4Address = new LinkAddress(srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
+ return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
}
- ifcg.clearFlag("running");
+ mIpv4Address = new LinkAddress(srvAddr, prefixLen);
+ } catch (IllegalArgumentException e) {
+ mLog.e("Error selecting ipv4 address", e);
+ if (!enabled) stopDhcp();
+ return false;
+ }
- // TODO: this may throw if the interface is already gone. Do proper handling and
- // simplify the DHCP server start/stop.
- mNMService.setInterfaceConfig(mIfaceName, ifcg);
+ final Boolean setIfaceUp;
+ if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
+ // The WiFi stack has ownership of the interface up/down state.
+ // It is unclear whether the Bluetooth or USB stacks will manage their own
+ // state.
+ setIfaceUp = null;
+ } else {
+ setIfaceUp = enabled;
+ }
+ if (!mInterfaceCtrl.setInterfaceConfiguration(mIpv4Address, setIfaceUp)) {
+ mLog.e("Error configuring interface");
+ if (!enabled) stopDhcp();
+ return false;
+ }
- if (!configureDhcp(enabled, (Inet4Address) addr, prefixLen)) {
- return false;
- }
- } catch (Exception e) {
- mLog.e("Error configuring interface " + e);
- if (!enabled) {
- try {
- // Calling stopDhcp several times is fine
- stopDhcp();
- } catch (Exception dhcpError) {
- mLog.e("Error stopping DHCP", dhcpError);
- }
- }
+ if (!configureDhcp(enabled, srvAddr, prefixLen)) {
return false;
}
// Directly-connected route.
- final IpPrefix ipv4Prefix = new IpPrefix(linkAddr.getAddress(),
- linkAddr.getPrefixLength());
+ final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(),
+ mIpv4Address.getPrefixLength());
final RouteInfo route = new RouteInfo(ipv4Prefix, null, null, RTN_UNICAST);
if (enabled) {
- mLinkProperties.addLinkAddress(linkAddr);
+ mLinkProperties.addLinkAddress(mIpv4Address);
mLinkProperties.addRoute(route);
} else {
- mLinkProperties.removeLinkAddress(linkAddr);
+ mLinkProperties.removeLinkAddress(mIpv4Address);
mLinkProperties.removeRoute(route);
}
return true;
@@ -584,14 +563,12 @@ public class IpServer extends StateMachine {
if (!deprecatedPrefixes.isEmpty()) {
final ArrayList<RouteInfo> toBeRemoved =
getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
- try {
- final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved);
- if (removalFailures > 0) {
- mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
- removalFailures));
- }
- } catch (RemoteException e) {
- mLog.e("Failed to remove IPv6 routes from local table: " + e);
+ // Remove routes from local network.
+ final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork(
+ mNetd, toBeRemoved);
+ if (removalFailures > 0) {
+ mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
+ removalFailures));
}
for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
@@ -608,13 +585,18 @@ public class IpServer extends StateMachine {
final ArrayList<RouteInfo> toBeAdded =
getLocalRoutesFor(mIfaceName, addedPrefixes);
try {
- // It's safe to call addInterfaceToLocalNetwork() even if
- // the interface is already in the local_network. Note also
- // that adding routes that already exist does not cause an
- // error (EEXIST is silently ignored).
- mNMService.addInterfaceToLocalNetwork(mIfaceName, toBeAdded);
- } catch (Exception e) {
- mLog.e("Failed to add IPv6 routes to local table: " + e);
+ // It's safe to call networkAddInterface() even if
+ // the interface is already in the local_network.
+ mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName);
+ try {
+ // Add routes from local network. Note that adding routes that
+ // already exist does not cause an error (EEXIST is silently ignored).
+ RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded);
+ } catch (IllegalStateException e) {
+ mLog.e("Failed to add IPv6 routes to local table: " + e);
+ }
+ } catch (ServiceSpecificException | RemoteException e) {
+ mLog.e("Failed to add " + mIfaceName + " to local table: ", e);
}
for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
@@ -728,7 +710,7 @@ public class IpServer extends StateMachine {
logMessage(this, message.what);
switch (message.what) {
case CMD_TETHER_REQUESTED:
- mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
switch (message.arg1) {
case STATE_LOCAL_ONLY:
transitionTo(mLocalHotspotState);
@@ -757,15 +739,17 @@ public class IpServer extends StateMachine {
@Override
public void enter() {
if (!startIPv4()) {
- mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
return;
}
try {
- mNMService.tetherInterface(mIfaceName);
- } catch (Exception e) {
+ final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(),
+ mIpv4Address.getPrefixLength());
+ NetdUtils.tetherInterface(mNetd, mIfaceName, ipv4Prefix);
+ } catch (RemoteException | ServiceSpecificException e) {
mLog.e("Error Tethering: " + e);
- mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
return;
}
@@ -784,9 +768,9 @@ public class IpServer extends StateMachine {
stopIPv6();
try {
- mNMService.untetherInterface(mIfaceName);
- } catch (Exception e) {
- mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
+ NetdUtils.untetherInterface(mNetd, mIfaceName);
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLastError = TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
mLog.e("Failed to untether interface: " + e);
}
@@ -816,7 +800,7 @@ public class IpServer extends StateMachine {
case CMD_START_TETHERING_ERROR:
case CMD_STOP_TETHERING_ERROR:
case CMD_SET_DNS_FORWARDERS_ERROR:
- mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_MASTER_ERROR;
transitionTo(mInitialState);
break;
default:
@@ -835,7 +819,7 @@ public class IpServer extends StateMachine {
@Override
public void enter() {
super.enter();
- if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) {
transitionTo(mInitialState);
}
@@ -871,7 +855,7 @@ public class IpServer extends StateMachine {
@Override
public void enter() {
super.enter();
- if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) {
transitionTo(mInitialState);
}
@@ -901,17 +885,17 @@ public class IpServer extends StateMachine {
// About to tear down NAT; gather remaining statistics.
mStatsService.forceUpdate();
} catch (Exception e) {
- if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
+ mLog.e("Exception in forceUpdate: " + e.toString());
}
try {
- mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface);
- } catch (Exception e) {
- if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString());
+ mNetd.ipfwdRemoveInterfaceForward(mIfaceName, upstreamIface);
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLog.e("Exception in ipfwdRemoveInterfaceForward: " + e.toString());
}
try {
- mNMService.disableNat(mIfaceName, upstreamIface);
- } catch (Exception e) {
- if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
+ mNetd.tetherRemoveForward(mIfaceName, upstreamIface);
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLog.e("Exception in disableNat: " + e.toString());
}
}
@@ -947,12 +931,12 @@ public class IpServer extends StateMachine {
for (String ifname : added) {
try {
- mNMService.enableNat(mIfaceName, ifname);
- mNMService.startInterfaceForwarding(mIfaceName, ifname);
- } catch (Exception e) {
- mLog.e("Exception enabling NAT: " + e);
+ mNetd.tetherAddForward(mIfaceName, ifname);
+ mNetd.ipfwdAddInterfaceForward(mIfaceName, ifname);
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLog.e("Exception enabling NAT: " + e.toString());
cleanupUpstream();
- mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
transitionTo(mInitialState);
return true;
}
@@ -997,7 +981,7 @@ public class IpServer extends StateMachine {
class UnavailableState extends State {
@Override
public void enter() {
- mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
sendInterfaceState(STATE_UNAVAILABLE);
}
}
diff --git a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
index bba61d72d8d6..6f017dcb623f 100644
--- a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
+++ b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -668,7 +668,7 @@ public class RouterAdvertisementDaemon {
}
private final class UnicastResponder extends Thread {
- private final InetSocketAddress mSolicitor = new InetSocketAddress();
+ private final InetSocketAddress mSolicitor = new InetSocketAddress(0);
// The recycled buffer for receiving Router Solicitations from clients.
// If the RS is larger than IPV6_MIN_MTU the packets are truncated.
// This is fine since currently only byte 0 is examined anyway.
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
index 7e685fbe97f1..4e2a2c1c7af7 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -16,16 +16,16 @@
package com.android.server.connectivity.tethering;
-import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
-import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
-import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_INVALID;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
+import static android.net.TetheringManager.EXTRA_ADD_TETHER_TYPE;
+import static android.net.TetheringManager.EXTRA_PROVISION_CALLBACK;
+import static android.net.TetheringManager.EXTRA_RUN_PROVISION;
+import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_INVALID;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
import static com.android.internal.R.string.config_wifi_tether_enable;
@@ -59,7 +59,7 @@ import java.io.PrintWriter;
/**
* Re-check tethering provisioning for enabled downstream tether types.
- * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
+ * Reference TetheringManager.TETHERING_{@code *} for each tether type.
*
* All methods of this class must be accessed from the thread of tethering
* state machine.
@@ -86,9 +86,9 @@ public class EntitlementManager {
private static final int EVENT_GET_ENTITLEMENT_VALUE = 4;
// The ArraySet contains enabled downstream types, ex:
- // {@link ConnectivityManager.TETHERING_WIFI}
- // {@link ConnectivityManager.TETHERING_USB}
- // {@link ConnectivityManager.TETHERING_BLUETOOTH}
+ // {@link TetheringManager.TETHERING_WIFI}
+ // {@link TetheringManager.TETHERING_USB}
+ // {@link TetheringManager.TETHERING_BLUETOOTH}
private final ArraySet<Integer> mCurrentTethers;
private final Context mContext;
private final int mPermissionChangeMessageCode;
@@ -96,8 +96,8 @@ public class EntitlementManager {
private final SparseIntArray mEntitlementCacheValue;
private final EntitlementHandler mHandler;
private final StateMachine mTetherMasterSM;
- // Key: ConnectivityManager.TETHERING_*(downstream).
- // Value: ConnectivityManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
+ // Key: TetheringManager.TETHERING_*(downstream).
+ // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
private final SparseIntArray mCellularPermitted;
private PendingIntent mProvisioningRecheckAlarm;
private boolean mCellularUpstreamPermitted = true;
@@ -133,7 +133,7 @@ public class EntitlementManager {
/**
* Ui entitlement check fails in |downstream|.
*
- * @param downstream tethering type from ConnectivityManager.TETHERING_{@code *}.
+ * @param downstream tethering type from TetheringManager.TETHERING_{@code *}.
*/
void onUiEntitlementFailed(int downstream);
}
@@ -169,7 +169,7 @@ public class EntitlementManager {
* This is called when tethering starts.
* Launch provisioning app if upstream is cellular.
*
- * @param downstreamType tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param downstreamType tethering type from TetheringManager.TETHERING_{@code *}
* @param showProvisioningUi a boolean indicating whether to show the
* provisioning app UI if there is one.
*/
@@ -210,7 +210,7 @@ public class EntitlementManager {
/**
* Tell EntitlementManager that a given type of tethering has been disabled
*
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
*/
public void stopProvisioningIfNeeded(int type) {
mHandler.sendMessage(mHandler.obtainMessage(EVENT_STOP_PROVISIONING, type, 0));
@@ -296,7 +296,7 @@ public class EntitlementManager {
/**
* Re-check tethering provisioning for all enabled tether types.
- * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
+ * Reference TetheringManager.TETHERING_{@code *} for each tether type.
*
* @param config an object that encapsulates the various tethering configuration elements.
* Note: this method is only called from TetherMaster on the handler thread.
@@ -363,7 +363,7 @@ public class EntitlementManager {
/**
* Run no UI tethering provisioning check.
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
* @param subId default data subscription ID.
*/
@VisibleForTesting
@@ -390,7 +390,7 @@ public class EntitlementManager {
/**
* Run the UI-enabled tethering provisioning check.
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
* @param subId default data subscription ID.
* @param receiver to receive entitlement check result.
*/
@@ -398,7 +398,7 @@ public class EntitlementManager {
protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) {
if (DBG) mLog.i("runUiTetherProvisioning: " + type);
- Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
+ Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING_UI);
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
intent.putExtra(EXTRA_SUBID, subId);
@@ -461,7 +461,7 @@ public class EntitlementManager {
* Add the mapping between provisioning result and tethering type.
* Notify UpstreamNetworkMonitor if Cellular permission changes.
*
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
* @param resultCode Provisioning result
*/
protected void addDownstreamMapping(int type, int resultCode) {
@@ -476,7 +476,7 @@ public class EntitlementManager {
/**
* Remove the mapping for input tethering type.
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
*/
protected void removeDownstreamMapping(int type) {
mLog.i("removeDownstreamMapping: " + type);
@@ -625,7 +625,7 @@ public class EntitlementManager {
/**
* Update the last entitlement value to internal cache
*
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
* @param resultCode last entitlement value
* @return the last updated entitlement value
*/
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
index 38fa91e7387e..ce7c2a669f0a 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
@@ -279,7 +279,7 @@ public class OffloadController {
entry.iface = kv.getKey();
entry.rxBytes = value.rxBytes;
entry.txBytes = value.txBytes;
- stats.addValues(entry);
+ stats.addEntry(entry);
}
return stats;
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 5b267046a851..d6abfb922a9c 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -20,23 +20,23 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
-import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
-import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
-import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER;
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_INVALID;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
-import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
+import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.TetheringManager.EXTRA_ERRORED_TETHER;
+import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_INVALID;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+import static android.net.TetheringManager.TETHER_ERROR_MASTER_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
+import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
+import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
import static android.net.util.TetheringMessageBase.BASE_MASTER;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -71,10 +71,10 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkInfo;
-import android.net.NetworkUtils;
import android.net.TetherStatesParcel;
import android.net.TetheringConfigurationParcel;
import android.net.ip.IpServer;
+import android.net.shared.NetdUtils;
import android.net.util.BaseNetdUnsolicitedEventListener;
import android.net.util.InterfaceSet;
import android.net.util.PrefixUtils;
@@ -87,12 +87,12 @@ import android.net.wifi.p2p.WifiP2pManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.os.UserManager;
import android.telephony.PhoneStateListener;
@@ -102,6 +102,9 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -139,6 +142,8 @@ public class Tethering {
};
private static final SparseArray<String> sMagicDecoderRing =
MessageUtils.findMessageNames(sMessageClasses);
+ // Keep in sync with NETID_UNSET in system/netd/include/netid_client.h
+ private static final int NETID_UNSET = 0;
private static class TetherState {
public final IpServer ipServer;
@@ -172,8 +177,6 @@ public class Tethering {
private final Context mContext;
private final ArrayMap<String, TetherState> mTetherStates;
private final BroadcastReceiver mStateReceiver;
- // Stopship: replace mNMService before production.
- private final INetworkManagementService mNMService;
private final INetworkStatsService mStatsService;
private final INetworkPolicyManager mPolicyManager;
private final Looper mLooper;
@@ -210,7 +213,6 @@ public class Tethering {
mLog.mark("Tethering.constructed");
mDeps = deps;
mContext = mDeps.getContext();
- mNMService = mDeps.getINetworkManagementService();
mStatsService = mDeps.getINetworkStatsService();
mPolicyManager = mDeps.getINetworkPolicyManager();
mNetd = mDeps.getINetd(mContext);
@@ -225,10 +227,9 @@ public class Tethering {
mHandler = mTetherMasterSM.getHandler();
mOffloadController = new OffloadController(mHandler,
- mDeps.getOffloadHardwareInterface(mHandler, mLog),
- mContext.getContentResolver(), mNMService,
- mLog);
- mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
+ mDeps.getOffloadHardwareInterface(mHandler, mLog), mContext.getContentResolver(),
+ mDeps.getINetworkManagementService(), mLog);
+ mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new HashSet<>();
@@ -289,13 +290,6 @@ public class Tethering {
filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
mContext.registerReceiver(mStateReceiver, filter, null, handler);
-
- filter = new IntentFilter();
- filter.addAction(Intent.ACTION_MEDIA_SHARED);
- filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
- filter.addDataScheme("file");
- mContext.registerReceiver(mStateReceiver, filter, null, handler);
-
}
private class TetheringThreadExecutor implements Executor {
@@ -421,7 +415,6 @@ public class Tethering {
}
}
-
void interfaceRemoved(String iface) {
if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
synchronized (mPublicSync) {
@@ -1022,8 +1015,8 @@ public class Tethering {
String[] ifaces = null;
try {
- ifaces = mNMService.listInterfaces();
- } catch (Exception e) {
+ ifaces = mNetd.interfaceGetList();
+ } catch (RemoteException | ServiceSpecificException e) {
Log.e(TAG, "Error listing Interfaces", e);
return;
}
@@ -1282,25 +1275,25 @@ public class Tethering {
protected boolean turnOnMasterTetherSettings() {
final TetheringConfiguration cfg = mConfig;
try {
- mNMService.setIpForwardingEnabled(true);
- } catch (Exception e) {
+ mNetd.ipfwdEnableForwarding(TAG);
+ } catch (RemoteException | ServiceSpecificException e) {
mLog.e(e);
transitionTo(mSetIpForwardingEnabledErrorState);
return false;
}
+
// TODO: Randomize DHCPv4 ranges, especially in hotspot mode.
// Legacy DHCP server is disabled if passed an empty ranges array
final String[] dhcpRanges = cfg.enableLegacyDhcpServer
- ? cfg.legacyDhcpRanges
- : new String[0];
+ ? cfg.legacyDhcpRanges : new String[0];
try {
- // TODO: Find a more accurate method name (startDHCPv4()?).
- mNMService.startTethering(dhcpRanges);
- } catch (Exception e) {
+ NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges);
+ } catch (RemoteException | ServiceSpecificException e) {
try {
- mNMService.stopTethering();
- mNMService.startTethering(dhcpRanges);
- } catch (Exception ee) {
+ // Stop and retry.
+ mNetd.tetherStop();
+ NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges);
+ } catch (RemoteException | ServiceSpecificException ee) {
mLog.e(ee);
transitionTo(mStartTetheringErrorState);
return false;
@@ -1312,15 +1305,15 @@ public class Tethering {
protected boolean turnOffMasterTetherSettings() {
try {
- mNMService.stopTethering();
- } catch (Exception e) {
+ mNetd.tetherStop();
+ } catch (RemoteException | ServiceSpecificException e) {
mLog.e(e);
transitionTo(mStopTetheringErrorState);
return false;
}
try {
- mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) {
+ mNetd.ipfwdDisableForwarding(TAG);
+ } catch (RemoteException | ServiceSpecificException e) {
mLog.e(e);
transitionTo(mSetIpForwardingDisabledErrorState);
return false;
@@ -1383,19 +1376,25 @@ public class Tethering {
protected void setDnsForwarders(final Network network, final LinkProperties lp) {
// TODO: Set v4 and/or v6 DNS per available connectivity.
- String[] dnsServers = mConfig.defaultIPv4DNS;
final Collection<InetAddress> dnses = lp.getDnsServers();
// TODO: Properly support the absence of DNS servers.
+ final String[] dnsServers;
if (dnses != null && !dnses.isEmpty()) {
- // TODO: remove this invocation of NetworkUtils.makeStrings().
- dnsServers = NetworkUtils.makeStrings(dnses);
+ dnsServers = new String[dnses.size()];
+ int i = 0;
+ for (InetAddress dns : dnses) {
+ dnsServers[i++] = dns.getHostAddress();
+ }
+ } else {
+ dnsServers = mConfig.defaultIPv4DNS;
}
+ final int netId = (network != null) ? network.netId : NETID_UNSET;
try {
- mNMService.setDnsForwarders(network, dnsServers);
+ mNetd.tetherDnsSet(netId, dnsServers);
mLog.log(String.format(
"SET DNS forwarders: network=%s dnsServers=%s",
network, Arrays.toString(dnsServers)));
- } catch (Exception e) {
+ } catch (RemoteException | ServiceSpecificException e) {
// TODO: Investigate how this can fail and what exactly
// happens if/when such failures occur.
mLog.e("setting DNS forwarders failed, " + e);
@@ -1698,8 +1697,8 @@ public class Tethering {
Log.e(TAG, "Error in startTethering");
notify(IpServer.CMD_START_TETHERING_ERROR);
try {
- mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) { }
+ mNetd.ipfwdDisableForwarding(TAG);
+ } catch (RemoteException | ServiceSpecificException e) { }
}
}
@@ -1709,8 +1708,8 @@ public class Tethering {
Log.e(TAG, "Error in stopTethering");
notify(IpServer.CMD_STOP_TETHERING_ERROR);
try {
- mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) { }
+ mNetd.ipfwdDisableForwarding(TAG);
+ } catch (RemoteException | ServiceSpecificException e) { }
}
}
@@ -1720,11 +1719,11 @@ public class Tethering {
Log.e(TAG, "Error in setDnsForwarders");
notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
try {
- mNMService.stopTethering();
- } catch (Exception e) { }
+ mNetd.tetherStop();
+ } catch (RemoteException | ServiceSpecificException e) { }
try {
- mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) { }
+ mNetd.ipfwdDisableForwarding(TAG);
+ } catch (RemoteException | ServiceSpecificException e) { }
}
}
@@ -1884,7 +1883,7 @@ public class Tethering {
}
}
- void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
// Binder.java closes the resource for us.
@SuppressWarnings("resource")
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
@@ -2065,7 +2064,7 @@ public class Tethering {
mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
final TetherState tetherState = new TetherState(
- new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
+ new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mStatsService,
makeControlCallback(), mConfig.enableLegacyDhcpServer,
mDeps.getIpServerDependencies()));
mTetherStates.put(iface, tetherState);
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 490614b03149..397ba8ada551 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -37,7 +37,6 @@ import static com.android.internal.R.string.config_mobile_hotspot_provision_app_
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
-import android.net.ConnectivityManager;
import android.net.TetheringConfigurationParcel;
import android.net.util.SharedLog;
import android.provider.Settings;
@@ -179,8 +178,8 @@ public class TetheringConfiguration {
pw.print("chooseUpstreamAutomatically: ");
pw.println(chooseUpstreamAutomatically);
- dumpStringArray(pw, "preferredUpstreamIfaceTypes",
- preferredUpstreamNames(preferredUpstreamIfaceTypes));
+ pw.print("legacyPreredUpstreamIfaceTypes: ");
+ pw.println(Arrays.toString(toIntArray(preferredUpstreamIfaceTypes)));
dumpStringArray(pw, "legacyDhcpRanges", legacyDhcpRanges);
dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS);
@@ -205,7 +204,7 @@ public class TetheringConfiguration {
sj.add(String.format("isDunRequired:%s", isDunRequired));
sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically));
sj.add(String.format("preferredUpstreamIfaceTypes:%s",
- makeString(preferredUpstreamNames(preferredUpstreamIfaceTypes))));
+ toIntArray(preferredUpstreamIfaceTypes)));
sj.add(String.format("provisioningApp:%s", makeString(provisioningApp)));
sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi));
sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer));
@@ -234,21 +233,6 @@ public class TetheringConfiguration {
return sj.toString();
}
- private static String[] preferredUpstreamNames(Collection<Integer> upstreamTypes) {
- String[] upstreamNames = null;
-
- if (upstreamTypes != null) {
- upstreamNames = new String[upstreamTypes.size()];
- int i = 0;
- for (Integer netType : upstreamTypes) {
- upstreamNames[i] = ConnectivityManager.getNetworkTypeName(netType);
- i++;
- }
- }
-
- return upstreamNames;
- }
-
/** Check whether dun is required. */
public static boolean checkDunRequired(Context ctx) {
final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
@@ -388,6 +372,15 @@ public class TetheringConfiguration {
return false;
}
+ private static int[] toIntArray(Collection<Integer> values) {
+ final int[] result = new int[values.size()];
+ int index = 0;
+ for (Integer value : values) {
+ result[index++] = value;
+ }
+ return result;
+ }
+
/**
* Convert this TetheringConfiguration to a TetheringConfigurationParcel.
*/
@@ -400,12 +393,7 @@ public class TetheringConfiguration {
parcel.isDunRequired = isDunRequired;
parcel.chooseUpstreamAutomatically = chooseUpstreamAutomatically;
- int[] preferredTypes = new int[preferredUpstreamIfaceTypes.size()];
- int index = 0;
- for (Integer type : preferredUpstreamIfaceTypes) {
- preferredTypes[index++] = type;
- }
- parcel.preferredUpstreamIfaceTypes = preferredTypes;
+ parcel.preferredUpstreamIfaceTypes = toIntArray(preferredUpstreamIfaceTypes);
parcel.legacyDhcpRanges = legacyDhcpRanges;
parcel.defaultIPv4DNS = defaultIPv4DNS;
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
index 6334c20c2acc..d5cdd8a004dc 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
@@ -22,14 +22,17 @@ import android.net.NetworkCapabilities;
import android.net.RouteInfo;
import android.net.util.InterfaceSet;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
import java.net.InetAddress;
+import java.net.UnknownHostException;
/**
* @hide
*/
public final class TetheringInterfaceUtils {
+ private static final InetAddress IN6ADDR_ANY = getByAddress(
+ new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
+ private static final InetAddress INADDR_ANY = getByAddress(new byte[] {0, 0, 0, 0});
+
/**
* Get upstream interfaces for tethering based on default routes for IPv4/IPv6.
* @return null if there is no usable interface, or a set of at least one interface otherwise.
@@ -40,7 +43,7 @@ public final class TetheringInterfaceUtils {
}
final LinkProperties lp = ns.linkProperties;
- final String if4 = getInterfaceForDestination(lp, Inet4Address.ANY);
+ final String if4 = getInterfaceForDestination(lp, INADDR_ANY);
final String if6 = getIPv6Interface(ns);
return (if4 == null && if6 == null) ? null : new InterfaceSet(if4, if6);
@@ -76,7 +79,7 @@ public final class TetheringInterfaceUtils {
&& ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
return canTether
- ? getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY)
+ ? getInterfaceForDestination(ns.linkProperties, IN6ADDR_ANY)
: null;
}
@@ -86,4 +89,12 @@ public final class TetheringInterfaceUtils {
: null;
return (ri != null) ? ri.getInterface() : null;
}
+
+ private static InetAddress getByAddress(final byte[] addr) {
+ try {
+ return InetAddress.getByAddress(null, addr);
+ } catch (UnknownHostException e) {
+ throw new AssertionError("illegal address length" + addr.length);
+ }
+ }
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
index 775484eabfa3..e4e4a090603d 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
@@ -26,11 +26,11 @@ import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
-import android.net.ConnectivityManager;
import android.net.IIntResultListener;
import android.net.INetworkStackConnector;
import android.net.ITetheringConnector;
import android.net.ITetheringEventCallback;
+import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
@@ -307,9 +307,15 @@ public class TetheringService extends Service {
mDeps = new TetheringDependencies() {
@Override
public NetworkRequest getDefaultNetworkRequest() {
- ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- return cm.getDefaultRequest();
+ // TODO: b/147280869, add a proper system API to replace this.
+ final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+ return trackDefaultRequest;
}
@Override
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 22150f623a35..5692a6fc5c80 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -16,10 +16,12 @@
package com.android.server.connectivity.tethering;
+import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
-import static android.net.ConnectivityManager.TYPE_NONE;
-import static android.net.ConnectivityManager.getNetworkTypeName;
+import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -35,10 +37,11 @@ import android.net.NetworkRequest;
import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
import android.os.Handler;
-import android.os.Process;
import android.util.Log;
+import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.StateMachine;
import java.util.HashMap;
@@ -79,11 +82,25 @@ public class UpstreamNetworkMonitor {
public static final int EVENT_ON_LINKPROPERTIES = 2;
public static final int EVENT_ON_LOST = 3;
public static final int NOTIFY_LOCAL_PREFIXES = 10;
+ // This value is used by deprecated preferredUpstreamIfaceTypes selection which is default
+ // disabled.
+ @VisibleForTesting
+ public static final int TYPE_NONE = -1;
private static final int CALLBACK_LISTEN_ALL = 1;
private static final int CALLBACK_DEFAULT_INTERNET = 2;
private static final int CALLBACK_MOBILE_REQUEST = 3;
+ private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray();
+ static {
+ sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI);
+ sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH);
+ sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET);
+ }
+
private final Context mContext;
private final SharedLog mLog;
private final StateMachine mTarget;
@@ -130,15 +147,15 @@ public class UpstreamNetworkMonitor {
*/
public void startTrackDefaultNetwork(NetworkRequest defaultNetworkRequest,
EntitlementManager entitle) {
- // This is not really a "request", just a way of tracking the system default network.
- // It's guaranteed not to actually bring up any networks because it's the same request
- // as the ConnectivityService default request, and thus shares fate with it. We can't
- // use registerDefaultNetworkCallback because it will not track the system default
- // network if there is a VPN that applies to our UID.
+
+ // defaultNetworkRequest is not really a "request", just a way of tracking the system
+ // default network. It's guaranteed not to actually bring up any networks because it's
+ // the should be the same request as the ConnectivityService default request, and thus
+ // shares fate with it. We can't use registerDefaultNetworkCallback because it will not
+ // track the system default network if there is a VPN that applies to our UID.
if (mDefaultNetworkCallback == null) {
- final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest);
mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET);
- cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler);
+ cm().requestNetwork(defaultNetworkRequest, mDefaultNetworkCallback, mHandler);
}
if (mEntitlementMgr == null) {
mEntitlementMgr = entitle;
@@ -204,7 +221,7 @@ public class UpstreamNetworkMonitor {
final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
final NetworkRequest mobileUpstreamRequest = new NetworkRequest.Builder()
- .setCapabilities(ConnectivityManager.networkCapabilitiesForType(legacyType))
+ .setCapabilities(networkCapabilitiesForType(legacyType))
.build();
// The existing default network and DUN callbacks will be notified.
@@ -239,7 +256,7 @@ public class UpstreamNetworkMonitor {
final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType(
mNetworkMap.values(), preferredTypes, isCellularUpstreamPermitted());
- mLog.log("preferred upstream type: " + getNetworkTypeName(typeStatePair.type));
+ mLog.log("preferred upstream type: " + typeStatePair.type);
switch (typeStatePair.type) {
case TYPE_MOBILE_DUN:
@@ -356,16 +373,6 @@ public class UpstreamNetworkMonitor {
notifyTarget(EVENT_ON_LINKPROPERTIES, network);
}
- private void handleSuspended(Network network) {
- if (!network.equals(mTetheringUpstreamNetwork)) return;
- mLog.log("SUSPENDED current upstream: " + network);
- }
-
- private void handleResumed(Network network) {
- if (!network.equals(mTetheringUpstreamNetwork)) return;
- mLog.log("RESUMED current upstream: " + network);
- }
-
private void handleLost(Network network) {
// There are few TODOs within ConnectivityService's rematching code
// pertaining to spurious onLost() notifications.
@@ -455,20 +462,6 @@ public class UpstreamNetworkMonitor {
}
@Override
- public void onNetworkSuspended(Network network) {
- if (mCallbackType == CALLBACK_LISTEN_ALL) {
- handleSuspended(network);
- }
- }
-
- @Override
- public void onNetworkResumed(Network network) {
- if (mCallbackType == CALLBACK_LISTEN_ALL) {
- handleResumed(network);
- }
- }
-
- @Override
public void onLost(Network network) {
if (mCallbackType == CALLBACK_DEFAULT_INTERNET) {
mDefaultInternetNetwork = null;
@@ -512,18 +505,15 @@ public class UpstreamNetworkMonitor {
for (int type : preferredTypes) {
NetworkCapabilities nc;
try {
- nc = ConnectivityManager.networkCapabilitiesForType(type);
+ nc = networkCapabilitiesForType(type);
} catch (IllegalArgumentException iae) {
- Log.e(TAG, "No NetworkCapabilities mapping for legacy type: "
- + ConnectivityManager.getNetworkTypeName(type));
+ Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " + type);
continue;
}
if (!isCellularUpstreamPermitted && isCellular(nc)) {
continue;
}
- nc.setSingleUid(Process.myUid());
-
for (UpstreamNetworkState value : netStates) {
if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) {
continue;
@@ -577,4 +567,28 @@ public class UpstreamNetworkMonitor {
return null;
}
+
+ /**
+ * Given a legacy type (TYPE_WIFI, ...) returns the corresponding NetworkCapabilities instance.
+ * This function is used for deprecated legacy type and be disabled by default.
+ */
+ @VisibleForTesting
+ public static NetworkCapabilities networkCapabilitiesForType(int type) {
+ final NetworkCapabilities nc = new NetworkCapabilities();
+
+ // Map from type to transports.
+ final int notFound = -1;
+ final int transport = sLegacyTypeToTransport.get(type, notFound);
+ Preconditions.checkArgument(transport != notFound, "unknown legacy type: " + type);
+ nc.addTransportType(transport);
+
+ if (type == TYPE_MOBILE_DUN) {
+ nc.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
+ // DUN is restricted network, see NetworkCapabilities#FORCE_RESTRICTED_CAPABILITIES.
+ nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ } else {
+ nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ }
+ return nc;
+ }
}
diff --git a/packages/Tethering/tests/unit/jarjar-rules.txt b/packages/Tethering/tests/unit/jarjar-rules.txt
index 64fdebd92726..921fbed373b0 100644
--- a/packages/Tethering/tests/unit/jarjar-rules.txt
+++ b/packages/Tethering/tests/unit/jarjar-rules.txt
@@ -7,5 +7,6 @@ rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering.
rule com.android.internal.util.Preconditions* com.android.networkstack.tethering.util.Preconditions@1
rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1
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
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index fd2f708aea30..65a0ac13a84b 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -16,13 +16,14 @@
package android.net.ip;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
-import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
+import static android.net.INetd.IF_STATE_UP;
+import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+import static android.net.TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.ip.IpServer.STATE_AVAILABLE;
import static android.net.ip.IpServer.STATE_LOCAL_ONLY;
@@ -52,7 +53,7 @@ import static org.mockito.Mockito.when;
import android.net.INetd;
import android.net.INetworkStatsService;
-import android.net.InterfaceConfiguration;
+import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -64,7 +65,6 @@ import android.net.dhcp.IDhcpServerCallbacks;
import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
import android.net.util.SharedLog;
-import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.text.TextUtils;
@@ -89,6 +89,8 @@ public class IpServerTest {
private static final String IFACE_NAME = "testnet1";
private static final String UPSTREAM_IFACE = "upstream0";
private static final String UPSTREAM_IFACE2 = "upstream1";
+ private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1";
+ private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24;
private static final int DHCP_LEASE_TIME_SECS = 3600;
private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
@@ -96,11 +98,9 @@ public class IpServerTest {
private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000;
- @Mock private INetworkManagementService mNMService;
@Mock private INetd mNetd;
@Mock private INetworkStatsService mStatsService;
@Mock private IpServer.Callback mCallback;
- @Mock private InterfaceConfiguration mInterfaceConfiguration;
@Mock private SharedLog mSharedLog;
@Mock private IDhcpServer mDhcpServer;
@Mock private RouterAdvertisementDaemon mRaDaemon;
@@ -112,6 +112,7 @@ public class IpServerTest {
private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
ArgumentCaptor.forClass(LinkProperties.class);
private IpServer mIpServer;
+ private InterfaceConfigurationParcel mInterfaceConfiguration;
private void initStateMachine(int interfaceType) throws Exception {
initStateMachine(interfaceType, false /* usingLegacyDhcp */);
@@ -131,17 +132,20 @@ public class IpServerTest {
}).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
- when(mDependencies.getNetdService()).thenReturn(mNetd);
-
+ mInterfaceConfiguration = new InterfaceConfigurationParcel();
+ mInterfaceConfiguration.flags = new String[0];
+ if (interfaceType == TETHERING_BLUETOOTH) {
+ mInterfaceConfiguration.ipv4Addr = BLUETOOTH_IFACE_ADDR;
+ mInterfaceConfiguration.prefixLength = BLUETOOTH_DHCP_PREFIX_LENGTH;
+ }
mIpServer = new IpServer(
- IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
- mNMService, mStatsService, mCallback, usingLegacyDhcp, mDependencies);
+ IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mStatsService,
+ mCallback, usingLegacyDhcp, mDependencies);
mIpServer.start();
// Starting the state machine always puts us in a consistent state and notifies
// the rest of the world that we've changed from an unknown to available state.
mLooper.dispatchAll();
- reset(mNMService, mStatsService, mCallback);
- when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
+ reset(mNetd, mStatsService, mCallback);
when(mRaDaemon.start()).thenReturn(true);
}
@@ -158,8 +162,7 @@ public class IpServerTest {
if (upstreamIface != null) {
dispatchTetherConnectionChanged(upstreamIface);
}
- reset(mNMService, mStatsService, mCallback);
- when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
+ reset(mNetd, mStatsService, mCallback);
}
@Before public void setUp() throws Exception {
@@ -169,15 +172,14 @@ public class IpServerTest {
@Test
public void startsOutAvailable() {
- mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(),
- TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mCallback,
- false /* usingLegacyDhcp */, mDependencies);
+ mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog,
+ mNetd, mStatsService, mCallback, false /* usingLegacyDhcp */, mDependencies);
mIpServer.start();
mLooper.dispatchAll();
verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(mCallback, mNMService, mStatsService);
+ verifyNoMoreInteractions(mCallback, mNetd, mStatsService);
}
@Test
@@ -196,7 +198,7 @@ public class IpServerTest {
// None of these commands should trigger us to request action from
// the rest of the system.
dispatchCommand(command);
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
}
@@ -208,7 +210,7 @@ public class IpServerTest {
verify(mCallback).updateInterfaceState(
mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -216,13 +218,17 @@ public class IpServerTest {
initStateMachine(TETHERING_BLUETOOTH);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder inOrder = inOrder(mCallback, mNMService);
- inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
+ InOrder inOrder = inOrder(mCallback, mNetd);
+ inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
+ inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
+ // One for ipv4 route, one for ipv6 link local route.
+ inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
+ any(), any());
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -230,14 +236,16 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_BLUETOOTH, null);
dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
- InOrder inOrder = inOrder(mNMService, mNetd, mStatsService, mCallback);
- inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
+ InOrder inOrder = inOrder(mNetd, mStatsService, mCallback);
+ inOrder.verify(mNetd).tetherApplyDnsInterfaces();
+ inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME);
+ inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -245,16 +253,19 @@ public class IpServerTest {
initStateMachine(TETHERING_USB);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder inOrder = inOrder(mCallback, mNMService);
- inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
- inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
- inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
+ InOrder inOrder = inOrder(mCallback, mNetd);
+ inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
+ IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
+ inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
+ inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
+ inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
+ any(), any());
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), mLinkPropertiesCaptor.capture());
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -262,16 +273,19 @@ public class IpServerTest {
initStateMachine(TETHERING_WIFI_P2P);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
- InOrder inOrder = inOrder(mCallback, mNMService);
- inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
- inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
- inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
+ InOrder inOrder = inOrder(mCallback, mNetd);
+ inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
+ IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
+ inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
+ inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
+ inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
+ any(), any());
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), mLinkPropertiesCaptor.capture());
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -281,10 +295,10 @@ public class IpServerTest {
// Telling the state machine about its upstream interface triggers
// a little more configuration.
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
- InOrder inOrder = inOrder(mNMService);
- inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ InOrder inOrder = inOrder(mNetd);
+ inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -292,49 +306,49 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
- InOrder inOrder = inOrder(mNMService, mStatsService);
+ InOrder inOrder = inOrder(mNetd, mStatsService);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
- inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
public void handlesChangingUpstreamNatFailure() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
- doThrow(RemoteException.class).when(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ doThrow(RemoteException.class).when(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
- InOrder inOrder = inOrder(mNMService, mStatsService);
+ InOrder inOrder = inOrder(mNetd, mStatsService);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2);
}
@Test
public void handlesChangingUpstreamInterfaceForwardingFailure() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
- doThrow(RemoteException.class).when(mNMService).startInterfaceForwarding(
+ doThrow(RemoteException.class).when(mNetd).ipfwdAddInterfaceForward(
IFACE_NAME, UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
- InOrder inOrder = inOrder(mNMService, mStatsService);
+ InOrder inOrder = inOrder(mNetd, mStatsService);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
- inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2);
}
@Test
@@ -342,17 +356,19 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
- InOrder inOrder = inOrder(mNMService, mNetd, mStatsService, mCallback);
+ InOrder inOrder = inOrder(mNetd, mStatsService, mCallback);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherApplyDnsInterfaces();
+ inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME);
+ inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -361,13 +377,14 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_USB, null);
if (shouldThrow) {
- doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
+ doThrow(RemoteException.class).when(mNetd).tetherInterfaceRemove(IFACE_NAME);
}
dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
- InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
- usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
- usbTeardownOrder.verify(mNMService).setInterfaceConfig(
- IFACE_NAME, mInterfaceConfiguration);
+ InOrder usbTeardownOrder = inOrder(mNetd, mCallback);
+ // Currently IpServer interfaceSetCfg twice to stop IPv4. One just set interface down
+ // Another one is set IPv4 to 0.0.0.0/0 as clearng ipv4 address.
+ usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg(
+ argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
usbTeardownOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
usbTeardownOrder.verify(mCallback).updateLinkProperties(
@@ -380,12 +397,15 @@ public class IpServerTest {
public void usbShouldBeTornDownOnTetherError() throws Exception {
initStateMachine(TETHERING_USB);
- doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
+ doThrow(RemoteException.class).when(mNetd).tetherInterfaceAdd(IFACE_NAME);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
- usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
- usbTeardownOrder.verify(mNMService).setInterfaceConfig(
- IFACE_NAME, mInterfaceConfiguration);
+ InOrder usbTeardownOrder = inOrder(mNetd, mCallback);
+ usbTeardownOrder.verify(mNetd).interfaceSetCfg(
+ argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
+ usbTeardownOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
+
+ usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg(
+ argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
usbTeardownOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
usbTeardownOrder.verify(mCallback).updateLinkProperties(
@@ -397,11 +417,13 @@ public class IpServerTest {
public void shouldTearDownUsbOnUpstreamError() throws Exception {
initTetheredStateMachine(TETHERING_USB, null);
- doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
+ doThrow(RemoteException.class).when(mNetd).tetherAddForward(anyString(), anyString());
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
- InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
- usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
- usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
+ InOrder usbTeardownOrder = inOrder(mNetd, mCallback);
+ usbTeardownOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE);
+
+ usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg(
+ argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
usbTeardownOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
usbTeardownOrder.verify(mCallback).updateLinkProperties(
@@ -413,11 +435,11 @@ public class IpServerTest {
public void ignoresDuplicateUpstreamNotifications() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
for (int i = 0; i < 5; i++) {
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
}
@@ -525,4 +547,12 @@ public class IpServerTest {
// never see an empty interface name in any LinkProperties update.
assertFalse(TextUtils.isEmpty(lp.getInterfaceName()));
}
+
+ private boolean assertContainsFlag(String[] flags, String match) {
+ for (String flag : flags) {
+ if (flag.equals(match)) return true;
+ }
+ fail("Missing flag: " + match);
+ return false;
+ }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 99cf9e90d912..66eba9ae3b7a 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -16,12 +16,12 @@
package com.android.server.connectivity.tethering;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
+import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 04b2eb411c9d..7af48a89d87c 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -19,16 +19,15 @@ package com.android.server.connectivity.tethering;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
-import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
-import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
-import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.RouteInfo.RTN_UNICAST;
+import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
+import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -50,7 +49,6 @@ import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -74,14 +72,13 @@ import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.ITetheringEventCallback;
import android.net.InetAddresses;
-import android.net.InterfaceConfiguration;
+import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.TetherStatesParcel;
@@ -147,6 +144,7 @@ public class TetheringTest {
private static final String TEST_USB_IFNAME = "test_rndis0";
private static final String TEST_WLAN_IFNAME = "test_wlan0";
private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
+ private static final String TETHERING_NAME = "Tethering";
private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
@@ -185,6 +183,7 @@ public class TetheringTest {
private BroadcastReceiver mBroadcastReceiver;
private Tethering mTethering;
private PhoneStateListener mPhoneStateListener;
+ private InterfaceConfigurationParcel mInterfaceConfiguration;
private class TestContext extends BroadcastInterceptingContext {
TestContext(Context base) {
@@ -248,11 +247,6 @@ public class TetheringTest {
}
@Override
- public INetd getNetdService() {
- return mNetd;
- }
-
- @Override
public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
DhcpServerCallbacks cb) {
new Thread(() -> {
@@ -429,11 +423,11 @@ public class TetheringTest {
.thenReturn(new int[0]);
when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic))
.thenReturn(false);
- when(mNMService.listInterfaces())
+ when(mNetd.interfaceGetList())
.thenReturn(new String[] {
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME});
- when(mNMService.getInterfaceConfig(anyString()))
- .thenReturn(new InterfaceConfiguration());
+ mInterfaceConfiguration = new InterfaceConfigurationParcel();
+ mInterfaceConfiguration.flags = new String[0];
when(mRouterAdvertisementDaemon.start())
.thenReturn(true);
@@ -495,15 +489,12 @@ public class TetheringTest {
p2pInfo.groupFormed = isGroupFormed;
p2pInfo.isGroupOwner = isGroupOwner;
- NetworkInfo networkInfo = new NetworkInfo(TYPE_WIFI_P2P, 0, null, null);
-
WifiP2pGroup group = new WifiP2pGroup();
group.setIsGroupOwner(isGroupOwner);
group.setInterface(ifname);
final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo);
- intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, networkInfo);
intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group);
mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
@@ -523,10 +514,11 @@ public class TetheringTest {
}
private void verifyInterfaceServingModeStarted(String ifname) throws Exception {
- verify(mNMService, times(1)).getInterfaceConfig(ifname);
- verify(mNMService, times(1))
- .setInterfaceConfig(eq(ifname), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).tetherInterface(ifname);
+ verify(mNetd, times(1)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, times(1)).tetherInterfaceAdd(ifname);
+ verify(mNetd, times(1)).networkAddInterface(INetd.LOCAL_NET_ID, ifname);
+ verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(ifname),
+ anyString(), anyString());
}
private void verifyTetheringBroadcast(String ifname, String whichExtra) {
@@ -558,7 +550,7 @@ public class TetheringTest {
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
}
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
verifyNoMoreInteractions(mWifiManager);
}
@@ -581,14 +573,14 @@ public class TetheringTest {
prepareUsbTethering(upstreamState);
// This should produce no activity of any kind.
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Pretend we then receive USB configured broadcast.
sendUsbBroadcast(true, true, true);
mLooper.dispatchAll();
// Now we should see the start of tethering mechanics (in this case:
// tetherMatchingInterfaces() which starts by fetching all interfaces).
- verify(mNMService, times(1)).listInterfaces();
+ verify(mNetd, times(1)).interfaceGetList();
// UpstreamNetworkMonitor should receive selected upstream
verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
@@ -618,9 +610,9 @@ public class TetheringTest {
verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
- verify(mNMService, times(1)).setIpForwardingEnabled(true);
- verify(mNMService, times(1)).startTethering(any(String[].class));
- verifyNoMoreInteractions(mNMService);
+ verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd, times(1)).tetherStartWithConfiguration(any());
+ verifyNoMoreInteractions(mNetd);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
verify(mWifiManager).updateInterfaceIpState(
@@ -638,16 +630,16 @@ public class TetheringTest {
mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
- // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
- verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
- verify(mNMService, times(2))
- .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).stopTethering();
- verify(mNMService, times(1)).setIpForwardingEnabled(false);
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME);
+ verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
+ // interfaceSetCfg() called once for enabling and twice disabling IPv4.
+ verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, times(1)).tetherStop();
+ verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME);
verify(mWifiManager, times(3)).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
@@ -684,8 +676,8 @@ public class TetheringTest {
UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
runUsbTethering(upstreamState);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
@@ -708,8 +700,8 @@ public class TetheringTest {
UpstreamNetworkState upstreamState = buildMobileIPv6UpstreamState();
runUsbTethering(upstreamState);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
@@ -721,8 +713,8 @@ public class TetheringTest {
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
runUsbTethering(upstreamState);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mRouterAdvertisementDaemon, times(1)).start();
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
@@ -736,12 +728,11 @@ public class TetheringTest {
UpstreamNetworkState upstreamState = buildMobile464xlatUpstreamState();
runUsbTethering(upstreamState);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
- TEST_XLAT_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
@@ -754,9 +745,9 @@ public class TetheringTest {
UpstreamNetworkState upstreamState = buildMobileIPv6UpstreamState();
runUsbTethering(upstreamState);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
// Then 464xlat comes up
upstreamState = buildMobile464xlatUpstreamState();
@@ -772,12 +763,11 @@ public class TetheringTest {
mLooper.dispatchAll();
// Forwarding is added for 464xlat
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
- TEST_XLAT_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
// Forwarding was not re-added for v6 (still times(1))
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
// DHCP not restarted on downstream (still times(1))
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
}
@@ -820,7 +810,7 @@ public class TetheringTest {
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
@@ -833,7 +823,7 @@ public class TetheringTest {
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
verifyNoMoreInteractions(mWifiManager);
}
@@ -847,7 +837,7 @@ public class TetheringTest {
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
@@ -858,9 +848,11 @@ public class TetheringTest {
verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
- verify(mNMService, times(1)).setIpForwardingEnabled(true);
- verify(mNMService, times(1)).startTethering(any(String[].class));
- verifyNoMoreInteractions(mNMService);
+ verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd, times(1)).tetherStartWithConfiguration(any());
+ verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_WLAN_IFNAME),
+ anyString(), anyString());
+ verifyNoMoreInteractions(mNetd);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
verify(mWifiManager).updateInterfaceIpState(
@@ -878,8 +870,8 @@ public class TetheringTest {
/////
// We do not currently emulate any upstream being found.
//
- // This is why there are no calls to verify mNMService.enableNat() or
- // mNMService.startInterfaceForwarding().
+ // This is why there are no calls to verify mNetd.tetherAddForward() or
+ // mNetd.ipfwdAddInterfaceForward().
/////
// Emulate pressing the WiFi tethering button.
@@ -887,7 +879,7 @@ public class TetheringTest {
mLooper.dispatchAll();
verify(mWifiManager, times(1)).stopSoftAp();
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Emulate externally-visible WifiManager effects, when tethering mode
// is being torn down.
@@ -895,16 +887,16 @@ public class TetheringTest {
mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
- // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
- verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
- verify(mNMService, atLeastOnce())
- .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).stopTethering();
- verify(mNMService, times(1)).setIpForwardingEnabled(false);
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME);
+ verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
+ // interfaceSetCfg() called once for enabling and twice for disabling IPv4.
+ verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, times(1)).tetherStop();
+ verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME);
verify(mWifiManager, times(3)).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
@@ -915,14 +907,14 @@ public class TetheringTest {
@Test
public void failureEnablingIpForwarding() throws Exception {
when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
- doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
+ doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME);
// Emulate pressing the WiFi tethering button.
mTethering.startTethering(TETHERING_WIFI, null, false);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
@@ -931,15 +923,15 @@ public class TetheringTest {
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
mLooper.dispatchAll();
- // We verify get/set called thrice here: twice for setup (on NMService) and once during
- // teardown (on Netd) because all events happen over the course of the single
+ // We verify get/set called three times here: twice for setup and once during
+ // teardown because all events happen over the course of the single
// dispatchAll() above. Note that once the IpServer IPv4 address config
// code is refactored the two calls during shutdown will revert to one.
- verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
- verify(mNMService, times(2))
- .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
- verify(mNetd, times(1)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName)));
- verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
+ verify(mNetd, times(3)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName)));
+ verify(mNetd, times(1)).tetherInterfaceAdd(TEST_WLAN_IFNAME);
+ verify(mNetd, times(1)).networkAddInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
+ verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_WLAN_IFNAME),
+ anyString(), anyString());
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
verify(mWifiManager).updateInterfaceIpState(
@@ -949,18 +941,20 @@ public class TetheringTest {
assertEquals(3, mTetheringDependencies.mIsTetheringSupportedCalls);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
// This is called, but will throw.
- verify(mNMService, times(1)).setIpForwardingEnabled(true);
+ verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
// This never gets called because of the exception thrown above.
- verify(mNMService, times(0)).startTethering(any(String[].class));
+ verify(mNetd, times(0)).tetherStartWithConfiguration(any());
// When the master state machine transitions to an error state it tells
// downstream interfaces, which causes us to tell Wi-Fi about the error
// so it can take down AP mode.
- verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME);
+ verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
}
private void runUserRestrictionsChange(
@@ -1232,9 +1226,9 @@ public class TetheringTest {
verifyInterfaceServingModeStarted(TEST_P2P_IFNAME);
verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_AVAILABLE_TETHER);
- verify(mNMService, times(1)).setIpForwardingEnabled(true);
- verify(mNMService, times(1)).startTethering(any(String[].class));
- verifyNoMoreInteractions(mNMService);
+ verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd, times(1)).tetherStartWithConfiguration(any());
+ verifyNoMoreInteractions(mNetd);
verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
// This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
@@ -1249,16 +1243,16 @@ public class TetheringTest {
mTethering.interfaceRemoved(TEST_P2P_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, times(1)).untetherInterface(TEST_P2P_IFNAME);
- // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
- verify(mNMService, times(2)).getInterfaceConfig(TEST_P2P_IFNAME);
- verify(mNMService, times(2))
- .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).stopTethering();
- verify(mNMService, times(1)).setIpForwardingEnabled(false);
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ verify(mNetd, times(1)).tetherInterfaceRemove(TEST_P2P_IFNAME);
+ verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME);
+ // interfaceSetCfg() called once for enabling and twice for disabling IPv4.
+ verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, times(1)).tetherStop();
+ verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME);
verify(mUpstreamNetworkMonitor, never()).getCurrentPreferredUpstream();
verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any());
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
@@ -1272,12 +1266,11 @@ public class TetheringTest {
sendWifiP2pConnectionChanged(true, false, TEST_P2P_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
- verify(mNMService, never())
- .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
- verify(mNMService, never()).setIpForwardingEnabled(true);
- verify(mNMService, never()).startTethering(any(String[].class));
+ verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, never()).tetherInterfaceAdd(TEST_P2P_IFNAME);
+ verify(mNetd, never()).networkAddInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME);
+ verify(mNetd, never()).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd, never()).tetherStartWithConfiguration(any());
// Emulate externally-visible WifiP2pManager effects, when wifi p2p group
// is being removed.
@@ -1285,13 +1278,13 @@ public class TetheringTest {
mTethering.interfaceRemoved(TEST_P2P_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, never()).untetherInterface(TEST_P2P_IFNAME);
- verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
- verify(mNMService, never())
- .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, never()).stopTethering();
- verify(mNMService, never()).setIpForwardingEnabled(false);
- verifyNoMoreInteractions(mNMService);
+ verify(mNetd, never()).tetherApplyDnsInterfaces();
+ verify(mNetd, never()).tetherInterfaceRemove(TEST_P2P_IFNAME);
+ verify(mNetd, never()).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME);
+ verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, never()).tetherStop();
+ verify(mNetd, never()).ipfwdDisableForwarding(TETHERING_NAME);
+ verifyNoMoreInteractions(mNetd);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
@@ -1321,12 +1314,11 @@ public class TetheringTest {
sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
- verify(mNMService, never())
- .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
- verify(mNMService, never()).setIpForwardingEnabled(true);
- verify(mNMService, never()).startTethering(any(String[].class));
+ verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, never()).tetherInterfaceAdd(TEST_P2P_IFNAME);
+ verify(mNetd, never()).networkAddInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME);
+ verify(mNetd, never()).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd, never()).tetherStartWithConfiguration(any());
assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
}
@Test
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index c90abbbedb5f..5ed75bf26f8b 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -18,13 +18,14 @@ package com.android.server.connectivity.tethering;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
-import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static com.android.server.connectivity.tethering.UpstreamNetworkMonitor.TYPE_NONE;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -538,13 +539,15 @@ public class UpstreamNetworkMonitorTest {
mUNM.selectPreferredUpstreamType(preferredTypes));
verify(mEntitleMgr, times(1)).maybeRunProvisioning();
}
+
private void assertSatisfiesLegacyType(int legacyType, UpstreamNetworkState ns) {
if (legacyType == TYPE_NONE) {
assertTrue(ns == null);
return;
}
- final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
+ final NetworkCapabilities nc =
+ UpstreamNetworkMonitor.networkCapabilitiesForType(legacyType);
assertTrue(nc.satisfiedByNetworkCapabilities(ns.networkCapabilities));
}
diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java
index b7e05d9c984c..7b5514b8a0d1 100644
--- a/rs/java/android/renderscript/BaseObj.java
+++ b/rs/java/android/renderscript/BaseObj.java
@@ -16,8 +16,10 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import dalvik.system.CloseGuard;
+
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index b8eb3a1d7a40..0941907d35f8 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* <p>An Element represents one item within an {@link
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index 9a6b0bcd4544..7cc2825ae565 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -16,13 +16,13 @@
package android.renderscript;
-import java.io.File;
-import java.io.InputStream;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import java.io.File;
+import java.io.InputStream;
+
/**
* @hide
* @deprecated in API 16
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index 583350e91795..df9d8019f28d 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -16,17 +16,16 @@
package android.renderscript;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.os.Environment;
+
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
-import android.os.Environment;
-
-import android.annotation.UnsupportedAppUsage;
-import android.content.res.AssetManager;
-import android.content.res.Resources;
-
/**
* @hide
* @deprecated in API 16
diff --git a/rs/java/android/renderscript/Matrix4f.java b/rs/java/android/renderscript/Matrix4f.java
index 026c9fbd7d5e..a9469c979494 100644
--- a/rs/java/android/renderscript/Matrix4f.java
+++ b/rs/java/android/renderscript/Matrix4f.java
@@ -16,8 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
-import java.lang.Math;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java
index 5321dcb957dc..826225a70d86 100644
--- a/rs/java/android/renderscript/Mesh.java
+++ b/rs/java/android/renderscript/Mesh.java
@@ -16,7 +16,8 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import java.util.Vector;
/**
diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java
index e28d646f5f1c..ff072183e927 100644
--- a/rs/java/android/renderscript/Program.java
+++ b/rs/java/android/renderscript/Program.java
@@ -17,14 +17,14 @@
package android.renderscript;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.res.Resources;
+import android.util.Log;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
-import android.annotation.UnsupportedAppUsage;
-import android.content.res.Resources;
-import android.util.Log;
-
/**
* @hide
diff --git a/rs/java/android/renderscript/ProgramFragment.java b/rs/java/android/renderscript/ProgramFragment.java
index 3dde9b6d6400..880531207b4d 100644
--- a/rs/java/android/renderscript/ProgramFragment.java
+++ b/rs/java/android/renderscript/ProgramFragment.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
index d05d41da8b6f..c741ce6e77ed 100644
--- a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
+++ b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/ProgramRaster.java b/rs/java/android/renderscript/ProgramRaster.java
index 33000acb4eb0..a21696c82161 100644
--- a/rs/java/android/renderscript/ProgramRaster.java
+++ b/rs/java/android/renderscript/ProgramRaster.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/ProgramStore.java b/rs/java/android/renderscript/ProgramStore.java
index 622fe21be47a..7e61347ee218 100644
--- a/rs/java/android/renderscript/ProgramStore.java
+++ b/rs/java/android/renderscript/ProgramStore.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/ProgramVertex.java b/rs/java/android/renderscript/ProgramVertex.java
index 83d9ea7be645..9257234de42c 100644
--- a/rs/java/android/renderscript/ProgramVertex.java
+++ b/rs/java/android/renderscript/ProgramVertex.java
@@ -38,7 +38,7 @@
**/
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/ProgramVertexFixedFunction.java b/rs/java/android/renderscript/ProgramVertexFixedFunction.java
index 579d3bb507e8..03c2eaf91242 100644
--- a/rs/java/android/renderscript/ProgramVertexFixedFunction.java
+++ b/rs/java/android/renderscript/ProgramVertexFixedFunction.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/RSSurfaceView.java b/rs/java/android/renderscript/RSSurfaceView.java
index 561373cef625..6bdde387b334 100644
--- a/rs/java/android/renderscript/RSSurfaceView.java
+++ b/rs/java/android/renderscript/RSSurfaceView.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index f4c27771c846..39efe731ce8a 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
@@ -447,44 +447,33 @@ public class RenderScript {
validate();
return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
}
- native long rsnAllocationCreateFromBitmap(long con, long type, int mip, long bitmapHandle,
+
+ native long rsnAllocationCreateFromBitmap(long con, long type, int mip, Bitmap bmp,
int usage);
synchronized long nAllocationCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
validate();
- return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp.getNativeInstance(), usage);
+ return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage);
}
- native long rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, long bitmapHandle,
+ native long rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, Bitmap bmp,
int usage);
synchronized long nAllocationCreateBitmapBackedAllocation(long type, int mip, Bitmap bmp,
int usage) {
validate();
- return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp.getNativeInstance(),
- usage);
+ return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp, usage);
}
- native long rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, long bitmapHandle,
+ native long rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, Bitmap bmp,
int usage);
synchronized long nAllocationCubeCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
validate();
- return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp.getNativeInstance(),
- usage);
- }
- native long rsnAllocationCreateBitmapRef(long con, long type, long bitmapHandle);
- synchronized long nAllocationCreateBitmapRef(long type, Bitmap bmp) {
- validate();
- return rsnAllocationCreateBitmapRef(mContext, type, bmp.getNativeInstance());
- }
- native long rsnAllocationCreateFromAssetStream(long con, int mips, int assetStream, int usage);
- synchronized long nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) {
- validate();
- return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage);
+ return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage);
}
- native void rsnAllocationCopyToBitmap(long con, long alloc, long bitmapHandle);
+ native void rsnAllocationCopyToBitmap(long con, long alloc, Bitmap bmp);
synchronized void nAllocationCopyToBitmap(long alloc, Bitmap bmp) {
validate();
- rsnAllocationCopyToBitmap(mContext, alloc, bmp.getNativeInstance());
+ rsnAllocationCopyToBitmap(mContext, alloc, bmp);
}
native void rsnAllocationSyncAll(long con, long alloc, int src);
@@ -537,10 +526,10 @@ public class RenderScript {
validate();
rsnAllocationGenerateMipmaps(mContext, alloc);
}
- native void rsnAllocationCopyFromBitmap(long con, long alloc, long bitmapHandle);
+ native void rsnAllocationCopyFromBitmap(long con, long alloc, Bitmap bmp);
synchronized void nAllocationCopyFromBitmap(long alloc, Bitmap bmp) {
validate();
- rsnAllocationCopyFromBitmap(mContext, alloc, bmp.getNativeInstance());
+ rsnAllocationCopyFromBitmap(mContext, alloc, bmp);
}
diff --git a/rs/java/android/renderscript/RenderScriptCacheDir.java b/rs/java/android/renderscript/RenderScriptCacheDir.java
index 1797bef4be8d..862d032d6987 100644
--- a/rs/java/android/renderscript/RenderScriptCacheDir.java
+++ b/rs/java/android/renderscript/RenderScriptCacheDir.java
@@ -16,7 +16,8 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import java.io.File;
/**
diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java
index 6fac83e8c4a8..dafaf367364d 100644
--- a/rs/java/android/renderscript/RenderScriptGL.java
+++ b/rs/java/android/renderscript/RenderScriptGL.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.view.Surface;
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index 9ad9aea9d7aa..d1d3a7642382 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.SparseArray;
/**
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 0854b9582187..f9ef0b7b8e9d 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -12,7 +12,6 @@ LOCAL_SHARED_LIBRARIES := \
libRS \
libcutils \
liblog \
- libhwui \
libutils \
libui \
libgui \
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index dfee96182a48..5ae895dbbce6 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -32,10 +32,10 @@
#include "jni.h"
#include <nativehelper/JNIHelp.h>
+#include <android/graphics/bitmap.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
#include "android_runtime/android_util_AssetManager.h"
-#include "android/graphics/GraphicsJNI.h"
#include "android/native_window.h"
#include "android/native_window_jni.h"
@@ -1319,27 +1319,28 @@ nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
rsAllocationGenerateMipmaps((RsContext)con, (RsAllocation)alloc);
}
+static size_t computeByteSize(const android::graphics::Bitmap& bitmap) {
+ AndroidBitmapInfo info = bitmap.getInfo();
+ return info.height * info.stride;
+}
+
static jlong
nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
- jlong bitmapPtr, jint usage)
+ jobject jbitmap, jint usage)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCreateFromBitmap((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
- ptr, bitmap.computeByteSize(), usage);
+ ptr, computeByteSize(bitmap), usage);
return id;
}
static jlong
nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type,
- jint mip, jlong bitmapPtr, jint usage)
+ jint mip, jobject jbitmap, jint usage)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCreateTyped((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
@@ -1349,40 +1350,35 @@ nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con,
static jlong
nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
- jlong bitmapPtr, jint usage)
+ jobject jbitmap, jint usage)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCubeCreateFromBitmap((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
- ptr, bitmap.computeByteSize(), usage);
+ ptr, computeByteSize(bitmap), usage);
return id;
}
static void
-nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jlong bitmapPtr)
+nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
- int w = bitmap.width();
- int h = bitmap.height();
+ android::graphics::Bitmap bitmap(_env, jbitmap);
+ int w = bitmap.getInfo().width;
+ int h = bitmap.getInfo().height;
const void* ptr = bitmap.getPixels();
rsAllocation2DData((RsContext)con, (RsAllocation)alloc, 0, 0,
0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X,
- w, h, ptr, bitmap.computeByteSize(), 0);
+ w, h, ptr, computeByteSize(bitmap), 0);
}
static void
-nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jlong bitmapPtr)
+nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
void* ptr = bitmap.getPixels();
- rsAllocationCopyToBitmap((RsContext)con, (RsAllocation)alloc, ptr, bitmap.computeByteSize());
+ rsAllocationCopyToBitmap((RsContext)con, (RsAllocation)alloc, ptr, computeByteSize(bitmap));
bitmap.notifyPixelsChanged();
}
@@ -2867,12 +2863,12 @@ static const JNINativeMethod methods[] = {
{"rsnTypeGetNativeData", "(JJ[J)V", (void*)nTypeGetNativeData },
{"rsnAllocationCreateTyped", "(JJIIJ)J", (void*)nAllocationCreateTyped },
-{"rsnAllocationCreateFromBitmap", "(JJIJI)J", (void*)nAllocationCreateFromBitmap },
-{"rsnAllocationCreateBitmapBackedAllocation", "(JJIJI)J", (void*)nAllocationCreateBitmapBackedAllocation },
-{"rsnAllocationCubeCreateFromBitmap","(JJIJI)J", (void*)nAllocationCubeCreateFromBitmap },
+{"rsnAllocationCreateFromBitmap", "(JJILandroid/graphics/Bitmap;I)J", (void*)nAllocationCreateFromBitmap },
+{"rsnAllocationCreateBitmapBackedAllocation", "(JJILandroid/graphics/Bitmap;I)J", (void*)nAllocationCreateBitmapBackedAllocation },
+{"rsnAllocationCubeCreateFromBitmap","(JJILandroid/graphics/Bitmap;I)J", (void*)nAllocationCubeCreateFromBitmap },
-{"rsnAllocationCopyFromBitmap", "(JJJ)V", (void*)nAllocationCopyFromBitmap },
-{"rsnAllocationCopyToBitmap", "(JJJ)V", (void*)nAllocationCopyToBitmap },
+{"rsnAllocationCopyFromBitmap", "(JJLandroid/graphics/Bitmap;)V", (void*)nAllocationCopyFromBitmap },
+{"rsnAllocationCopyToBitmap", "(JJLandroid/graphics/Bitmap;)V", (void*)nAllocationCopyToBitmap },
{"rsnAllocationSyncAll", "(JJI)V", (void*)nAllocationSyncAll },
{"rsnAllocationSetupBufferQueue", "(JJI)V", (void*)nAllocationSetupBufferQueue },
diff --git a/services/Android.bp b/services/Android.bp
index 1e119363f545..5afed6c4fd19 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -113,7 +113,7 @@ droidstubs {
srcs: [":services-sources"],
installable: false,
// TODO: remove the --hide options below
- args: " --show-single-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
+ args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
" --hide-annotation android.annotation.Hide" +
" --hide-package com.google.android.startop.iorap" +
" --hide ReferencesHidden" +
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6a6e2b2f3467..58d3489a8cc8 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -35,6 +35,7 @@ import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.AlertDialog;
import android.app.PendingIntent;
+import android.app.RemoteAction;
import android.appwidget.AppWidgetManagerInternal;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@@ -148,6 +149,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// their capabilities are ready.
private static final int WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS = 1000;
+ static final String FUNCTION_REGISTER_SYSTEM_ACTION = "registerSystemAction";
+ static final String FUNCTION_UNREGISTER_SYSTEM_ACTION = "unregisterSystemAction";
private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
"registerUiTestAutomationService";
@@ -253,6 +256,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ @VisibleForTesting
+ AccessibilityManagerService(
+ Context context,
+ PackageManager packageManager,
+ AccessibilitySecurityPolicy securityPolicy,
+ SystemActionPerformer systemActionPerformer,
+ AccessibilityWindowManager a11yWindowManager,
+ AccessibilityDisplayListener a11yDisplayListener) {
+ mContext = context;
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
+ mMainHandler = new MainHandler(mContext.getMainLooper());
+ mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
+ mPackageManager = packageManager;
+ mSecurityPolicy = securityPolicy;
+ mSystemActionPerformer = systemActionPerformer;
+ mA11yWindowManager = a11yWindowManager;
+ mA11yDisplayListener = a11yDisplayListener;
+ init();
+ }
+
/**
* Creates a new instance.
*
@@ -260,21 +284,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
public AccessibilityManagerService(Context context) {
mContext = context;
- mPackageManager = mContext.getPackageManager();
- mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
- mSecurityPolicy = new AccessibilitySecurityPolicy(mContext, this);
mMainHandler = new MainHandler(mContext.getMainLooper());
+ mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
+ mPackageManager = mContext.getPackageManager();
+ mSecurityPolicy = new AccessibilitySecurityPolicy(mContext, this);
mSystemActionPerformer = new SystemActionPerformer(mContext, mWindowManagerService);
mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
mWindowManagerService, this, mSecurityPolicy, this);
mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
- mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager);
- mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
+ init();
+ }
+ private void init() {
+ mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager);
registerBroadcastReceivers();
new AccessibilityContentObserver(mMainHandler).register(
- context.getContentResolver());
+ mContext.getContentResolver());
}
@Override
@@ -623,6 +650,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
event.recycle();
}
+ /**
+ * This is the implementation of AccessibilityManager system API.
+ * System UI calls into this method through AccessibilityManager system API to register a
+ * system action.
+ */
+ @Override
+ public void registerSystemAction(RemoteAction action, int actionId) {
+ mSecurityPolicy.enforceCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY,
+ FUNCTION_REGISTER_SYSTEM_ACTION);
+ mSystemActionPerformer.registerSystemAction(actionId, action);
+ }
+
+ /**
+ * This is the implementation of AccessibilityManager system API.
+ * System UI calls into this method through AccessibilityManager system API to unregister a
+ * system action.
+ */
+ @Override
+ public void unregisterSystemAction(int actionId) {
+ mSecurityPolicy.enforceCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY,
+ FUNCTION_UNREGISTER_SYSTEM_ACTION);
+ mSystemActionPerformer.unregisterSystemAction(actionId);
+ }
+
@Override
public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
synchronized (mLock) {
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index 17549268503e..11dcfefd7e3b 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -157,8 +157,13 @@ public class SystemActionPerformer {
/**
* This method is called to register a system action. If a system action is already registered
* with the given id, the existing system action will be overwritten.
+ *
+ * This method is supposed to be package internal since this class is meant to be used by
+ * AccessibilityManagerService only. But Mockito has a bug which requiring this to be public
+ * to be mocked.
*/
- void registerSystemAction(int id, RemoteAction action) {
+ @VisibleForTesting
+ public void registerSystemAction(int id, RemoteAction action) {
synchronized (mSystemActionLock) {
mRegisteredSystemActions.put(id, action);
}
@@ -170,8 +175,13 @@ public class SystemActionPerformer {
/**
* This method is called to unregister a system action previously registered through
* registerSystemAction.
+ *
+ * This method is supposed to be package internal since this class is meant to be used by
+ * AccessibilityManagerService only. But Mockito has a bug which requiring this to be public
+ * to be mocked.
*/
- void unregisterSystemAction(int id) {
+ @VisibleForTesting
+ public void unregisterSystemAction(int id) {
synchronized (mSystemActionLock) {
mRegisteredSystemActions.remove(id);
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 95cd8fc47944..f34b5e71ad7b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -112,7 +112,6 @@ import com.android.server.autofill.ui.PendingUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -311,20 +310,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@NonNull
private final InputMethodManagerInternal mInputMethodManagerInternal;
- @GuardedBy("mLock")
- @Nullable
- private CompletableFuture<InlineSuggestionsRequest> mSuggestionsRequestFuture;
-
- @GuardedBy("mLock")
- @Nullable
- private CompletableFuture<IInlineSuggestionsResponseCallback>
- mInlineSuggestionsResponseCallbackFuture;
-
@Nullable
private InlineSuggestionsRequestCallbackImpl mInlineSuggestionsRequestCallback;
- private static final int INLINE_REQUEST_TIMEOUT_MS = 1000;
-
/**
* Receiver of assist data from the app's {@link Activity}.
*/
@@ -336,7 +324,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
+ "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
return;
}
- if (mCurrentViewId == null) {
+ // Keeps to prevent it is cleared on multiple threads.
+ final AutofillId currentViewId = mCurrentViewId;
+ if (currentViewId == null) {
Slog.w(TAG, "No current view id - session might have finished");
return;
}
@@ -410,7 +400,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (mContexts == null) {
mContexts = new ArrayList<>(1);
}
- mContexts.add(new FillContext(requestId, structure, mCurrentViewId));
+ mContexts.add(new FillContext(requestId, structure, currentViewId));
cancelCurrentRequestLocked();
@@ -422,7 +412,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final ArrayList<FillContext> contexts =
mergePreviousSessionLocked(/* forSave= */ false);
- final InlineSuggestionsRequest suggestionsRequest = getInlineSuggestionsRequest();
+ final InlineSuggestionsRequest suggestionsRequest =
+ mInlineSuggestionsRequestCallback != null
+ ? mInlineSuggestionsRequestCallback.getRequest() : null;
request = new FillRequest(requestId, contexts, mClientState, flags,
suggestionsRequest);
@@ -620,13 +612,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private void maybeRequestInlineSuggestionsRequestThenFillLocked(@NonNull ViewState viewState,
int newState, int flags) {
if (isInlineSuggestionsEnabled()) {
- mSuggestionsRequestFuture = new CompletableFuture<>();
- mInlineSuggestionsResponseCallbackFuture = new CompletableFuture<>();
-
- if (mInlineSuggestionsRequestCallback == null) {
- mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallbackImpl(this);
- }
-
+ mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallbackImpl();
mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(
mComponentName, mCurrentViewId, mInlineSuggestionsRequestCallback);
}
@@ -636,10 +622,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private static final class InlineSuggestionsRequestCallbackImpl
extends IInlineSuggestionsRequestCallback.Stub {
- private final WeakReference<Session> mSession;
+ private static final int INLINE_REQUEST_TIMEOUT_MS = 1000;
+
+ private final CompletableFuture<InlineSuggestionsRequest> mRequest;
+ private final CompletableFuture<IInlineSuggestionsResponseCallback> mResponseCallback;
- private InlineSuggestionsRequestCallbackImpl(Session session) {
- mSession = new WeakReference<>(session);
+ private InlineSuggestionsRequestCallbackImpl() {
+ mRequest = new CompletableFuture<>();
+ mResponseCallback = new CompletableFuture<>();
}
@Override
@@ -648,13 +638,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
Log.d(TAG, "inline suggestions request unsupported, "
+ "falling back to regular autofill");
}
- final Session session = mSession.get();
- if (session != null) {
- synchronized (session.mLock) {
- session.mSuggestionsRequestFuture.cancel(true);
- session.mInlineSuggestionsResponseCallbackFuture.cancel(true);
- }
- }
+ mRequest.cancel(true);
+ mResponseCallback.cancel(true);
}
@Override
@@ -663,13 +648,36 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (sDebug) {
Log.d(TAG, "onInlineSuggestionsRequest() received: " + request);
}
- final Session session = mSession.get();
- if (session != null) {
- synchronized (session.mLock) {
- session.mSuggestionsRequestFuture.complete(request);
- session.mInlineSuggestionsResponseCallbackFuture.complete(callback);
- }
+ mRequest.complete(request);
+ mResponseCallback.complete(callback);
+ }
+
+ @Nullable
+ private InlineSuggestionsRequest getRequest() {
+ try {
+ return mRequest.get(INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
+ } catch (CancellationException e) {
+ Log.w(TAG, "Inline suggestions request cancelled");
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ return null;
+ }
+
+ @Nullable
+ private IInlineSuggestionsResponseCallback getResponseCallback() {
+ try {
+ return mResponseCallback.get(INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
+ } catch (CancellationException e) {
+ Log.w(TAG, "Inline suggestions callback cancelled");
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
}
+ return null;
}
}
@@ -2678,22 +2686,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
* Returns whether we made a request to show inline suggestions.
*/
private boolean requestShowInlineSuggestions(FillResponse response) {
- IInlineSuggestionsResponseCallback inlineContentCallback = null;
- synchronized (mLock) {
- if (mInlineSuggestionsResponseCallbackFuture != null) {
- try {
- inlineContentCallback = mInlineSuggestionsResponseCallbackFuture.get(
- INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
- } catch (CancellationException e) {
- Log.w(TAG, "Inline suggestions callback cancelled");
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
+ final IInlineSuggestionsResponseCallback inlineContentCallback =
+ mInlineSuggestionsRequestCallback != null
+ ? mInlineSuggestionsRequestCallback.getResponseCallback() : null;
if (inlineContentCallback == null) {
Log.w(TAG, "Session input method callback is not set yet");
return false;
@@ -3015,10 +3010,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final AutofillId focusedId = AutofillId.withoutSession(mCurrentViewId);
- final InlineSuggestionsRequest inlineSuggestionsRequest = getInlineSuggestionsRequest();
+ final InlineSuggestionsRequest inlineSuggestionsRequest =
+ mInlineSuggestionsRequestCallback != null
+ ? mInlineSuggestionsRequestCallback.getRequest() : null;
final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback =
- getInlineSuggestionsResponseCallback();
-
+ mInlineSuggestionsRequestCallback != null
+ ? mInlineSuggestionsRequestCallback.getResponseCallback() : null;
remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, focusedId,
currentValue, inlineSuggestionsRequest, inlineSuggestionsResponseCallback);
@@ -3028,40 +3025,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return mAugmentedAutofillDestroyer;
}
- @Nullable
- private InlineSuggestionsRequest getInlineSuggestionsRequest() {
- if (mSuggestionsRequestFuture != null) {
- try {
- return mSuggestionsRequestFuture.get(
- INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
- } catch (CancellationException e) {
- Log.w(TAG, "Inline suggestions request cancelled");
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- return null;
- }
-
- @Nullable
- private IInlineSuggestionsResponseCallback getInlineSuggestionsResponseCallback() {
- if (mInlineSuggestionsResponseCallbackFuture != null) {
- try {
- return mInlineSuggestionsResponseCallbackFuture.get(
- INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
- } catch (CancellationException e) {
- Log.w(TAG, "Inline suggestions callback cancelled");
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- return null;
- }
-
@GuardedBy("mLock")
private void cancelAugmentedAutofillLocked() {
final RemoteAugmentedAutofillService remoteService = mService
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 3bce322a7655..d45a54e0ff28 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1452,6 +1452,11 @@ public class BackupManagerService extends IBackupManager.Stub {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) {
return;
}
+ dumpWithoutCheckingPermission(fd, pw, args);
+ }
+
+ @VisibleForTesting
+ void dumpWithoutCheckingPermission(FileDescriptor fd, PrintWriter pw, String[] args) {
int userId = binderGetCallingUserId();
if (!isUserReadyForBackup(userId)) {
pw.println("Inactive");
@@ -1460,7 +1465,16 @@ public class BackupManagerService extends IBackupManager.Stub {
if (args != null) {
for (String arg : args) {
- if ("users".equals(arg.toLowerCase())) {
+ if ("-h".equals(arg)) {
+ pw.println("'dumpsys backup' optional arguments:");
+ pw.println(" -h : this help text");
+ pw.println(" a[gents] : dump information about defined backup agents");
+ pw.println(" transportclients : dump information about transport clients");
+ pw.println(" transportstats : dump transport statts");
+ pw.println(" users : dump the list of users for which backup service "
+ + "is running");
+ return;
+ } else if ("users".equals(arg.toLowerCase())) {
pw.print(DUMP_RUNNING_USERS_MESSAGE);
for (int i = 0; i < mUserServices.size(); i++) {
pw.print(" " + mUserServices.keyAt(i));
@@ -1471,11 +1485,12 @@ public class BackupManagerService extends IBackupManager.Stub {
}
}
- UserBackupManagerService userBackupManagerService =
- getServiceForUserIfCallerHasPermission(UserHandle.USER_SYSTEM, "dump()");
-
- if (userBackupManagerService != null) {
- userBackupManagerService.dump(fd, pw, args);
+ for (int i = 0; i < mUserServices.size(); i++) {
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(mUserServices.keyAt(i), "dump()");
+ if (userBackupManagerService != null) {
+ userBackupManagerService.dump(fd, pw, args);
+ }
}
}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 064cd060528d..7b95ab526b41 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -3545,14 +3545,7 @@ public class UserBackupManagerService {
try {
if (args != null) {
for (String arg : args) {
- if ("-h".equals(arg)) {
- pw.println("'dumpsys backup' optional arguments:");
- pw.println(" -h : this help text");
- pw.println(" a[gents] : dump information about defined backup agents");
- pw.println(" users : dump the list of users for which backup service "
- + "is running");
- return;
- } else if ("agents".startsWith(arg)) {
+ if ("agents".startsWith(arg)) {
dumpAgents(pw);
return;
} else if ("transportclients".equals(arg.toLowerCase())) {
@@ -3583,8 +3576,10 @@ public class UserBackupManagerService {
}
private void dumpInternal(PrintWriter pw) {
+ // Add prefix for only non-system users so that system user dumpsys is the same as before
+ String userPrefix = mUserId == UserHandle.USER_SYSTEM ? "" : "User " + mUserId + ":";
synchronized (mQueueLock) {
- pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
+ pw.println(userPrefix + "Backup Manager is " + (mEnabled ? "enabled" : "disabled")
+ " / " + (!mSetupComplete ? "not " : "") + "setup complete / "
+ (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
@@ -3594,13 +3589,13 @@ public class UserBackupManagerService {
+ " (now = " + System.currentTimeMillis() + ')');
pw.println(" next scheduled: " + KeyValueBackupJob.nextScheduled(mUserId));
- pw.println("Transport whitelist:");
+ pw.println(userPrefix + "Transport whitelist:");
for (ComponentName transport : mTransportManager.getTransportWhitelist()) {
pw.print(" ");
pw.println(transport.flattenToShortString());
}
- pw.println("Available transports:");
+ pw.println(userPrefix + "Available transports:");
final String[] transports = listAllTransports();
if (transports != null) {
for (String t : transports) {
@@ -3626,18 +3621,18 @@ public class UserBackupManagerService {
mTransportManager.dumpTransportClients(pw);
- pw.println("Pending init: " + mPendingInits.size());
+ pw.println(userPrefix + "Pending init: " + mPendingInits.size());
for (String s : mPendingInits) {
pw.println(" " + s);
}
- pw.print("Ancestral: ");
+ pw.print(userPrefix + "Ancestral: ");
pw.println(Long.toHexString(mAncestralToken));
- pw.print("Current: ");
+ pw.print(userPrefix + "Current: ");
pw.println(Long.toHexString(mCurrentToken));
int numPackages = mBackupParticipants.size();
- pw.println("Participants:");
+ pw.println(userPrefix + "Participants:");
for (int i = 0; i < numPackages; i++) {
int uid = mBackupParticipants.keyAt(i);
pw.print(" uid: ");
@@ -3648,7 +3643,7 @@ public class UserBackupManagerService {
}
}
- pw.println("Ancestral packages: "
+ pw.println(userPrefix + "Ancestral packages: "
+ (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
if (mAncestralPackages != null) {
for (String pkg : mAncestralPackages) {
@@ -3657,17 +3652,17 @@ public class UserBackupManagerService {
}
Set<String> processedPackages = mProcessedPackagesJournal.getPackagesCopy();
- pw.println("Ever backed up: " + processedPackages.size());
+ pw.println(userPrefix + "Ever backed up: " + processedPackages.size());
for (String pkg : processedPackages) {
pw.println(" " + pkg);
}
- pw.println("Pending key/value backup: " + mPendingBackups.size());
+ pw.println(userPrefix + "Pending key/value backup: " + mPendingBackups.size());
for (BackupRequest req : mPendingBackups.values()) {
pw.println(" " + req);
}
- pw.println("Full backup queue:" + mFullBackupQueue.size());
+ pw.println(userPrefix + "Full backup queue:" + mFullBackupQueue.size());
for (FullBackupEntry entry : mFullBackupQueue) {
pw.print(" ");
pw.print(entry.lastBackup);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a1f57cb51188..b2fba730fac1 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -165,9 +165,3 @@ prebuilt_etc {
name: "protolog.conf.json.gz",
src: ":services.core.json.gz",
}
-
-platform_compat_config {
- name: "services-core-platform-compat-config",
- src: ":services.core.unboosted",
-}
-
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bd8a3618733f..c2e32d332f50 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -92,6 +92,7 @@ import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
import android.net.NetworkMonitorManager;
import android.net.NetworkPolicyManager;
+import android.net.NetworkProvider;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkScore;
@@ -219,6 +220,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* @hide
@@ -595,6 +597,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
// sequence number of NetworkRequests
private int mNextNetworkRequestId = 1;
+ // Sequence number for NetworkProvider IDs.
+ private final AtomicInteger mNextNetworkProviderId = new AtomicInteger(
+ NetworkProvider.FIRST_PROVIDER_ID);
+
// NetworkRequest activity String log entries.
private static final int MAX_NETWORK_REQUEST_LOGS = 20;
private final LocalLog mNetworkRequestInfoLogs = new LocalLog(MAX_NETWORK_REQUEST_LOGS);
@@ -3029,25 +3035,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (VDBG) log("NetworkFactory connected");
// Finish setting up the full connection
- mNetworkFactoryInfos.get(msg.replyTo).asyncChannel.sendMessage(
- AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
- // A network factory has connected. Send it all current NetworkRequests.
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.request.isListen()) continue;
- ensureRunningOnConnectivityServiceThread();
- NetworkAgentInfo nai = nri.mSatisfier;
- final int score;
- final int serial;
- if (nai != null) {
- score = nai.getCurrentScore();
- serial = nai.factorySerialNumber;
- } else {
- score = 0;
- serial = NetworkFactory.SerialNumber.NONE;
- }
- ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, serial,
- nri.request);
- }
+ NetworkFactoryInfo nfi = mNetworkFactoryInfos.get(msg.replyTo);
+ nfi.completeConnection();
+ sendAllRequestsToFactory(nfi);
} else {
loge("Error connecting NetworkFactory");
mNetworkFactoryInfos.remove(msg.obj);
@@ -3430,8 +3420,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
- nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST,
- nri.request);
+ nfi.cancelRequest(nri.request);
}
} else {
// listens don't have a singular affectedNetwork. Check all networks to see
@@ -4927,15 +4916,70 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static class NetworkFactoryInfo {
public final String name;
public final Messenger messenger;
- public final AsyncChannel asyncChannel;
+ private final AsyncChannel mAsyncChannel;
+ private final IBinder.DeathRecipient mDeathRecipient;
public final int factorySerialNumber;
NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
- int factorySerialNumber) {
+ int factorySerialNumber, IBinder.DeathRecipient deathRecipient) {
this.name = name;
this.messenger = messenger;
- this.asyncChannel = asyncChannel;
this.factorySerialNumber = factorySerialNumber;
+ mAsyncChannel = asyncChannel;
+ mDeathRecipient = deathRecipient;
+
+ if ((mAsyncChannel == null) == (mDeathRecipient == null)) {
+ throw new AssertionError("Must pass exactly one of asyncChannel or deathRecipient");
+ }
+ }
+
+ boolean isLegacyNetworkFactory() {
+ return mAsyncChannel != null;
+ }
+
+ void sendMessageToNetworkProvider(int what, int arg1, int arg2, Object obj) {
+ try {
+ messenger.send(Message.obtain(null /* handler */, what, arg1, arg2, obj));
+ } catch (RemoteException e) {
+ // Remote process died. Ignore; the death recipient will remove this
+ // NetworkFactoryInfo from mNetworkFactoryInfos.
+ }
+ }
+
+ void requestNetwork(NetworkRequest request, int score, int servingSerialNumber) {
+ if (isLegacyNetworkFactory()) {
+ mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
+ servingSerialNumber, request);
+ } else {
+ sendMessageToNetworkProvider(NetworkProvider.CMD_REQUEST_NETWORK, score,
+ servingSerialNumber, request);
+ }
+ }
+
+ void cancelRequest(NetworkRequest request) {
+ if (isLegacyNetworkFactory()) {
+ mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, request);
+ } else {
+ sendMessageToNetworkProvider(NetworkProvider.CMD_CANCEL_REQUEST, 0, 0, request);
+ }
+ }
+
+ void connect(Context context, Handler handler) {
+ if (isLegacyNetworkFactory()) {
+ mAsyncChannel.connect(context, handler, messenger);
+ } else {
+ try {
+ messenger.getBinder().linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ mDeathRecipient.binderDied();
+ }
+ }
+ }
+
+ void completeConnection() {
+ if (isLegacyNetworkFactory()) {
+ mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ }
}
}
@@ -5306,6 +5350,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
}
+ /** Returns the next Network provider ID. */
+ public final int nextNetworkProviderId() {
+ return mNextNetworkProviderId.getAndIncrement();
+ }
+
@Override
public void releaseNetworkRequest(NetworkRequest networkRequest) {
ensureNetworkRequestHasType(networkRequest);
@@ -5317,23 +5366,51 @@ public class ConnectivityService extends IConnectivityManager.Stub
public int registerNetworkFactory(Messenger messenger, String name) {
enforceNetworkFactoryPermission();
NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(),
- NetworkFactory.SerialNumber.nextSerialNumber());
+ nextNetworkProviderId(), null /* deathRecipient */);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
return nfi.factorySerialNumber;
}
private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
+ if (mNetworkFactoryInfos.containsKey(nfi.messenger)) {
+ // Avoid creating duplicates. even if an app makes a direct AIDL call.
+ // This will never happen if an app calls ConnectivityManager#registerNetworkProvider,
+ // as that will throw if a duplicate provider is registered.
+ Slog.e(TAG, "Attempt to register existing NetworkFactoryInfo "
+ + mNetworkFactoryInfos.get(nfi.messenger).name);
+ return;
+ }
+
if (DBG) log("Got NetworkFactory Messenger for " + nfi.name);
mNetworkFactoryInfos.put(nfi.messenger, nfi);
- nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
+ nfi.connect(mContext, mTrackerHandler);
+ if (!nfi.isLegacyNetworkFactory()) {
+ // Legacy NetworkFactories get their requests when their AsyncChannel connects.
+ sendAllRequestsToFactory(nfi);
+ }
}
@Override
- public void unregisterNetworkFactory(Messenger messenger) {
+ public int registerNetworkProvider(Messenger messenger, String name) {
+ enforceNetworkFactoryPermission();
+ NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger,
+ null /* asyncChannel */, nextNetworkProviderId(),
+ () -> unregisterNetworkProvider(messenger));
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
+ return nfi.factorySerialNumber;
+ }
+
+ @Override
+ public void unregisterNetworkProvider(Messenger messenger) {
enforceNetworkFactoryPermission();
mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger));
}
+ @Override
+ public void unregisterNetworkFactory(Messenger messenger) {
+ unregisterNetworkProvider(messenger);
+ }
+
private void handleUnregisterNetworkFactory(Messenger messenger) {
NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger);
if (nfi == null) {
@@ -5343,6 +5420,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log("unregisterNetworkFactory for " + nfi.name);
}
+ @Override
+ public void declareNetworkRequestUnfulfillable(NetworkRequest request) {
+ enforceNetworkFactoryPermission();
+ mHandler.post(() -> handleReleaseNetworkRequest(request, Binder.getCallingUid(), true));
+ }
+
// NOTE: Accessed on multiple threads, must be synchronized on itself.
@GuardedBy("mNetworkForNetId")
private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
@@ -5961,8 +6044,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
}
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
- nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
- serial, networkRequest);
+ nfi.requestNetwork(networkRequest, score, serial);
+ }
+ }
+
+ /** Sends all current NetworkRequests to the specified factory. */
+ private void sendAllRequestsToFactory(NetworkFactoryInfo nfi) {
+ ensureRunningOnConnectivityServiceThread();
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ if (nri.request.isListen()) continue;
+ NetworkAgentInfo nai = nri.mSatisfier;
+ final int score;
+ final int serial;
+ if (nai != null) {
+ score = nai.getCurrentScore();
+ serial = nai.factorySerialNumber;
+ } else {
+ score = 0;
+ serial = NetworkFactory.SerialNumber.NONE;
+ }
+ nfi.requestNetwork(nri.request, score, serial);
}
}
diff --git a/services/core/java/com/android/server/GnssManagerService.java b/services/core/java/com/android/server/GnssManagerService.java
index bbcfdc63f3f1..32cdc41472c9 100644
--- a/services/core/java/com/android/server/GnssManagerService.java
+++ b/services/core/java/com/android/server/GnssManagerService.java
@@ -47,7 +47,6 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocationManagerServiceUtils.LinkedListener;
import com.android.server.LocationManagerServiceUtils.LinkedListenerBase;
-import com.android.server.location.AbstractLocationProvider;
import com.android.server.location.CallerIdentity;
import com.android.server.location.GnssBatchingProvider;
import com.android.server.location.GnssCapabilitiesProvider;
@@ -116,11 +115,9 @@ public class GnssManagerService {
private final Handler mHandler;
public GnssManagerService(LocationManagerService locationManagerService,
- Context context,
- AbstractLocationProvider.LocationProviderManager gnssProviderManager,
- LocationUsageLogger locationUsageLogger) {
- this(locationManagerService, context, new GnssLocationProvider(context, gnssProviderManager,
- FgThread.getHandler().getLooper()), locationUsageLogger);
+ Context context, LocationUsageLogger locationUsageLogger) {
+ this(locationManagerService, context,
+ new GnssLocationProvider(context, FgThread.getHandler()), locationUsageLogger);
}
// Can use this constructor to inject GnssLocationProvider for testing
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index c5f1923b0b98..32128d5f26f8 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -23,8 +23,6 @@ import static android.location.LocationManager.NETWORK_PROVIDER;
import static android.location.LocationManager.PASSIVE_PROVIDER;
import static android.os.PowerManager.locationPowerSaveModeToString;
-import static com.android.internal.util.Preconditions.checkState;
-
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -74,7 +72,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
-import android.provider.Settings;
import android.stats.location.LocationStatsEnums;
import android.text.TextUtils;
import android.util.EventLog;
@@ -92,6 +89,7 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.location.AbstractLocationProvider;
+import com.android.server.location.AbstractLocationProvider.State;
import com.android.server.location.ActivityRecognitionProxy;
import com.android.server.location.CallerIdentity;
import com.android.server.location.GeocoderProxy;
@@ -105,6 +103,7 @@ import com.android.server.location.LocationRequestStatistics.PackageStatistics;
import com.android.server.location.LocationSettingsStore;
import com.android.server.location.LocationUsageLogger;
import com.android.server.location.MockProvider;
+import com.android.server.location.MockableLocationProvider;
import com.android.server.location.PassiveProvider;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -121,6 +120,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
/**
@@ -196,6 +197,8 @@ public class LocationManagerService extends ILocationManager.Stub {
private final LocationSettingsStore mSettingsStore;
private final LocationUsageLogger mLocationUsageLogger;
+ private final PassiveLocationProviderManager mPassiveManager;
+
private AppOpsManager mAppOps;
private PackageManager mPackageManager;
private PowerManager mPowerManager;
@@ -205,21 +208,17 @@ public class LocationManagerService extends ILocationManager.Stub {
private GeofenceManager mGeofenceManager;
private LocationFudger mLocationFudger;
private GeocoderProxy mGeocodeProvider;
- @Nullable
- private GnssManagerService mGnssManagerService;
- private PassiveProvider mPassiveProvider; // track passive provider for special cases
+ @Nullable private GnssManagerService mGnssManagerService;
+
@GuardedBy("mLock")
private String mExtraLocationControllerPackage;
- private boolean mExtraLocationControllerPackageEnabled;
-
- // list of currently active providers
@GuardedBy("mLock")
- private final ArrayList<LocationProviderManager> mProviders = new ArrayList<>();
+ private boolean mExtraLocationControllerPackageEnabled;
- // list of non-mock providers, so that when mock providers replace real providers, they can be
- // later re-replaced
- @GuardedBy("mLock")
- private final ArrayList<LocationProviderManager> mRealProviders = new ArrayList<>();
+ // @GuardedBy("mLock")
+ // hold lock for write or to prevent write, no lock for read
+ private final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
+ new CopyOnWriteArrayList<>();
@GuardedBy("mLock")
private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
@@ -238,9 +237,9 @@ public class LocationManagerService extends ILocationManager.Stub {
private final HashMap<String, Location> mLastLocationCoarseInterval =
new HashMap<>();
- // current active user on the device - other users are denied location data
- private int mCurrentUserId = UserHandle.USER_SYSTEM;
- private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
+ // current active user on the device
+ private int mCurrentUserId;
+ private int[] mCurrentUserProfiles;
@GuardedBy("mLock")
@PowerManager.LocationPowerSaveMode
@@ -252,6 +251,17 @@ public class LocationManagerService extends ILocationManager.Stub {
mSettingsStore = new LocationSettingsStore(mContext, mHandler);
mLocationUsageLogger = new LocationUsageLogger();
+ mCurrentUserId = UserHandle.USER_NULL;
+ mCurrentUserProfiles = new int[]{UserHandle.USER_NULL};
+
+ // set up passive provider - we do this early because it has no dependencies on system
+ // services or external code that isn't ready yet, and because this allows the variable to
+ // be final. other more complex providers are initialized later, when system services are
+ // ready
+ mPassiveManager = new PassiveLocationProviderManager();
+ mProviderManagers.add(mPassiveManager);
+ mPassiveManager.setRealProvider(new PassiveProvider(mContext));
+
// Let the package manager query which are the default location
// providers as they get certain permissions granted by default.
PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
@@ -415,15 +425,15 @@ public class LocationManagerService extends ILocationManager.Stub {
for (Receiver receiver : mReceivers.values()) {
receiver.updateMonitoring(true);
}
- for (LocationProviderManager p : mProviders) {
- applyRequirementsLocked(p);
+ for (LocationProviderManager manager : mProviderManagers) {
+ applyRequirementsLocked(manager);
}
}
@GuardedBy("mLock")
private void onPermissionsChangedLocked() {
- for (LocationProviderManager p : mProviders) {
- applyRequirementsLocked(p);
+ for (LocationProviderManager manager : mProviderManagers) {
+ applyRequirementsLocked(manager);
}
}
@@ -442,16 +452,16 @@ public class LocationManagerService extends ILocationManager.Stub {
mBatterySaverMode = newLocationMode;
- for (LocationProviderManager p : mProviders) {
- applyRequirementsLocked(p);
+ for (LocationProviderManager manager : mProviderManagers) {
+ applyRequirementsLocked(manager);
}
}
@GuardedBy("mLock")
private void onScreenStateChangedLocked() {
if (mBatterySaverMode == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) {
- for (LocationProviderManager p : mProviders) {
- applyRequirementsLocked(p);
+ for (LocationProviderManager manager : mProviderManagers) {
+ applyRequirementsLocked(manager);
}
}
}
@@ -466,8 +476,8 @@ public class LocationManagerService extends ILocationManager.Stub {
intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId));
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
- for (LocationProviderManager p : mProviders) {
- p.onUseableChangedLocked(userId);
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.onUseableChangedLocked(userId);
}
}
@@ -521,22 +531,22 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
private void onBackgroundThrottleIntervalChangedLocked() {
- for (LocationProviderManager provider : mProviders) {
- applyRequirementsLocked(provider);
+ for (LocationProviderManager manager : mProviderManagers) {
+ applyRequirementsLocked(manager);
}
}
@GuardedBy("mLock")
private void onBackgroundThrottleWhitelistChangedLocked() {
- for (LocationProviderManager p : mProviders) {
- applyRequirementsLocked(p);
+ for (LocationProviderManager manager : mProviderManagers) {
+ applyRequirementsLocked(manager);
}
}
@GuardedBy("lock")
private void onIgnoreSettingsWhitelistChangedLocked() {
- for (LocationProviderManager p : mProviders) {
- applyRequirementsLocked(p);
+ for (LocationProviderManager manager : mProviderManagers) {
+ applyRequirementsLocked(manager);
}
}
@@ -623,22 +633,11 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
private void initializeProvidersLocked() {
- // create a passive location provider, which is always enabled
- LocationProviderManager passiveProviderManager = new LocationProviderManager(
- PASSIVE_PROVIDER);
- addProviderLocked(passiveProviderManager);
- mPassiveProvider = new PassiveProvider(mContext, passiveProviderManager);
- passiveProviderManager.attachLocked(mPassiveProvider);
-
if (GnssManagerService.isGnssSupported()) {
- // Create a gps location provider manager
- LocationProviderManager gnssProviderManager = new LocationProviderManager(GPS_PROVIDER);
- mRealProviders.add(gnssProviderManager);
- addProviderLocked(gnssProviderManager);
-
- mGnssManagerService = new GnssManagerService(this, mContext, gnssProviderManager,
- mLocationUsageLogger);
- gnssProviderManager.attachLocked(mGnssManagerService.getGnssLocationProvider());
+ mGnssManagerService = new GnssManagerService(this, mContext, mLocationUsageLogger);
+ LocationProviderManager gnssManager = new LocationProviderManager(GPS_PROVIDER);
+ mProviderManagers.add(gnssManager);
+ gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider());
}
/*
@@ -662,37 +661,31 @@ public class LocationManagerService extends ILocationManager.Stub {
ensureFallbackFusedProviderPresentLocked(pkgs);
- // bind to network provider
- LocationProviderManager networkProviderManager = new LocationProviderManager(
- NETWORK_PROVIDER);
LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
mContext,
- networkProviderManager,
NETWORK_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableNetworkLocationOverlay,
com.android.internal.R.string.config_networkLocationProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames);
if (networkProvider != null) {
- mRealProviders.add(networkProviderManager);
- addProviderLocked(networkProviderManager);
- networkProviderManager.attachLocked(networkProvider);
+ LocationProviderManager networkManager = new LocationProviderManager(NETWORK_PROVIDER);
+ mProviderManagers.add(networkManager);
+ networkManager.setRealProvider(networkProvider);
} else {
Slog.w(TAG, "no network location provider found");
}
// bind to fused provider
- LocationProviderManager fusedProviderManager = new LocationProviderManager(FUSED_PROVIDER);
LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
mContext,
- fusedProviderManager,
FUSED_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableFusedLocationOverlay,
com.android.internal.R.string.config_fusedLocationProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames);
if (fusedProvider != null) {
- mRealProviders.add(fusedProviderManager);
- addProviderLocked(fusedProviderManager);
- fusedProviderManager.attachLocked(fusedProvider);
+ LocationProviderManager fusedManager = new LocationProviderManager(FUSED_PROVIDER);
+ mProviderManagers.add(fusedManager);
+ fusedManager.setRealProvider(fusedProvider);
} else {
Slog.e(TAG, "no fused location provider found",
new IllegalStateException("Location service needs a fused location provider"));
@@ -754,10 +747,7 @@ public class LocationManagerService extends ILocationManager.Stub {
Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
Integer.parseInt(fragments[8]) /* powerRequirement */,
Integer.parseInt(fragments[9]) /* accuracy */);
- LocationProviderManager testProviderManager = new LocationProviderManager(name);
- addProviderLocked(testProviderManager);
- testProviderManager.attachLocked(
- new MockProvider(mContext, testProviderManager, properties));
+ addTestProvider(name, properties, mContext.getOpPackageName());
}
}
@@ -771,231 +761,202 @@ public class LocationManagerService extends ILocationManager.Stub {
Log.d(TAG, "foreground user is changing to " + userId);
}
- int oldUserId = userId;
+ int oldUserId = mCurrentUserId;
mCurrentUserId = userId;
onUserProfilesChangedLocked();
// let providers know the current user has changed
- for (LocationProviderManager p : mProviders) {
- p.onUseableChangedLocked(oldUserId);
- p.onUseableChangedLocked(mCurrentUserId);
+ for (LocationProviderManager manager : mProviderManagers) {
+ // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
+ mSettingsStore.setLocationProviderAllowed(manager.getName(),
+ manager.isUseable(mCurrentUserId), mCurrentUserId);
+
+ manager.onUseableChangedLocked(oldUserId);
+ manager.onUseableChangedLocked(mCurrentUserId);
}
}
/**
* Location provider manager, manages a LocationProvider.
*/
- class LocationProviderManager implements AbstractLocationProvider.LocationProviderManager {
+ class LocationProviderManager implements MockableLocationProvider.Listener {
private final String mName;
- // remember to clear binder identity before invoking any provider operation
- @GuardedBy("mLock")
- @Nullable
- protected AbstractLocationProvider mProvider;
+ // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
+ protected final MockableLocationProvider mProvider;
@GuardedBy("mLock")
- private SparseArray<Boolean> mUseable; // combined state for each user id
- @GuardedBy("mLock")
- private boolean mEnabled; // state of provider
-
- @GuardedBy("mLock")
- @Nullable
- private ProviderProperties mProperties;
+ private final SparseArray<Boolean> mUseable; // combined state for each user id
private LocationProviderManager(String name) {
mName = name;
-
- mProvider = null;
mUseable = new SparseArray<>(1);
- mEnabled = false;
- mProperties = null;
-
- // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
- Settings.Secure.putStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- "-" + mName,
- mCurrentUserId);
- }
-
- @GuardedBy("mLock")
- public void attachLocked(AbstractLocationProvider provider) {
- Objects.requireNonNull(provider);
- checkState(mProvider == null);
- if (D) {
- Log.d(TAG, mName + " provider attached");
- }
-
- mProvider = provider;
-
- // it would be more correct to call this for all users, but we know this can only
- // affect the current user since providers are disabled for non-current users
- onUseableChangedLocked(mCurrentUserId);
+ // initialize last since this lets our reference escape
+ mProvider = new MockableLocationProvider(mContext, mLock, this);
}
public String getName() {
return mName;
}
- @GuardedBy("mLock")
- public List<String> getPackagesLocked() {
- if (mProvider == null) {
- return Collections.emptyList();
- } else {
- // safe to not clear binder context since this doesn't call into the real provider
- return mProvider.getProviderPackages();
- }
+ public boolean hasProvider() {
+ return mProvider.getProvider() != null;
}
- public boolean isMock() {
- return false;
+ public void setRealProvider(AbstractLocationProvider provider) {
+ mProvider.setRealProvider(provider);
}
- @GuardedBy("mLock")
- public boolean isPassiveLocked() {
- return mProvider == mPassiveProvider;
+ public void setMockProvider(@Nullable MockProvider provider) {
+ mProvider.setMockProvider(provider);
+ }
+
+ public Set<String> getPackages() {
+ return mProvider.getState().providerPackageNames;
}
- @GuardedBy("mLock")
@Nullable
- public ProviderProperties getPropertiesLocked() {
- return mProperties;
+ public ProviderProperties getProperties() {
+ return mProvider.getState().properties;
}
- public void setRequest(ProviderRequest request, WorkSource workSource) {
- // move calls going to providers onto a different thread to avoid deadlock
- mHandler.post(() -> {
- synchronized (mLock) {
- if (mProvider != null) {
- mProvider.onSetRequest(request, workSource);
- }
+ public void setMockProviderEnabled(boolean enabled) {
+ synchronized (mLock) {
+ if (!mProvider.isMock()) {
+ throw new IllegalArgumentException(mName + " provider is not a test provider");
}
- });
+
+ mProvider.setMockProviderEnabled(enabled);
+ }
}
- public void sendExtraCommand(String command, Bundle extras) {
- int uid = Binder.getCallingUid();
- int pid = Binder.getCallingPid();
+ public void setMockProviderLocation(Location location) {
+ synchronized (mLock) {
+ if (!mProvider.isMock()) {
+ throw new IllegalArgumentException(mName + " provider is not a test provider");
+ }
- // move calls going to providers onto a different thread to avoid deadlock
- mHandler.post(() -> {
- synchronized (mLock) {
- if (mProvider != null) {
- mProvider.onSendExtraCommand(uid, pid, command, extras);
- }
+ String locationProvider = location.getProvider();
+ if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
+ // The location has an explicit provider that is different from the mock
+ // provider name. The caller may be trying to fool us via b/33091107.
+ EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
+ mName + "!=" + locationProvider);
}
- });
- }
- @GuardedBy("mLock")
- public void dumpLocked(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
- pw.print(mName + " provider");
- if (isMock()) {
- pw.print(" [mock]");
+ mProvider.setMockProviderLocation(location);
}
- pw.println(":");
+ }
- pw.increaseIndent();
+ public List<LocationRequest> getMockProviderRequests() {
+ synchronized (mLock) {
+ if (!mProvider.isMock()) {
+ throw new IllegalArgumentException(mName + " provider is not a test provider");
+ }
- pw.println("useable=" + isUseableLocked(mCurrentUserId));
- if (!isUseableLocked(mCurrentUserId)) {
- pw.println("attached=" + (mProvider != null));
- pw.println("enabled=" + mEnabled);
+ return mProvider.getCurrentRequest().locationRequests;
}
+ }
- pw.println("properties=" + mProperties);
+ public void setRequest(ProviderRequest request) {
+ mProvider.setRequest(request);
+ }
- if (mProvider != null) {
- // in order to be consistent with other provider APIs, this should be run on the
- // location thread... but this likely isn't worth it just for dumping info.
- long identity = Binder.clearCallingIdentity();
- try {
- mProvider.dump(fd, pw, args);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
+ mProvider.sendExtraCommand(uid, pid, command, extras);
+ }
+
+ public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
+ synchronized (mLock) {
+ pw.print(mName + " provider");
+ if (mProvider.isMock()) {
+ pw.print(" [mock]");
+ }
+ pw.println(":");
+
+ pw.increaseIndent();
+
+ pw.println("useable=" + isUseable(mCurrentUserId));
+ if (!isUseable(mCurrentUserId)) {
+ pw.println("enabled=" + mProvider.getState().enabled);
}
+
+ pw.println("properties=" + mProvider.getState().properties);
}
+ mProvider.dump(fd, pw, args);
+
pw.decreaseIndent();
}
+ @GuardedBy("mLock")
@Override
public void onReportLocation(Location location) {
- // likelihood of a 0,0 bug is far greater than this being a valid location
- if (!isMock() && location.getLatitude() == 0 && location.getLongitude() == 0) {
- Slog.w(TAG, "blocking 0,0 location from " + mName + " provider");
- return;
+ // don't validate mock locations
+ if (!location.isFromMockProvider()) {
+ if (location.getLatitude() == 0 && location.getLongitude() == 0) {
+ Slog.w(TAG, "blocking 0,0 location from " + mName + " provider");
+ return;
+ }
}
- synchronized (mLock) {
- handleLocationChangedLocked(location, this);
- }
+ handleLocationChangedLocked(location, this);
}
+ @GuardedBy("mLock")
@Override
public void onReportLocation(List<Location> locations) {
if (mGnssManagerService == null) {
return;
}
- synchronized (mLock) {
- LocationProviderManager gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
- if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
- Slog.w(TAG, "reportLocationBatch() called without user permission");
- return;
- }
- mGnssManagerService.onReportLocation(locations);
+ if (!GPS_PROVIDER.equals(mName) || !isUseable()) {
+ Slog.w(TAG, "reportLocationBatch() called without user permission");
+ return;
}
- }
- @Override
- public void onSetEnabled(boolean enabled) {
- synchronized (mLock) {
- if (enabled == mEnabled) {
- return;
- }
-
- if (D) {
- Log.d(TAG, mName + " provider enabled is now " + mEnabled);
- }
-
- mEnabled = enabled;
-
- // it would be more correct to call this for all users, but we know this can only
- // affect the current user since providers are disabled for non-current users
- onUseableChangedLocked(mCurrentUserId);
- }
+ mGnssManagerService.onReportLocation(locations);
}
+ @GuardedBy("mLock")
@Override
- public void onSetProperties(ProviderProperties properties) {
- synchronized (mLock) {
- mProperties = properties;
+ public void onStateChanged(State oldState, State newState) {
+ if (oldState.enabled != newState.enabled) {
+ // it would be more correct to call this for all users, but we know this can
+ // only affect the current user since providers are disabled for non-current
+ // users
+ onUseableChangedLocked(mCurrentUserId);
}
}
@GuardedBy("mLock")
- public boolean isUseableLocked() {
- return isUseableLocked(mCurrentUserId);
+ public boolean isUseable() {
+ return isUseable(mCurrentUserId);
}
@GuardedBy("mLock")
- public boolean isUseableLocked(int userId) {
- return mUseable.get(userId, Boolean.FALSE);
+ public boolean isUseable(int userId) {
+ synchronized (mLock) {
+ return mUseable.get(userId, Boolean.FALSE);
+ }
}
@GuardedBy("mLock")
public void onUseableChangedLocked(int userId) {
+ if (userId == UserHandle.USER_NULL) {
+ // only used during initialization - we don't care about the null user
+ return;
+ }
+
// if any property that contributes to "useability" here changes state, it MUST result
// in a direct or indrect call to onUseableChangedLocked. this allows the provider to
// guarantee that it will always eventually reach the correct state.
- boolean useable = mProvider != null && mProviders.contains(this)
- && isCurrentProfileLocked(userId) && isLocationEnabledForUser(userId)
- && mEnabled;
+ boolean useable = isCurrentProfileLocked(userId)
+ && mSettingsStore.isLocationEnabled(userId) && mProvider.getState().enabled;
- if (useable == isUseableLocked(userId)) {
+ if (useable == isUseable(userId)) {
return;
}
mUseable.put(userId, useable);
@@ -1007,11 +968,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// fused and passive provider never get public updates for legacy reasons
if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
// update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
- Settings.Secure.putStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- (useable ? "+" : "-") + mName,
- userId);
+ mSettingsStore.setLocationProviderAllowed(mName, useable, userId);
Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION);
intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName);
@@ -1031,53 +988,38 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private class MockLocationProvider extends LocationProviderManager {
+ class PassiveLocationProviderManager extends LocationProviderManager {
- private ProviderRequest mCurrentRequest;
-
- private MockLocationProvider(String name) {
- super(name);
+ private PassiveLocationProviderManager() {
+ super(PASSIVE_PROVIDER);
}
@Override
- public void attachLocked(AbstractLocationProvider provider) {
- checkState(provider instanceof MockProvider);
- super.attachLocked(provider);
- }
-
- public boolean isMock() {
- return true;
+ public void setRealProvider(AbstractLocationProvider provider) {
+ Preconditions.checkArgument(provider instanceof PassiveProvider);
+ super.setRealProvider(provider);
}
- @GuardedBy("mLock")
- public void setEnabledLocked(boolean enabled) {
- if (mProvider != null) {
- long identity = Binder.clearCallingIdentity();
- try {
- ((MockProvider) mProvider).setEnabled(enabled);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ @Override
+ public void setMockProvider(@Nullable MockProvider provider) {
+ if (provider != null) {
+ throw new IllegalArgumentException("Cannot mock the passive provider");
}
}
- @GuardedBy("mLock")
- public void setLocationLocked(Location location) {
- if (mProvider != null) {
+ public void updateLocation(Location location) {
+ synchronized (mLock) {
+ PassiveProvider passiveProvider = (PassiveProvider) mProvider.getProvider();
+ Preconditions.checkState(passiveProvider != null);
+
long identity = Binder.clearCallingIdentity();
try {
- ((MockProvider) mProvider).setLocation(location);
+ passiveProvider.updateLocation(location);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
-
- @Override
- public void setRequest(ProviderRequest request, WorkSource workSource) {
- super.setRequest(request, workSource);
- mCurrentRequest = request;
- }
}
/**
@@ -1181,17 +1123,17 @@ public class LocationManagerService extends ILocationManager.Stub {
// See if receiver has any enabled update records. Also note if any update records
// are high power (has a high power provider with an interval under a threshold).
for (UpdateRecord updateRecord : mUpdateRecords.values()) {
- LocationProviderManager provider = getLocationProviderLocked(
+ LocationProviderManager manager = getLocationProviderManager(
updateRecord.mProvider);
- if (provider == null) {
+ if (manager == null) {
continue;
}
- if (!provider.isUseableLocked() && !isSettingsExemptLocked(updateRecord)) {
+ if (!manager.isUseable() && !isSettingsExemptLocked(updateRecord)) {
continue;
}
requestingLocation = true;
- ProviderProperties properties = provider.getPropertiesLocked();
+ ProviderProperties properties = manager.getProperties();
if (properties != null
&& properties.mPowerRequirement == Criteria.POWER_HIGH
&& updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
@@ -1432,7 +1374,7 @@ public class LocationManagerService extends ILocationManager.Stub {
String featureId, String listenerIdentifier) {
Objects.requireNonNull(listenerIdentifier);
- return mGnssManagerService == null ? false : mGnssManagerService.addGnssBatchingCallback(
+ return mGnssManagerService != null && mGnssManagerService.addGnssBatchingCallback(
callback, packageName, featureId, listenerIdentifier);
}
@@ -1443,7 +1385,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
- return mGnssManagerService == null ? false : mGnssManagerService.startGnssBatch(periodNanos,
+ return mGnssManagerService != null && mGnssManagerService.startGnssBatch(periodNanos,
wakeOnFifoFull, packageName);
}
@@ -1454,35 +1396,14 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean stopGnssBatch() {
- return mGnssManagerService == null ? false : mGnssManagerService.stopGnssBatch();
+ return mGnssManagerService != null && mGnssManagerService.stopGnssBatch();
}
- @GuardedBy("mLock")
- private void addProviderLocked(LocationProviderManager provider) {
- Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
-
- mProviders.add(provider);
-
- // it would be more correct to call this for all users, but we know this can only
- // affect the current user since providers are disabled for non-current users
- provider.onUseableChangedLocked(mCurrentUserId);
- }
-
- @GuardedBy("mLock")
- private void removeProviderLocked(LocationProviderManager provider) {
- if (mProviders.remove(provider)) {
- // it would be more correct to call this for all users, but we know this can only
- // affect the current user since providers are disabled for non-current users
- provider.onUseableChangedLocked(mCurrentUserId);
- }
- }
-
- @GuardedBy("mLock")
@Nullable
- private LocationProviderManager getLocationProviderLocked(String providerName) {
- for (LocationProviderManager provider : mProviders) {
- if (providerName.equals(provider.getName())) {
- return provider;
+ private LocationProviderManager getLocationProviderManager(String providerName) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ if (providerName.equals(manager.getName())) {
+ return manager;
}
}
@@ -1531,12 +1452,12 @@ public class LocationManagerService extends ILocationManager.Stub {
// network and fused providers are ok with COARSE or FINE
return RESOLUTION_LEVEL_COARSE;
} else {
- for (LocationProviderManager lp : mProviders) {
+ for (LocationProviderManager lp : mProviderManagers) {
if (!lp.getName().equals(provider)) {
continue;
}
- ProviderProperties properties = lp.getPropertiesLocked();
+ ProviderProperties properties = lp.getProperties();
if (properties != null) {
if (properties.mRequiresSatellite) {
// provider requiring satellites require FINE permission
@@ -1587,11 +1508,9 @@ public class LocationManagerService extends ILocationManager.Stub {
case RESOLUTION_LEVEL_COARSE:
return AppOpsManager.OPSTR_COARSE_LOCATION;
case RESOLUTION_LEVEL_FINE:
- return AppOpsManager.OPSTR_FINE_LOCATION;
+ // fall through
case RESOLUTION_LEVEL_NONE:
- // The client is not allowed to get any location, so both FINE and COARSE ops will
- // be denied. Pick the most restrictive one to be safe.
- return AppOpsManager.OPSTR_FINE_LOCATION;
+ // fall through
default:
// Use the most restrictive ops if not sure.
return AppOpsManager.OPSTR_FINE_LOCATION;
@@ -1629,17 +1548,14 @@ public class LocationManagerService extends ILocationManager.Stub {
*/
@Override
public List<String> getAllProviders() {
- synchronized (mLock) {
- ArrayList<String> providers = new ArrayList<>(mProviders.size());
- for (LocationProviderManager provider : mProviders) {
- String name = provider.getName();
- if (FUSED_PROVIDER.equals(name)) {
- continue;
- }
- providers.add(name);
+ ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
+ for (LocationProviderManager manager : mProviderManagers) {
+ if (FUSED_PROVIDER.equals(manager.getName())) {
+ continue;
}
- return providers;
+ providers.add(manager.getName());
}
+ return providers;
}
/**
@@ -1651,21 +1567,21 @@ public class LocationManagerService extends ILocationManager.Stub {
public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
synchronized (mLock) {
- ArrayList<String> providers = new ArrayList<>(mProviders.size());
- for (LocationProviderManager provider : mProviders) {
- String name = provider.getName();
+ ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
+ for (LocationProviderManager manager : mProviderManagers) {
+ String name = manager.getName();
if (FUSED_PROVIDER.equals(name)) {
continue;
}
if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
continue;
}
- if (enabledOnly && !provider.isUseableLocked()) {
+ if (enabledOnly && !manager.isUseable()) {
continue;
}
if (criteria != null
&& !android.location.LocationProvider.propertiesMeetCriteria(
- name, provider.getPropertiesLocked(), criteria)) {
+ name, manager.getProperties(), criteria)) {
continue;
}
providers.add(name);
@@ -1702,12 +1618,12 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@GuardedBy("mLock")
- private void updateProviderUseableLocked(LocationProviderManager provider) {
- boolean useable = provider.isUseableLocked();
+ private void updateProviderUseableLocked(LocationProviderManager manager) {
+ boolean useable = manager.isUseable();
ArrayList<Receiver> deadReceivers = null;
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
if (records != null) {
for (UpdateRecord record : records) {
if (!isCurrentProfileLocked(
@@ -1721,7 +1637,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
// Sends a notification message to the receiver
- if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
+ if (!record.mReceiver.callProviderEnabledLocked(manager.getName(), useable)) {
if (deadReceivers == null) {
deadReceivers = new ArrayList<>();
}
@@ -1736,26 +1652,25 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- applyRequirementsLocked(provider);
+ applyRequirementsLocked(manager);
}
@GuardedBy("mLock")
private void applyRequirementsLocked(String providerName) {
- LocationProviderManager provider = getLocationProviderLocked(providerName);
- if (provider != null) {
- applyRequirementsLocked(provider);
+ LocationProviderManager manager = getLocationProviderManager(providerName);
+ if (manager != null) {
+ applyRequirementsLocked(manager);
}
}
@GuardedBy("mLock")
- private void applyRequirementsLocked(LocationProviderManager provider) {
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
- WorkSource worksource = new WorkSource();
- ProviderRequest providerRequest = new ProviderRequest();
+ private void applyRequirementsLocked(LocationProviderManager manager) {
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
+ ProviderRequest.Builder providerRequest = new ProviderRequest.Builder();
// if provider is not active, it should not respond to requests
- if (mProviders.contains(provider) && records != null && !records.isEmpty()) {
+ if (mProviderManagers.contains(manager) && records != null && !records.isEmpty()) {
long backgroundThrottleInterval;
long identity = Binder.clearCallingIdentity();
@@ -1765,6 +1680,8 @@ public class LocationManagerService extends ILocationManager.Stub {
Binder.restoreCallingIdentity(identity);
}
+ ArrayList<LocationRequest> requests = new ArrayList<>(records.size());
+
final boolean isForegroundOnlyMode =
mBatterySaverMode == PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
final boolean shouldThrottleRequests =
@@ -1772,7 +1689,7 @@ public class LocationManagerService extends ILocationManager.Stub {
== PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF
&& !mPowerManager.isInteractive();
// initialize the low power mode to true and set to false if any of the records requires
- providerRequest.lowPowerMode = true;
+ providerRequest.setLowPowerMode(true);
for (UpdateRecord record : records) {
if (!isCurrentProfileLocked(
UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
@@ -1787,10 +1704,10 @@ public class LocationManagerService extends ILocationManager.Stub {
}
final boolean isBatterySaverDisablingLocation = shouldThrottleRequests
|| (isForegroundOnlyMode && !record.mIsForegroundUid);
- if (!provider.isUseableLocked() || isBatterySaverDisablingLocation) {
+ if (!manager.isUseable() || isBatterySaverDisablingLocation) {
if (isSettingsExemptLocked(record)) {
- providerRequest.locationSettingsIgnored = true;
- providerRequest.lowPowerMode = false;
+ providerRequest.setLocationSettingsIgnored(true);
+ providerRequest.setLowPowerMode(false);
} else {
continue;
}
@@ -1801,7 +1718,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// if we're forcing location, don't apply any throttling
- if (!providerRequest.locationSettingsIgnored && !isThrottlingExemptLocked(
+ if (!providerRequest.isLocationSettingsIgnored() && !isThrottlingExemptLocked(
record.mReceiver.mCallerIdentity)) {
if (!record.mIsForegroundUid) {
interval = Math.max(interval, backgroundThrottleInterval);
@@ -1813,23 +1730,25 @@ public class LocationManagerService extends ILocationManager.Stub {
}
record.mRequest = locationRequest;
- providerRequest.locationRequests.add(locationRequest);
+ requests.add(locationRequest);
if (!locationRequest.isLowPowerMode()) {
- providerRequest.lowPowerMode = false;
+ providerRequest.setLowPowerMode(false);
}
- if (interval < providerRequest.interval) {
- providerRequest.reportLocation = true;
- providerRequest.interval = interval;
+ if (interval < providerRequest.getInterval()) {
+ providerRequest.setInterval(interval);
}
}
- if (providerRequest.reportLocation) {
+ providerRequest.setLocationRequests(requests);
+
+ if (providerRequest.getInterval() < Long.MAX_VALUE) {
// calculate who to blame for power
// This is somewhat arbitrary. We pick a threshold interval
// that is slightly higher that the minimum interval, and
// spread the blame across all applications with a request
// under that threshold.
- long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
+ // TODO: overflow
+ long thresholdInterval = (providerRequest.getInterval() + 1000) * 3 / 2;
for (UpdateRecord record : records) {
if (isCurrentProfileLocked(
UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
@@ -1837,18 +1756,18 @@ public class LocationManagerService extends ILocationManager.Stub {
// Don't assign battery blame for update records whose
// client has no permission to receive location data.
- if (!providerRequest.locationRequests.contains(locationRequest)) {
+ if (!providerRequest.getLocationRequests().contains(locationRequest)) {
continue;
}
if (locationRequest.getInterval() <= thresholdInterval) {
if (record.mReceiver.mWorkSource != null
&& isValidWorkSource(record.mReceiver.mWorkSource)) {
- worksource.add(record.mReceiver.mWorkSource);
+ providerRequest.getWorkSource().add(record.mReceiver.mWorkSource);
} else {
// Assign blame to caller if there's no WorkSource associated with
// the request or if it's invalid.
- worksource.add(
+ providerRequest.getWorkSource().add(
record.mReceiver.mCallerIdentity.mUid,
record.mReceiver.mCallerIdentity.mPackageName);
}
@@ -1858,7 +1777,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- provider.setRequest(providerRequest, worksource);
+ manager.setRequest(providerRequest.build());
}
/**
@@ -2198,8 +2117,8 @@ public class LocationManagerService extends ILocationManager.Stub {
throw new IllegalArgumentException("provider name must not be null");
}
- LocationProviderManager provider = getLocationProviderLocked(name);
- if (provider == null) {
+ LocationProviderManager manager = getLocationProviderManager(name);
+ if (manager == null) {
throw new IllegalArgumentException("provider doesn't exist: " + name);
}
@@ -2217,7 +2136,7 @@ public class LocationManagerService extends ILocationManager.Stub {
oldRecord.disposeLocked(false);
}
- if (!provider.isUseableLocked() && !isSettingsExemptLocked(record)) {
+ if (!manager.isUseable() && !isSettingsExemptLocked(record)) {
// Notify the listener that updates are currently disabled - but only if the request
// does not ignore location settings
receiver.callProviderEnabledLocked(name, false);
@@ -2320,8 +2239,8 @@ public class LocationManagerService extends ILocationManager.Stub {
// or use the fused provider
String name = request.getProvider();
if (name == null) name = LocationManager.FUSED_PROVIDER;
- LocationProviderManager provider = getLocationProviderLocked(name);
- if (provider == null) return null;
+ LocationProviderManager manager = getLocationProviderManager(name);
+ if (manager == null) return null;
// only the current user or location providers may get location this way
if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isProviderPackage(
@@ -2329,7 +2248,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
- if (!provider.isUseableLocked()) {
+ if (!manager.isUseable()) {
return null;
}
@@ -2450,19 +2369,19 @@ public class LocationManagerService extends ILocationManager.Stub {
"Access Fine Location permission not granted to inject Location");
synchronized (mLock) {
- LocationProviderManager provider = getLocationProviderLocked(location.getProvider());
- if (provider == null || !provider.isUseableLocked()) {
+ LocationProviderManager manager = getLocationProviderManager(location.getProvider());
+ if (manager == null || !manager.isUseable()) {
return false;
}
// NOTE: If last location is already available, location is not injected. If
// provider's normal source (like a GPS chipset) have already provided an output
// there is no need to inject this location.
- if (mLastLocation.get(provider.getName()) != null) {
+ if (mLastLocation.get(manager.getName()) != null) {
return false;
}
- updateLastLocationLocked(location, provider.getName());
+ updateLastLocationLocked(location, manager.getName());
return true;
}
}
@@ -2511,7 +2430,7 @@ public class LocationManagerService extends ILocationManager.Stub {
packageName,
request,
/* hasListener= */ false,
- intent != null,
+ true,
geofence,
mActivityManager.getPackageImportance(packageName));
}
@@ -2542,7 +2461,7 @@ public class LocationManagerService extends ILocationManager.Stub {
packageName,
/* LocationRequest= */ null,
/* hasListener= */ false,
- intent != null,
+ true,
geofence,
mActivityManager.getPackageImportance(packageName));
}
@@ -2555,7 +2474,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName,
String featureId) {
- return mGnssManagerService == null ? false : mGnssManagerService.registerGnssStatusCallback(
+ return mGnssManagerService != null && mGnssManagerService.registerGnssStatusCallback(
listener, packageName, featureId);
}
@@ -2569,9 +2488,8 @@ public class LocationManagerService extends ILocationManager.Stub {
String packageName, String featureId, String listenerIdentifier) {
Objects.requireNonNull(listenerIdentifier);
- return mGnssManagerService == null ? false
- : mGnssManagerService.addGnssMeasurementsListener(listener, packageName, featureId,
- listenerIdentifier);
+ return mGnssManagerService != null && mGnssManagerService.addGnssMeasurementsListener(
+ listener, packageName, featureId, listenerIdentifier);
}
@Override
@@ -2586,8 +2504,8 @@ public class LocationManagerService extends ILocationManager.Stub {
public void injectGnssMeasurementCorrections(
GnssMeasurementCorrections measurementCorrections, String packageName) {
if (mGnssManagerService != null) {
- mGnssManagerService.injectGnssMeasurementCorrections(
- measurementCorrections, packageName);
+ mGnssManagerService.injectGnssMeasurementCorrections(measurementCorrections,
+ packageName);
}
}
@@ -2602,9 +2520,8 @@ public class LocationManagerService extends ILocationManager.Stub {
String packageName, String featureId, String listenerIdentifier) {
Objects.requireNonNull(listenerIdentifier);
- return mGnssManagerService == null ? false
- : mGnssManagerService.addGnssNavigationMessageListener(listener, packageName,
- featureId, listenerIdentifier);
+ return mGnssManagerService != null && mGnssManagerService.addGnssNavigationMessageListener(
+ listener, packageName, featureId, listenerIdentifier);
}
@Override
@@ -2634,9 +2551,10 @@ public class LocationManagerService extends ILocationManager.Stub {
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
providerName);
- LocationProviderManager provider = getLocationProviderLocked(providerName);
- if (provider != null) {
- provider.sendExtraCommand(command, extras);
+ LocationProviderManager manager = getLocationProviderManager(providerName);
+ if (manager != null) {
+ manager.sendExtraCommand(Binder.getCallingUid(), Binder.getCallingPid(), command,
+ extras);
}
mLocationUsageLogger.logLocationApiUsage(
@@ -2650,43 +2568,37 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean sendNiResponse(int notifId, int userResponse) {
- return mGnssManagerService == null ? false : mGnssManagerService.sendNiResponse(notifId,
+ return mGnssManagerService != null && mGnssManagerService.sendNiResponse(notifId,
userResponse);
}
@Override
public ProviderProperties getProviderProperties(String providerName) {
- synchronized (mLock) {
- LocationProviderManager provider = getLocationProviderLocked(providerName);
- if (provider == null) {
- return null;
- }
- return provider.getPropertiesLocked();
+ LocationProviderManager manager = getLocationProviderManager(providerName);
+ if (manager == null) {
+ return null;
}
+ return manager.getProperties();
}
@Override
public boolean isProviderPackage(String packageName) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
Manifest.permission.READ_DEVICE_CONFIG + " permission required");
- synchronized (mLock) {
- for (LocationProviderManager provider : mProviders) {
- if (provider.getPackagesLocked().contains(packageName)) {
- return true;
- }
+ for (LocationProviderManager manager : mProviderManagers) {
+ if (manager.getPackages().contains(packageName)) {
+ return true;
}
- return false;
}
+ return false;
}
@Override
public List<String> getProviderPackages(String providerName) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
Manifest.permission.READ_DEVICE_CONFIG + " permission required");
- synchronized (mLock) {
- LocationProviderManager provider = getLocationProviderLocked(providerName);
- return provider == null ? Collections.emptyList() : provider.getPackagesLocked();
- }
+ LocationProviderManager manager = getLocationProviderManager(providerName);
+ return manager == null ? Collections.emptyList() : new ArrayList<>(manager.getPackages());
}
@Override
@@ -2753,8 +2665,8 @@ public class LocationManagerService extends ILocationManager.Stub {
if (FUSED_PROVIDER.equals(providerName)) return false;
synchronized (mLock) {
- LocationProviderManager provider = getLocationProviderLocked(providerName);
- return provider != null && provider.isUseableLocked(userId);
+ LocationProviderManager manager = getLocationProviderManager(providerName);
+ return manager != null && manager.isUseable(userId);
}
}
@@ -2792,37 +2704,39 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@GuardedBy("mLock")
- private void handleLocationChangedLocked(Location location, LocationProviderManager provider) {
- if (!mProviders.contains(provider)) {
+ private void handleLocationChangedLocked(Location location, LocationProviderManager manager) {
+ if (!mProviderManagers.contains(manager)) {
+ Log.w(TAG, "received location from unknown provider: " + manager.getName());
return;
}
if (!location.isComplete()) {
- Log.w(TAG, "Dropping incomplete location: " + location);
+ Log.w(TAG, "dropping incomplete location from " + manager.getName() + " provider: "
+ + location);
return;
}
- // only notify passive provider and update last location for locations that come from
- // useable providers
- if (provider.isUseableLocked()) {
- if (!provider.isPassiveLocked()) {
- mPassiveProvider.updateLocation(location);
- }
+ // notify passive provider
+ if (manager != mPassiveManager) {
+ mPassiveManager.updateLocation(new Location(location));
}
if (D) Log.d(TAG, "incoming location: " + location);
long now = SystemClock.elapsedRealtime();
- if (provider.isUseableLocked()) {
- updateLastLocationLocked(location, provider.getName());
+
+
+ // only update last location for locations that come from useable providers
+ if (manager.isUseable()) {
+ updateLastLocationLocked(location, manager.getName());
}
// Update last known coarse interval location if enough time has passed.
Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(
- provider.getName());
+ manager.getName());
if (lastLocationCoarseInterval == null) {
lastLocationCoarseInterval = new Location(location);
- if (provider.isUseableLocked()) {
- mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
+ if (manager.isUseable()) {
+ mLastLocationCoarseInterval.put(manager.getName(), lastLocationCoarseInterval);
}
}
long timeDeltaMs = TimeUnit.NANOSECONDS.toMillis(location.getElapsedRealtimeNanos()
@@ -2837,7 +2751,7 @@ public class LocationManagerService extends ILocationManager.Stub {
lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
// Skip if there are no UpdateRecords for this provider.
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
if (records == null || records.size() == 0) return;
// Fetch coarse location
@@ -2854,7 +2768,7 @@ public class LocationManagerService extends ILocationManager.Stub {
Receiver receiver = r.mReceiver;
boolean receiverDead = false;
- if (!provider.isUseableLocked() && !isSettingsExemptLocked(r)) {
+ if (!manager.isUseable() && !isSettingsExemptLocked(r)) {
continue;
}
@@ -2949,7 +2863,7 @@ public class LocationManagerService extends ILocationManager.Stub {
for (UpdateRecord r : deadUpdateRecords) {
r.disposeLocked(true);
}
- applyRequirementsLocked(provider);
+ applyRequirementsLocked(manager);
}
}
@@ -3006,143 +2920,99 @@ public class LocationManagerService extends ILocationManager.Stub {
// Mock Providers
- private boolean canCallerAccessMockLocation(String opPackageName) {
- return mAppOps.checkOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
- opPackageName) == AppOpsManager.MODE_ALLOWED;
- }
-
@Override
- public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
- if (!canCallerAccessMockLocation(opPackageName)) {
+ public void addTestProvider(String provider, ProviderProperties properties,
+ String packageName) {
+ if (mAppOps.checkOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(), packageName)
+ != AppOpsManager.MODE_ALLOWED) {
return;
}
- if (PASSIVE_PROVIDER.equals(name)) {
- throw new IllegalArgumentException("Cannot mock the passive location provider");
- }
-
synchronized (mLock) {
- long identity = Binder.clearCallingIdentity();
- try {
- LocationProviderManager oldProvider = getLocationProviderLocked(name);
- if (oldProvider != null) {
- removeProviderLocked(oldProvider);
- }
-
- MockLocationProvider mockProviderManager = new MockLocationProvider(name);
- addProviderLocked(mockProviderManager);
- mockProviderManager.attachLocked(
- new MockProvider(mContext, mockProviderManager, properties));
- } finally {
- Binder.restoreCallingIdentity(identity);
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ if (manager == null) {
+ manager = new LocationProviderManager(provider);
+ mProviderManagers.add(manager);
}
+
+ manager.setMockProvider(new MockProvider(mContext, properties));
}
}
@Override
- public void removeTestProvider(String name, String opPackageName) {
- if (!canCallerAccessMockLocation(opPackageName)) {
+ public void removeTestProvider(String provider, String packageName) {
+ if (mAppOps.checkOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(), packageName)
+ != AppOpsManager.MODE_ALLOWED) {
return;
}
synchronized (mLock) {
- long identity = Binder.clearCallingIdentity();
- try {
- LocationProviderManager testProvider = getLocationProviderLocked(name);
- if (testProvider == null || !testProvider.isMock()) {
- return;
- }
-
- removeProviderLocked(testProvider);
-
- // reinstate real provider if available
- LocationProviderManager realProvider = null;
- for (LocationProviderManager provider : mRealProviders) {
- if (name.equals(provider.getName())) {
- realProvider = provider;
- break;
- }
- }
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ if (manager == null) {
+ return;
+ }
- if (realProvider != null) {
- addProviderLocked(realProvider);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
+ manager.setMockProvider(null);
+ if (!manager.hasProvider()) {
+ mProviderManagers.remove(manager);
+ mLastLocation.remove(manager.getName());
+ mLastLocationCoarseInterval.remove(manager.getName());
}
}
}
@Override
- public void setTestProviderLocation(String providerName, Location location,
- String opPackageName) {
- if (!canCallerAccessMockLocation(opPackageName)) {
+ public void setTestProviderLocation(String provider, Location location, String packageName) {
+ if (mAppOps.checkOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(), packageName)
+ != AppOpsManager.MODE_ALLOWED) {
return;
}
- synchronized (mLock) {
- LocationProviderManager testProvider = getLocationProviderLocked(providerName);
- if (testProvider == null || !testProvider.isMock()) {
- throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
- }
-
- String locationProvider = location.getProvider();
- if (!TextUtils.isEmpty(locationProvider) && !providerName.equals(locationProvider)) {
- // The location has an explicit provider that is different from the mock
- // provider name. The caller may be trying to fool us via b/33091107.
- EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
- providerName + "!=" + location.getProvider());
- }
-
- ((MockLocationProvider) testProvider).setLocationLocked(location);
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ if (manager == null) {
+ throw new IllegalArgumentException("provider doesn't exist: " + provider);
}
+
+ manager.setMockProviderLocation(location);
}
@Override
- public void setTestProviderEnabled(String providerName, boolean enabled, String opPackageName) {
- if (!canCallerAccessMockLocation(opPackageName)) {
+ public void setTestProviderEnabled(String provider, boolean enabled, String packageName) {
+ if (mAppOps.checkOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(), packageName)
+ != AppOpsManager.MODE_ALLOWED) {
return;
}
- synchronized (mLock) {
- LocationProviderManager testProvider = getLocationProviderLocked(providerName);
- if (testProvider == null || !testProvider.isMock()) {
- throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
- }
-
- ((MockLocationProvider) testProvider).setEnabledLocked(enabled);
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ if (manager == null) {
+ throw new IllegalArgumentException("provider doesn't exist: " + provider);
}
+
+ manager.setMockProviderEnabled(enabled);
}
@Override
@NonNull
- public List<LocationRequest> getTestProviderCurrentRequests(String providerName,
- String opPackageName) {
- if (!canCallerAccessMockLocation(opPackageName)) {
+ public List<LocationRequest> getTestProviderCurrentRequests(String provider,
+ String packageName) {
+ if (mAppOps.checkOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(), packageName)
+ != AppOpsManager.MODE_ALLOWED) {
return Collections.emptyList();
}
- synchronized (mLock) {
- LocationProviderManager testProvider = getLocationProviderLocked(providerName);
- if (testProvider == null || !testProvider.isMock()) {
- throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
- }
-
- MockLocationProvider provider = (MockLocationProvider) testProvider;
- if (provider.mCurrentRequest == null) {
- return Collections.emptyList();
- }
- List<LocationRequest> requests = new ArrayList<>();
- for (LocationRequest request : provider.mCurrentRequest.locationRequests) {
- requests.add(new LocationRequest(request));
- }
- return requests;
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ if (manager == null) {
+ throw new IllegalArgumentException("provider doesn't exist: " + provider);
}
+
+ return manager.getMockProviderRequests();
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) {
+ return;
+ }
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
@@ -3192,6 +3062,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
ipw.decreaseIndent();
+ mRequestStatistics.history.dump(ipw);
+
ipw.println("Last Known Locations:");
ipw.increaseIndent();
for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
@@ -3224,25 +3096,27 @@ public class LocationManagerService extends ILocationManager.Stub {
mLocationFudger.dump(fd, ipw, args);
ipw.decreaseIndent();
}
+ }
- ipw.println("Location Settings:");
- ipw.increaseIndent();
- mSettingsStore.dump(fd, ipw, args);
- ipw.decreaseIndent();
+ ipw.println("Location Settings:");
+ ipw.increaseIndent();
+ mSettingsStore.dump(fd, ipw, args);
+ ipw.decreaseIndent();
- ipw.println("Location Providers:");
- ipw.increaseIndent();
- for (LocationProviderManager provider : mProviders) {
- provider.dumpLocked(fd, ipw, args);
- }
- ipw.decreaseIndent();
+ ipw.println("Location Providers:");
+ ipw.increaseIndent();
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.dump(fd, ipw, args);
}
+ ipw.decreaseIndent();
- if (mGnssManagerService != null) {
- ipw.println("GNSS:");
- ipw.increaseIndent();
- mGnssManagerService.dump(fd, ipw, args);
- ipw.decreaseIndent();
+ synchronized (mLock) {
+ if (mGnssManagerService != null) {
+ ipw.println("GNSS:");
+ ipw.increaseIndent();
+ mGnssManagerService.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1f736502ae42..05d83606b2d0 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -58,10 +58,12 @@ import android.net.NetworkStack;
import android.net.NetworkStats;
import android.net.NetworkUtils;
import android.net.RouteInfo;
-import android.net.TetherConfigParcel;
import android.net.TetherStatsParcel;
import android.net.UidRange;
import android.net.UidRangeParcel;
+import android.net.shared.NetdUtils;
+import android.net.shared.RouteUtils;
+import android.net.shared.RouteUtils.ModifyOperation;
import android.net.util.NetdService;
import android.os.BatteryStats;
import android.os.Binder;
@@ -898,48 +900,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@Override
public void addRoute(int netId, RouteInfo route) {
- modifyRoute(MODIFY_OPERATION_ADD, netId, route);
+ NetworkStack.checkNetworkStackPermission(mContext);
+ RouteUtils.modifyRoute(mNetdService, ModifyOperation.ADD, netId, route);
}
@Override
public void removeRoute(int netId, RouteInfo route) {
- modifyRoute(MODIFY_OPERATION_REMOVE, netId, route);
- }
-
- private void modifyRoute(boolean add, int netId, RouteInfo route) {
NetworkStack.checkNetworkStackPermission(mContext);
-
- final String ifName = route.getInterface();
- final String dst = route.getDestination().toString();
- final String nextHop;
-
- switch (route.getType()) {
- case RouteInfo.RTN_UNICAST:
- if (route.hasGateway()) {
- nextHop = route.getGateway().getHostAddress();
- } else {
- nextHop = INetd.NEXTHOP_NONE;
- }
- break;
- case RouteInfo.RTN_UNREACHABLE:
- nextHop = INetd.NEXTHOP_UNREACHABLE;
- break;
- case RouteInfo.RTN_THROW:
- nextHop = INetd.NEXTHOP_THROW;
- break;
- default:
- nextHop = INetd.NEXTHOP_NONE;
- break;
- }
- try {
- if (add) {
- mNetdService.networkAddRoute(netId, ifName, dst, nextHop);
- } else {
- mNetdService.networkRemoveRoute(netId, ifName, dst, nextHop);
- }
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
+ RouteUtils.modifyRoute(mNetdService, ModifyOperation.REMOVE, netId, route);
}
private ArrayList<String> readRouteList(String filename) {
@@ -1023,12 +991,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@Override
public void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, String[] dhcpRange) {
NetworkStack.checkNetworkStackPermission(mContext);
- // an odd number of addrs will fail
try {
- final TetherConfigParcel config = new TetherConfigParcel();
- config.usingLegacyDnsProxy = usingLegacyDnsProxy;
- config.dhcpRanges = dhcpRange;
- mNetdService.tetherStartWithConfiguration(config);
+ NetdUtils.tetherStart(mNetdService, usingLegacyDnsProxy, dhcpRange);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
@@ -1060,26 +1024,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
public void tetherInterface(String iface) {
NetworkStack.checkNetworkStackPermission(mContext);
try {
- mNetdService.tetherInterfaceAdd(iface);
+ final LinkAddress addr = getInterfaceConfig(iface).getLinkAddress();
+ final IpPrefix dest = new IpPrefix(addr.getAddress(), addr.getPrefixLength());
+ NetdUtils.tetherInterface(mNetdService, iface, dest);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
- List<RouteInfo> routes = new ArrayList<>();
- // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it
- // suitable to use as a route destination.
- routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface));
- addInterfaceToLocalNetwork(iface, routes);
}
@Override
public void untetherInterface(String iface) {
NetworkStack.checkNetworkStackPermission(mContext);
try {
- mNetdService.tetherInterfaceRemove(iface);
+ NetdUtils.untetherInterface(mNetdService, iface);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
- } finally {
- removeInterfaceFromLocalNetwork(iface);
}
}
@@ -2122,16 +2081,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@Override
public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, iface);
-
- for (RouteInfo route : routes) {
- if (!route.isDefaultRoute()) {
- modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, route);
- }
- }
-
- // IPv6 link local should be activated always.
- modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID,
- new RouteInfo(new IpPrefix("fe80::/64"), null, iface));
+ // modifyInterfaceInNetwork already check calling permission.
+ RouteUtils.addRoutesToLocalNetwork(mNetdService, iface, routes);
}
@Override
@@ -2141,17 +2092,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@Override
public int removeRoutesFromLocalNetwork(List<RouteInfo> routes) {
- int failures = 0;
-
- for (RouteInfo route : routes) {
- try {
- modifyRoute(MODIFY_OPERATION_REMOVE, INetd.LOCAL_NET_ID, route);
- } catch (IllegalStateException e) {
- failures++;
- }
- }
-
- return failures;
+ NetworkStack.checkNetworkStackPermission(mContext);
+ return RouteUtils.removeRoutesFromLocalNetwork(mNetdService, routes);
}
@Override
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
index cfe56052118f..d20936c2d217 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
@@ -36,11 +36,11 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.TimestampedValue;
import android.provider.Settings;
import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.TimeUtils;
-import android.util.TimestampedValue;
import com.android.internal.util.DumpUtils;
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index deff440aa0a6..7b4fd37f01c9 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -199,13 +199,14 @@ public class PackageWatchdog {
mSystemClock = clock;
mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS;
loadFromFile();
+ sPackageWatchdog = this;
}
/** Creates or gets singleton instance of PackageWatchdog. */
public static PackageWatchdog getInstance(Context context) {
synchronized (PackageWatchdog.class) {
if (sPackageWatchdog == null) {
- sPackageWatchdog = new PackageWatchdog(context);
+ new PackageWatchdog(context);
}
return sPackageWatchdog;
}
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index fb1a962c0ef3..3dafc64391fd 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -18,8 +18,12 @@ package com.android.server;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
@@ -36,8 +40,12 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.StatsLog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.server.PackageWatchdog.FailureReasons;
+import com.android.server.PackageWatchdog.PackageHealthObserver;
+import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
import com.android.server.am.SettingsToPropertiesMapper;
import com.android.server.utils.FlagNamespaceUtils;
@@ -79,19 +87,30 @@ public class RescueParty {
@VisibleForTesting
static final long BOOT_TRIGGER_WINDOW_MILLIS = 600 * DateUtils.SECOND_IN_MILLIS;
@VisibleForTesting
- static final long PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS = 30 * DateUtils.SECOND_IN_MILLIS;
- @VisibleForTesting
static final String TAG = "RescueParty";
+ private static final String NAME = "rescue-party-observer";
+
+
private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
private static final String PROP_RESCUE_BOOT_START = "sys.rescue_boot_start";
private static final String PROP_VIRTUAL_DEVICE = "ro.hardware.virtual_device";
+ private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
+ | ApplicationInfo.FLAG_SYSTEM;
+
+
/** Threshold for boot loops */
private static final Threshold sBoot = new BootThreshold();
/** Threshold for app crash loops */
private static SparseArray<Threshold> sApps = new SparseArray<>();
+ /** Register the Rescue Party observer as a Package Watchdog health observer */
+ public static void registerHealthObserver(Context context) {
+ PackageWatchdog.getInstance(context).registerHealthObserver(
+ RescuePartyObserver.getInstance(context));
+ }
+
private static boolean isDisabled() {
// Check if we're explicitly enabled for testing
if (SystemProperties.getBoolean(PROP_ENABLE_RESCUE, false)) {
@@ -135,24 +154,6 @@ public class RescueParty {
}
/**
- * Take note of a persistent app or apex module crash. If we notice too many of these
- * events happening in rapid succession, we'll send out a rescue party.
- */
- public static void noteAppCrash(Context context, int uid) {
- if (isDisabled()) return;
- Threshold t = sApps.get(uid);
- if (t == null) {
- t = new AppThreshold(uid);
- sApps.put(uid, t);
- }
- if (t.incrementAndTest()) {
- t.reset();
- incrementRescueLevel(t.uid);
- executeRescueLevel(context);
- }
- }
-
- /**
* Check if we're currently attempting to reboot for a factory reset.
*/
public static boolean isAttemptingFactoryReset() {
@@ -171,11 +172,6 @@ public class RescueParty {
@VisibleForTesting
static void resetAllThresholds() {
sBoot.reset();
-
- for (int i = 0; i < sApps.size(); i++) {
- Threshold appThreshold = sApps.get(sApps.keyAt(i));
- appThreshold.reset();
- }
}
@VisibleForTesting
@@ -243,6 +239,28 @@ public class RescueParty {
FlagNamespaceUtils.NAMESPACE_NO_PACKAGE);
}
+ private static int mapRescueLevelToUserImpact(int rescueLevel) {
+ switch(rescueLevel) {
+ case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+ case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ return PackageHealthObserverImpact.USER_IMPACT_LOW;
+ case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ case LEVEL_FACTORY_RESET:
+ return PackageHealthObserverImpact.USER_IMPACT_HIGH;
+ default:
+ return PackageHealthObserverImpact.USER_IMPACT_NONE;
+ }
+ }
+
+ private static int getPackageUid(Context context, String packageName) {
+ try {
+ return context.getPackageManager().getPackageUid(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Since UIDs are always >= 0, this value means the UID could not be determined.
+ return -1;
+ }
+ }
+
private static void resetAllSettings(Context context, int mode) throws Exception {
// Try our best to reset all settings possible, and once finished
// rethrow any exception that we encountered
@@ -271,6 +289,89 @@ public class RescueParty {
}
/**
+ * Handle mitigation action for package failures. This observer will be register to Package
+ * Watchdog and will receive calls about package failures. This observer is persistent so it
+ * may choose to mitigate failures for packages it has not explicitly asked to observe.
+ */
+ public static class RescuePartyObserver implements PackageHealthObserver {
+
+ private Context mContext;
+
+ @GuardedBy("RescuePartyObserver.class")
+ static RescuePartyObserver sRescuePartyObserver;
+
+ private RescuePartyObserver(Context context) {
+ mContext = context;
+ }
+
+ /** Creates or gets singleton instance of RescueParty. */
+ public static RescuePartyObserver getInstance(Context context) {
+ synchronized (RescuePartyObserver.class) {
+ if (sRescuePartyObserver == null) {
+ sRescuePartyObserver = new RescuePartyObserver(context);
+ }
+ return sRescuePartyObserver;
+ }
+ }
+
+ @Override
+ public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
+ @FailureReasons int failureReason) {
+ if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
+ || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
+ int rescueLevel = MathUtils.constrain(
+ SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1,
+ LEVEL_NONE, LEVEL_FACTORY_RESET);
+ return mapRescueLevelToUserImpact(rescueLevel);
+ } else {
+ return PackageHealthObserverImpact.USER_IMPACT_NONE;
+ }
+ }
+
+ @Override
+ public boolean execute(@Nullable VersionedPackage failedPackage,
+ @FailureReasons int failureReason) {
+ if (isDisabled()) {
+ return false;
+ }
+ if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
+ || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
+ int triggerUid = getPackageUid(mContext, failedPackage.getPackageName());
+ incrementRescueLevel(triggerUid);
+ executeRescueLevel(mContext);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return true;
+ }
+
+ @Override
+ public boolean mayObservePackage(String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ // A package is a Mainline module if this is non-null
+ if (pm.getModuleInfo(packageName, 0) != null) {
+ return true;
+ }
+ ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
+ return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+ }
+
+ /**
* Threshold that can be triggered if a number of events occur within a
* window of time.
*/
@@ -349,27 +450,6 @@ public class RescueParty {
}
}
- /**
- * Specialization of {@link Threshold} for monitoring app crashes. It stores
- * counters in memory.
- */
- private static class AppThreshold extends Threshold {
- private int count;
- private long start;
-
- public AppThreshold(int uid) {
- // We're interested in TRIGGER_COUNT events in any
- // PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS second period; apps crash pretty quickly
- // so we can keep a tight leash on them.
- super(uid, TRIGGER_COUNT, PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS);
- }
-
- @Override public int getCount() { return count; }
- @Override public void setCount(int count) { this.count = count; }
- @Override public long getStart() { return start; }
- @Override public void setStart(long start) { this.start = start; }
- }
-
private static int[] getAllUserIds() {
int[] userIds = { UserHandle.USER_SYSTEM };
try {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3d455ee1cf19..db542145a750 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.Manifest.permission.ACCESS_MTP;
import static android.Manifest.permission.INSTALL_PACKAGES;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
@@ -111,6 +112,7 @@ import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.provider.DeviceConfig;
+import android.provider.Downloads;
import android.provider.MediaStore;
import android.provider.Settings;
import android.sysprop.VoldProperties;
@@ -367,6 +369,8 @@ class StorageManagerService extends IStorageManager.Stub
private volatile int mMediaStoreAuthorityAppId = -1;
+ private volatile int mDownloadsAuthorityAppId = -1;
+
private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
private final Installer mInstaller;
@@ -1788,6 +1792,15 @@ class StorageManagerService extends IStorageManager.Stub
mMediaStoreAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}
+ provider = mPmInternal.resolveContentProvider(
+ Downloads.Impl.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ UserHandle.getUserId(UserHandle.USER_SYSTEM));
+
+ if (provider != null) {
+ mDownloadsAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
+ }
+
try {
mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback);
mIAppOpsService.startWatchingMode(OP_LEGACY_STORAGE, null, mAppOpsCallback);
@@ -3881,6 +3894,19 @@ class StorageManagerService extends IStorageManager.Stub
return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
}
+ if (mIsFuseEnabled && mDownloadsAuthorityAppId == UserHandle.getAppId(uid)) {
+ // DownloadManager can write in app-private directories on behalf of apps;
+ // give it write access to Android/
+ return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE;
+ }
+
+ final boolean hasMtp = mIPackageManager.checkUidPermission(ACCESS_MTP, uid) ==
+ PERMISSION_GRANTED;
+ if (mIsFuseEnabled && hasMtp) {
+ // The process hosting the MTP server should be able to write in Android/
+ return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE;
+ }
+
// Determine if caller is holding runtime permission
final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 2091c2a0c694..9ffe89c61a44 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1059,8 +1059,8 @@ final class UiModeManagerService extends SystemService {
if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
try {
int result = ActivityTaskManager.getService().startActivityWithConfig(
- null, null, homeIntent, null, null, null, 0, 0,
- mConfiguration, null, UserHandle.USER_CURRENT);
+ null, getContext().getBasePackageName(), homeIntent, null, null, null,
+ 0, 0, mConfiguration, null, UserHandle.USER_CURRENT);
if (ActivityManager.isStartResultSuccessful(result)) {
dockAppStarted = true;
} else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 454941ccdb03..a60b09fda2e8 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -39,8 +39,10 @@ import android.system.StructRlimit;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.StatsLog;
+import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.ZygoteConnectionConstants;
import com.android.server.am.ActivityManagerService;
import com.android.server.wm.SurfaceAnimationThread;
@@ -606,13 +608,18 @@ public class Watchdog extends Thread {
pids.add(Process.myPid());
if (mPhonePid > 0) pids.add(mPhonePid);
+ long anrTime = SystemClock.uptimeMillis();
+ ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(false);
final File stack = ActivityManagerService.dumpStackTraces(
- pids, null, null, getInterestingNativePids());
+ pids, processCpuTracker, new SparseArray<>(), getInterestingNativePids());
// Give some extra time to make sure the stack traces get written.
// The system's been hanging for a minute, another second or two won't hurt much.
SystemClock.sleep(5000);
+ processCpuTracker.update();
+ String cpuInfo = processCpuTracker.printCurrentState(anrTime);
+
// Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
doSysRq('w');
doSysRq('l');
@@ -627,7 +634,7 @@ public class Watchdog extends Thread {
if (mActivity != null) {
mActivity.addErrorToDropBox(
"watchdog", null, "system_server", null, null, null,
- subject, null, stack, null);
+ subject, cpuInfo, stack, null);
}
StatsLog.write(StatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject);
}
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 4b48ef917744..143474bd5c94 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -413,6 +413,11 @@ public class AdbDebuggingManager {
case MESSAGE_ADB_CLEAR: {
Slog.d(TAG, "Received a request to clear the adb authorizations");
mConnectedKeys.clear();
+ // If the key store has not yet been instantiated then do so now; this avoids
+ // the unnecessary creation of the key store when adb is not enabled.
+ if (mAdbKeyStore == null) {
+ mAdbKeyStore = new AdbKeyStore();
+ }
mAdbKeyStore.deleteKeyStore();
cancelJobToUpdateAdbKeyStore();
break;
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index a4c44fabfba6..d7ad1c252401 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2934,33 +2934,37 @@ final class ActivityManagerShellCommand extends ShellCommand {
}
ArraySet<Long> enabled = new ArraySet<>();
ArraySet<Long> disabled = new ArraySet<>();
- switch (toggleValue) {
- case "enable":
- enabled.add(changeId);
- pw.println("Enabled change " + changeId + " for " + packageName + ".");
- CompatibilityChangeConfig overrides =
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
- return 0;
- case "disable":
- disabled.add(changeId);
- pw.println("Disabled change " + changeId + " for " + packageName + ".");
- overrides =
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
- return 0;
- case "reset":
- if (platformCompat.clearOverride(changeId, packageName)) {
- pw.println("Reset change " + changeId + " for " + packageName
- + " to default value.");
- } else {
- pw.println("No override exists for changeId " + changeId + ".");
- }
- return 0;
- default:
- pw.println("Invalid toggle value: '" + toggleValue + "'.");
+ try {
+ switch (toggleValue) {
+ case "enable":
+ enabled.add(changeId);
+ CompatibilityChangeConfig overrides =
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled));
+ platformCompat.setOverrides(overrides, packageName);
+ pw.println("Enabled change " + changeId + " for " + packageName + ".");
+ return 0;
+ case "disable":
+ disabled.add(changeId);
+ overrides =
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled));
+ platformCompat.setOverrides(overrides, packageName);
+ pw.println("Disabled change " + changeId + " for " + packageName + ".");
+ return 0;
+ case "reset":
+ if (platformCompat.clearOverride(changeId, packageName)) {
+ pw.println("Reset change " + changeId + " for " + packageName
+ + " to default value.");
+ } else {
+ pw.println("No override exists for changeId " + changeId + ".");
+ }
+ return 0;
+ default:
+ pw.println("Invalid toggle value: '" + toggleValue + "'.");
+ }
+ } catch (SecurityException e) {
+ pw.println(e.getMessage());
}
return -1;
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 5e48dcf91676..8071f52037e6 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -33,8 +33,6 @@ import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ModuleInfo;
-import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.net.Uri;
import android.os.Binder;
@@ -56,7 +54,6 @@ import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.server.PackageWatchdog;
-import com.android.server.RescueParty;
import com.android.server.wm.WindowProcessController;
import java.io.FileDescriptor;
@@ -423,28 +420,6 @@ class AppErrors {
}
if (r != null) {
- boolean isApexModule = false;
- try {
- for (String androidPackage : r.getPackageList()) {
- ModuleInfo moduleInfo = mContext.getPackageManager().getModuleInfo(
- androidPackage, /*flags=*/ 0);
- if (moduleInfo != null) {
- isApexModule = true;
- break;
- }
- }
- } catch (IllegalStateException | PackageManager.NameNotFoundException e) {
- // Call to PackageManager#getModuleInfo() can result in NameNotFoundException or
- // IllegalStateException. In case they are thrown, there isn't much we can do
- // other than proceed with app crash handling.
- }
-
- if (r.isPersistent() || isApexModule) {
- // If a persistent app or apex module is stuck in a crash loop, the device isn't
- // very usable, so we want to consider sending out a rescue party.
- RescueParty.noteAppCrash(mContext, r.uid);
- }
-
mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(),
PackageWatchdog.FAILURE_REASON_APP_CRASH);
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index a1e1f29016c2..b9f2e76c6ecb 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -103,6 +103,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.MemInfoReader;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
import com.android.server.Watchdog;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.dex.DexManager;
@@ -357,6 +358,8 @@ public final class ProcessList {
private boolean mAppDataIsolationEnabled = false;
+ private ArrayList<String> mAppDataIsolationWhitelistedApps;
+
/**
* Temporary to avoid allocations. Protected by main lock.
*/
@@ -645,6 +648,9 @@ public final class ProcessList {
// want some apps enabled while some apps disabled
mAppDataIsolationEnabled =
SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
+ mAppDataIsolationWhitelistedApps = new ArrayList<>(
+ SystemConfig.getInstance().getAppDataIsolationWhitelistedApps());
+
if (sKillHandler == null) {
sKillThread = new ServiceThread(TAG + ":kill",
@@ -1555,20 +1561,27 @@ public final class ProcessList {
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
-
+ int numGids = 3;
+ if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER
+ || mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
+ numGids++;
+ }
/*
* Add shared application and profile GIDs so applications can share some
* resources like shared libraries and access user-wide resources
*/
if (ArrayUtils.isEmpty(permGids)) {
- gids = new int[3];
+ gids = new int[numGids];
} else {
- gids = new int[permGids.length + 3];
- System.arraycopy(permGids, 0, gids, 3, permGids.length);
+ gids = new int[permGids.length + numGids];
+ System.arraycopy(permGids, 0, gids, numGids, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
+ if (numGids > 3) {
+ gids[3] = Process.SDCARD_RW_GID;
+ }
// Replace any invalid GIDs
if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2];
@@ -1905,6 +1918,16 @@ public final class ProcessList {
result.put(packageName, Pair.create(volumeUuid, inode));
}
}
+ if (mAppDataIsolationWhitelistedApps != null) {
+ for (String packageName : mAppDataIsolationWhitelistedApps) {
+ String volumeUuid = pmInt.getPackage(packageName).getVolumeUuid();
+ long inode = pmInt.getCeDataInode(packageName, userId);
+ if (inode != 0) {
+ result.put(packageName, Pair.create(volumeUuid, inode));
+ }
+ }
+ }
+
return result;
}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index cf83dd630a29..f15d999e1006 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -17,8 +17,10 @@
package com.android.server.compat;
import android.compat.Compatibility.ChangeConfig;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Environment;
+import android.os.RemoteException;
import android.text.TextUtils;
import android.util.LongArray;
import android.util.LongSparseArray;
@@ -26,8 +28,11 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.IOverrideValidator;
+import com.android.internal.compat.OverrideAllowedState;
import com.android.server.compat.config.Change;
import com.android.server.compat.config.XmlParser;
@@ -54,22 +59,14 @@ final class CompatConfig {
private static final String TAG = "CompatConfig";
- private static final CompatConfig sInstance = new CompatConfig().initConfigFromLib(
- Environment.buildPath(
- Environment.getRootDirectory(), "etc", "compatconfig"));
-
@GuardedBy("mChanges")
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
- @VisibleForTesting
- CompatConfig() {
- }
+ private IOverrideValidator mOverrideValidator;
- /**
- * @return The static instance of this class to be used within the system server.
- */
- static CompatConfig get() {
- return sInstance;
+ @VisibleForTesting
+ CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
+ mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
}
/**
@@ -159,8 +156,12 @@ final class CompatConfig {
* @param enabled If the change should be enabled or disabled.
* @return {@code true} if the change existed before adding the override.
*/
- boolean addOverride(long changeId, String packageName, boolean enabled) {
+ boolean addOverride(long changeId, String packageName, boolean enabled)
+ throws RemoteException, SecurityException {
boolean alreadyKnown = true;
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+ allowedState.enforce(changeId, packageName);
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
if (c == null) {
@@ -186,6 +187,20 @@ final class CompatConfig {
}
/**
+ * Returns the minimum sdk version for which this change should be enabled (or 0 if it is not
+ * target sdk gated).
+ */
+ int minTargetSdkForChangeId(long changeId) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ return 0;
+ }
+ return c.getEnableAfterTargetSdk();
+ }
+ }
+
+ /**
* Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
* restores the default behaviour for the given change and app, once any app processes have been
* restarted.
@@ -194,34 +209,44 @@ final class CompatConfig {
* @param packageName The app package name that was overridden.
* @return {@code true} if an override existed;
*/
- boolean removeOverride(long changeId, String packageName) {
+ boolean removeOverride(long changeId, String packageName)
+ throws RemoteException, SecurityException {
boolean overrideExists = false;
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
- if (c != null) {
- overrideExists = true;
- c.removePackageOverride(packageName);
+ try {
+ if (c != null) {
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+ allowedState.enforce(changeId, packageName);
+ overrideExists = true;
+ c.removePackageOverride(packageName);
+ }
+ } catch (RemoteException e) {
+ // Should never occur, since validator is in the same process.
+ throw new RuntimeException("Unable to call override validator!", e);
}
}
return overrideExists;
}
/**
- * Overrides the enabled state for a given change and app. This method is intended to be used
- * *only* for debugging purposes.
+ * Overrides the enabled state for a given change and app.
*
* <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
*
* @param overrides list of overrides to default changes config.
* @param packageName app for which the overrides will be applied.
*/
- void addOverrides(CompatibilityChangeConfig overrides, String packageName) {
+ void addOverrides(CompatibilityChangeConfig overrides, String packageName)
+ throws RemoteException, SecurityException {
synchronized (mChanges) {
for (Long changeId : overrides.enabledChanges()) {
addOverride(changeId, packageName, true);
}
for (Long changeId : overrides.disabledChanges()) {
addOverride(changeId, packageName, false);
+
}
}
}
@@ -235,10 +260,22 @@ final class CompatConfig {
*
* @param packageName The package for which the overrides should be purged.
*/
- void removePackageOverrides(String packageName) {
+ void removePackageOverrides(String packageName) throws RemoteException, SecurityException {
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
- mChanges.valueAt(i).removePackageOverride(packageName);
+ try {
+ CompatChange change = mChanges.valueAt(i);
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(change.getId(),
+ packageName);
+ allowedState.enforce(change.getId(), packageName);
+ if (change != null) {
+ mChanges.valueAt(i).removePackageOverride(packageName);
+ }
+ } catch (RemoteException e) {
+ // Should never occur, since validator is in the same process.
+ throw new RuntimeException("Unable to call override validator!", e);
+ }
}
}
}
@@ -326,17 +363,23 @@ final class CompatConfig {
}
}
- CompatConfig initConfigFromLib(File libraryDir) {
+ static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
+ CompatConfig config = new CompatConfig(androidBuildClassifier, context);
+ config.initConfigFromLib(Environment.buildPath(
+ Environment.getRootDirectory(), "etc", "compatconfig"));
+ return config;
+ }
+
+ void initConfigFromLib(File libraryDir) {
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
Slog.e(TAG, "No directory " + libraryDir + ", skipping");
- return this;
+ return;
}
for (File f : libraryDir.listFiles()) {
Slog.d(TAG, "Found a config file: " + f.getPath());
//TODO(b/138222363): Handle duplicate ids across config files.
readConfig(f);
}
- return this;
}
private void readConfig(File configFile) {
@@ -350,4 +393,7 @@ final class CompatConfig {
}
}
+ IOverrideValidator getOverrideValidator() {
+ return mOverrideValidator;
+ }
}
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
new file mode 100644
index 000000000000..dfc00806992b
--- /dev/null
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -0,0 +1,94 @@
+/*
+ * 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 com.android.server.compat;
+
+import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+import static com.android.internal.compat.OverrideAllowedState.PACKAGE_DOES_NOT_EXIST;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.AndroidBuildClassifier;
+import com.android.internal.compat.IOverrideValidator;
+import com.android.internal.compat.OverrideAllowedState;
+
+/**
+ * Implementation of the policy for allowing compat change overrides.
+ */
+public class OverrideValidatorImpl extends IOverrideValidator.Stub {
+
+ private AndroidBuildClassifier mAndroidBuildClassifier;
+ private Context mContext;
+ private CompatConfig mCompatConfig;
+
+ @VisibleForTesting
+ OverrideValidatorImpl(AndroidBuildClassifier androidBuildClassifier,
+ Context context, CompatConfig config) {
+ mAndroidBuildClassifier = androidBuildClassifier;
+ mContext = context;
+ mCompatConfig = config;
+ }
+
+ @Override
+ public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) {
+ boolean debuggableBuild = false;
+ boolean finalBuild = false;
+
+ debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
+ finalBuild = mAndroidBuildClassifier.isFinalBuild();
+
+ // Allow any override for userdebug or eng builds.
+ if (debuggableBuild) {
+ return new OverrideAllowedState(ALLOWED, -1, -1);
+ }
+ PackageManager packageManager = mContext.getPackageManager();
+ if (packageManager == null) {
+ throw new IllegalStateException("No PackageManager!");
+ }
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = packageManager.getApplicationInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ return new OverrideAllowedState(PACKAGE_DOES_NOT_EXIST, -1, -1);
+ }
+ int appTargetSdk = applicationInfo.targetSdkVersion;
+ // Only allow overriding debuggable apps.
+ if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ return new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1);
+ }
+ int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
+ // Do not allow overriding non-target sdk gated changes on user builds
+ if (minTargetSdk == -1) {
+ return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk);
+ }
+ // Allow overriding any change for debuggable apps on non-final builds.
+ if (!finalBuild) {
+ return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
+ }
+ // Only allow to opt-in for a targetSdk gated change.
+ if (applicationInfo.targetSdkVersion < minTargetSdk) {
+ return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
+ }
+ return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, minTargetSdk);
+ }
+}
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 6ec4b9fbdb93..bb8b12e86e16 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -27,9 +27,12 @@ import android.os.UserHandle;
import android.util.Slog;
import android.util.StatsLog;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.ChangeReporter;
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.IOverrideValidator;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
@@ -46,11 +49,21 @@ public class PlatformCompat extends IPlatformCompat.Stub {
private final Context mContext;
private final ChangeReporter mChangeReporter;
+ private final CompatConfig mCompatConfig;
public PlatformCompat(Context context) {
mContext = context;
mChangeReporter = new ChangeReporter(
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
+ mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext);
+ }
+
+ @VisibleForTesting
+ PlatformCompat(Context context, CompatConfig compatConfig) {
+ mContext = context;
+ mChangeReporter = new ChangeReporter(
+ StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
+ mCompatConfig = compatConfig;
}
@Override
@@ -75,7 +88,7 @@ public class PlatformCompat extends IPlatformCompat.Stub {
@Override
public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
- if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) {
+ if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
reportChange(changeId, appInfo.uid,
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
return true;
@@ -122,57 +135,59 @@ public class PlatformCompat extends IPlatformCompat.Stub {
* otherwise.
*/
public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
- return CompatConfig.get().registerListener(changeId, listener);
+ return mCompatConfig.registerListener(changeId, listener);
}
@Override
- public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
- CompatConfig.get().addOverrides(overrides, packageName);
+ public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
+ throws RemoteException, SecurityException {
+ mCompatConfig.addOverrides(overrides, packageName);
killPackage(packageName);
}
@Override
- public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) {
- CompatConfig.get().addOverrides(overrides, packageName);
+ public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
+ throws RemoteException, SecurityException {
+ mCompatConfig.addOverrides(overrides, packageName);
}
@Override
- public void clearOverrides(String packageName) {
- CompatConfig config = CompatConfig.get();
- config.removePackageOverrides(packageName);
+ public void clearOverrides(String packageName) throws RemoteException, SecurityException {
+ mCompatConfig.removePackageOverrides(packageName);
killPackage(packageName);
}
@Override
- public void clearOverridesForTest(String packageName) {
- CompatConfig config = CompatConfig.get();
- config.removePackageOverrides(packageName);
+ public void clearOverridesForTest(String packageName)
+ throws RemoteException, SecurityException {
+ mCompatConfig.removePackageOverrides(packageName);
}
@Override
- public boolean clearOverride(long changeId, String packageName) {
- boolean existed = CompatConfig.get().removeOverride(changeId, packageName);
+ public boolean clearOverride(long changeId, String packageName)
+ throws RemoteException, SecurityException {
+ boolean existed = mCompatConfig.removeOverride(changeId, packageName);
killPackage(packageName);
return existed;
}
@Override
public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
- return CompatConfig.get().getAppConfig(appInfo);
+ return mCompatConfig.getAppConfig(appInfo);
}
@Override
public CompatibilityChangeInfo[] listAllChanges() {
- return CompatConfig.get().dumpChanges();
+ return mCompatConfig.dumpChanges();
}
/**
* Check whether the change is known to the compat config.
- * @param changeId
+ *
* @return {@code true} if the change is known.
*/
public boolean isKnownChangeId(long changeId) {
- return CompatConfig.get().isKnownChangeId(changeId);
+ return mCompatConfig.isKnownChangeId(changeId);
}
@@ -182,11 +197,11 @@ public class PlatformCompat extends IPlatformCompat.Stub {
*
* @param appInfo The app in question
* @return A sorted long array of change IDs. We use a primitive array to minimize memory
- * footprint: Every app process will store this array statically so we aim to reduce
- * overhead as much as possible.
+ * footprint: Every app process will store this array statically so we aim to reduce
+ * overhead as much as possible.
*/
public long[] getDisabledChanges(ApplicationInfo appInfo) {
- return CompatConfig.get().getDisabledChanges(appInfo);
+ return mCompatConfig.getDisabledChanges(appInfo);
}
/**
@@ -196,18 +211,24 @@ public class PlatformCompat extends IPlatformCompat.Stub {
* @return The change ID, or {@code -1} if no change with that name exists.
*/
public long lookupChangeId(String name) {
- return CompatConfig.get().lookupChangeId(name);
+ return mCompatConfig.lookupChangeId(name);
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
- CompatConfig.get().dumpConfig(pw);
+ mCompatConfig.dumpConfig(pw);
+ }
+
+ @Override
+ public IOverrideValidator getOverrideValidator() {
+ return mCompatConfig.getOverrideValidator();
}
/**
* Clears information stored about events reported on behalf of an app.
* To be called once upon app start or end. A second call would be a no-op.
+ *
* @param appInfo the app to reset
*/
public void resetReporting(ApplicationInfo appInfo) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e39d6d5389e3..d7ae5b5c91bd 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1305,13 +1305,21 @@ public final class DisplayManagerService extends SystemService {
}
private SurfaceControl.ScreenshotGraphicBuffer screenshotInternal(int displayId) {
- final IBinder token = getDisplayToken(displayId);
- if (token == null) {
- return null;
+ synchronized (mSyncRoot) {
+ final IBinder token = getDisplayToken(displayId);
+ if (token == null) {
+ return null;
+ }
+ final LogicalDisplay logicalDisplay = mLogicalDisplays.get(displayId);
+ if (logicalDisplay == null) {
+ return null;
+ }
+
+ final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked();
+ return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(token, new Rect(),
+ displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight(),
+ false /* useIdentityTransform */, 0 /* rotation */);
}
- return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(
- token, new Rect(), 0 /* width */, 0 /* height */,
- false /* useIdentityTransform */, 0 /* rotation */);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index ad728c18dd59..8498dcb32eb1 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -237,15 +237,15 @@ public class DisplayModeDirector {
lowestConsideredPriority++;
}
- int defaultModeId = defaultMode.getModeId();
+ int baseModeId = defaultMode.getModeId();
if (availableModes.length > 0) {
- defaultModeId = availableModes[0];
+ baseModeId = availableModes[0];
}
// filterModes function is going to filter the modes based on the voting system. If
// the application requests a given mode with preferredModeId function, it will be
- // stored as defaultModeId.
+ // stored as baseModeId.
return new DesiredDisplayModeSpecs(
- defaultModeId, new RefreshRateRange(minRefreshRate, maxRefreshRate));
+ baseModeId, new RefreshRateRange(minRefreshRate, maxRefreshRate));
}
}
@@ -526,7 +526,7 @@ public class DisplayModeDirector {
}
/**
- * Information about the desired display mode to be set by the system. Includes the default
+ * Information about the desired display mode to be set by the system. Includes the base
* mode ID and refresh rate range.
*
* We have this class in addition to SurfaceControl.DesiredDisplayConfigSpecs to make clear the
@@ -535,10 +535,10 @@ public class DisplayModeDirector {
*/
public static final class DesiredDisplayModeSpecs {
/**
- * Default mode ID. This is what system defaults to for all other settings, or
+ * Base mode ID. This is what system defaults to for all other settings, or
* if the refresh rate range is not available.
*/
- public int defaultModeId;
+ public int baseModeId;
/**
* The refresh rate range.
*/
@@ -548,9 +548,8 @@ public class DisplayModeDirector {
refreshRateRange = new RefreshRateRange();
}
- public DesiredDisplayModeSpecs(
- int defaultModeId, @NonNull RefreshRateRange refreshRateRange) {
- this.defaultModeId = defaultModeId;
+ public DesiredDisplayModeSpecs(int baseModeId, @NonNull RefreshRateRange refreshRateRange) {
+ this.baseModeId = baseModeId;
this.refreshRateRange = refreshRateRange;
}
@@ -559,7 +558,7 @@ public class DisplayModeDirector {
*/
@Override
public String toString() {
- return String.format("defaultModeId=%d min=%.0f max=%.0f", defaultModeId,
+ return String.format("baseModeId=%d min=%.0f max=%.0f", baseModeId,
refreshRateRange.min, refreshRateRange.max);
}
/**
@@ -577,7 +576,7 @@ public class DisplayModeDirector {
DesiredDisplayModeSpecs desiredDisplayModeSpecs = (DesiredDisplayModeSpecs) other;
- if (defaultModeId != desiredDisplayModeSpecs.defaultModeId) {
+ if (baseModeId != desiredDisplayModeSpecs.baseModeId) {
return false;
}
if (!refreshRateRange.equals(desiredDisplayModeSpecs.refreshRateRange)) {
@@ -588,14 +587,14 @@ public class DisplayModeDirector {
@Override
public int hashCode() {
- return Objects.hash(defaultModeId, refreshRateRange);
+ return Objects.hash(baseModeId, refreshRateRange);
}
/**
* Copy values from the other object.
*/
public void copyFrom(DesiredDisplayModeSpecs other) {
- defaultModeId = other.defaultModeId;
+ baseModeId = other.baseModeId;
refreshRateRange.min = other.refreshRateRange.min;
refreshRateRange.max = other.refreshRateRange.max;
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index cf94d4695497..fb8a4193286b 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -272,14 +272,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// Check whether surface flinger spontaneously changed display config specs out from
// under us. If so, schedule a traversal to reapply our display config specs.
- if (mDisplayModeSpecs.defaultModeId != 0) {
- int activeDefaultMode =
+ if (mDisplayModeSpecs.baseModeId != 0) {
+ int activeBaseMode =
findMatchingModeIdLocked(physicalDisplayConfigSpecs.defaultConfig);
// If we can't map the defaultConfig index to a mode, then the physical display
// configs must have changed, and the code below for handling changes to the
// list of available modes will take care of updating display config specs.
- if (activeDefaultMode != 0) {
- if (mDisplayModeSpecs.defaultModeId != activeDefaultMode
+ if (activeBaseMode != 0) {
+ if (mDisplayModeSpecs.baseModeId != activeBaseMode
|| mDisplayModeSpecs.refreshRateRange.min
!= physicalDisplayConfigSpecs.minRefreshRate
|| mDisplayModeSpecs.refreshRateRange.max
@@ -312,14 +312,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mDefaultModeId = activeRecord.mMode.getModeId();
}
- // Determine whether the display mode specs' default mode is still there.
- if (mSupportedModes.indexOfKey(mDisplayModeSpecs.defaultModeId) < 0) {
- if (mDisplayModeSpecs.defaultModeId != 0) {
+ // Determine whether the display mode specs' base mode is still there.
+ if (mSupportedModes.indexOfKey(mDisplayModeSpecs.baseModeId) < 0) {
+ if (mDisplayModeSpecs.baseModeId != 0) {
Slog.w(TAG,
- "DisplayModeSpecs default mode no longer available, using currently"
- + " active mode as default.");
+ "DisplayModeSpecs base mode no longer available, using currently"
+ + " active mode.");
}
- mDisplayModeSpecs.defaultModeId = activeRecord.mMode.getModeId();
+ mDisplayModeSpecs.baseModeId = activeRecord.mMode.getModeId();
mDisplayModeSpecsInvalid = true;
}
@@ -648,13 +648,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public void setDesiredDisplayModeSpecsLocked(
DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {
- if (displayModeSpecs.defaultModeId == 0) {
+ if (displayModeSpecs.baseModeId == 0) {
// Bail if the caller is requesting a null mode. We'll get called again shortly with
// a valid mode.
return;
}
- int defaultPhysIndex = findDisplayInfoIndexLocked(displayModeSpecs.defaultModeId);
- if (defaultPhysIndex < 0) {
+ int basePhysIndex = findDisplayInfoIndexLocked(displayModeSpecs.baseModeId);
+ if (basePhysIndex < 0) {
// When a display is hotplugged, it's possible for a mode to be removed that was
// previously valid. Because of the way display changes are propagated through the
// framework, and the caching of the display mode specs in LogicalDisplay, it's
@@ -662,8 +662,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// mode. This should only happen in extremely rare cases. A followup call will
// contain a valid mode id.
Slog.w(TAG,
- "Ignoring request for invalid default mode id "
- + displayModeSpecs.defaultModeId);
+ "Ignoring request for invalid base mode id " + displayModeSpecs.baseModeId);
updateDeviceInfoLocked();
return;
}
@@ -673,7 +672,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
getHandler().sendMessage(PooledLambda.obtainMessage(
LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this,
getDisplayTokenLocked(),
- new SurfaceControl.DesiredDisplayConfigSpecs(defaultPhysIndex,
+ new SurfaceControl.DesiredDisplayConfigSpecs(basePhysIndex,
mDisplayModeSpecs.refreshRateRange.min,
mDisplayModeSpecs.refreshRateRange.max)));
}
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index b6255d15795e..c8e5f6c8f53b 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -317,7 +317,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
@Override
public void setDesiredDisplayModeSpecsLocked(
DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {
- final int id = displayModeSpecs.defaultModeId;
+ final int id = displayModeSpecs.baseModeId;
int index = -1;
if (id == 0) {
// Use the default.
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index ae6d63adc7e7..90358ca1f133 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -83,11 +83,11 @@ import android.view.ViewConfiguration;
import android.widget.Toast;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
@@ -186,6 +186,9 @@ public class InputManagerService extends IInputManager.Stub
// The associations of input devices to displays by port. Maps from input device port (String)
// to display id (int). Currently only accessed by InputReader.
private final Map<String, Integer> mStaticAssociations;
+ private final Object mAssociationsLock = new Object();
+ @GuardedBy("mAssociationLock")
+ private final Map<String, Integer> mRuntimeAssociations = new HashMap<String, Integer>();
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
@@ -240,6 +243,7 @@ public class InputManagerService extends IInputManager.Stub
private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
private static native void nativeSetPointerCapture(long ptr, boolean detached);
private static native boolean nativeCanDispatchToDisplay(long ptr, int deviceId, int displayId);
+ private static native void nativeNotifyPortAssociationsChanged(long ptr);
// Input event injection constants defined in InputDispatcher.h.
private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
@@ -1723,6 +1727,49 @@ public class InputManagerService extends IInputManager.Stub
nativeSetCustomPointerIcon(mPtr, icon);
}
+ /**
+ * Add a runtime association between the input port and the display port. This overrides any
+ * static associations.
+ * @param inputPort The port of the input device.
+ * @param displayPort The physical port of the associated display.
+ */
+ @Override // Binder call
+ public void addPortAssociation(@NonNull String inputPort, int displayPort) {
+ if (!checkCallingPermission(
+ android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT,
+ "addPortAssociation()")) {
+ throw new SecurityException(
+ "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT permission");
+ }
+
+ Objects.requireNonNull(inputPort);
+ synchronized (mAssociationsLock) {
+ mRuntimeAssociations.put(inputPort, displayPort);
+ }
+ nativeNotifyPortAssociationsChanged(mPtr);
+ }
+
+ /**
+ * Remove the runtime association between the input port and the display port. Any existing
+ * static association for the cleared input port will be restored.
+ * @param inputPort The port of the input device to be cleared.
+ */
+ @Override // Binder call
+ public void removePortAssociation(@NonNull String inputPort) {
+ if (!checkCallingPermission(
+ android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT,
+ "clearPortAssociations()")) {
+ throw new SecurityException(
+ "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT permission");
+ }
+
+ Objects.requireNonNull(inputPort);
+ synchronized (mAssociationsLock) {
+ mRuntimeAssociations.remove(inputPort);
+ }
+ nativeNotifyPortAssociationsChanged(mPtr);
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -1743,6 +1790,16 @@ public class InputManagerService extends IInputManager.Stub
pw.println(" display: " + v);
});
}
+
+ synchronized (mAssociationsLock) {
+ if (!mRuntimeAssociations.isEmpty()) {
+ pw.println("Runtime Associations:");
+ mRuntimeAssociations.forEach((k, v) -> {
+ pw.print(" port: " + k);
+ pw.println(" display: " + v);
+ });
+ }
+ }
}
private boolean checkCallingPermission(String permission, String func) {
@@ -1766,6 +1823,7 @@ public class InputManagerService extends IInputManager.Stub
@Override
public void monitor() {
synchronized (mInputFilterLock) { }
+ synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
nativeMonitor(mPtr);
}
@@ -1930,7 +1988,7 @@ public class InputManagerService extends IInputManager.Stub
* @return Flattened list
*/
private static List<String> flatten(@NonNull Map<String, Integer> map) {
- List<String> list = new ArrayList<>(map.size() * 2);
+ final List<String> list = new ArrayList<>(map.size() * 2);
map.forEach((k, v)-> {
list.add(k);
list.add(v.toString());
@@ -1943,11 +2001,11 @@ public class InputManagerService extends IInputManager.Stub
* directory.
*/
private static Map<String, Integer> loadStaticInputPortAssociations() {
- File baseDir = Environment.getVendorDirectory();
- File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
+ final File baseDir = Environment.getVendorDirectory();
+ final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
try {
- InputStream stream = new FileInputStream(confFile);
+ final InputStream stream = new FileInputStream(confFile);
return ConfigurationProcessor.processInputPortAssociations(stream);
} catch (FileNotFoundException e) {
// Most of the time, file will not exist, which is expected.
@@ -1960,7 +2018,14 @@ public class InputManagerService extends IInputManager.Stub
// Native callback
private String[] getInputPortAssociations() {
- List<String> associationList = flatten(mStaticAssociations);
+ final Map<String, Integer> associations = new HashMap<>(mStaticAssociations);
+
+ // merge the runtime associations.
+ synchronized (mAssociationsLock) {
+ associations.putAll(mRuntimeAssociations);
+ }
+
+ final List<String> associationList = flatten(associations);
return associationList.toArray(new String[0]);
}
diff --git a/services/core/java/com/android/server/integrity/IntegrityFileManager.java b/services/core/java/com/android/server/integrity/IntegrityFileManager.java
index f90fab4666d6..17a4b9c6c170 100644
--- a/services/core/java/com/android/server/integrity/IntegrityFileManager.java
+++ b/services/core/java/com/android/server/integrity/IntegrityFileManager.java
@@ -25,6 +25,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.integrity.model.RuleMetadata;
import com.android.server.integrity.parser.RuleBinaryParser;
+import com.android.server.integrity.parser.RuleIndexRange;
import com.android.server.integrity.parser.RuleIndexingController;
import com.android.server.integrity.parser.RuleMetadataParser;
import com.android.server.integrity.parser.RuleParseException;
@@ -38,6 +39,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
@@ -152,14 +154,19 @@ public class IntegrityFileManager {
throws IOException, RuleParseException {
synchronized (RULES_LOCK) {
// Try to identify indexes from the index file.
- List<List<Integer>> ruleReadingIndexes =
- mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata);
+ List<RuleIndexRange> ruleReadingIndexes;
+ try {
+ ruleReadingIndexes =
+ mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata);
+ } catch (Exception e) {
+ Slog.w(TAG, "Error identifying the rule indexes. Trying unindexed.", e);
+ ruleReadingIndexes = Collections.emptyList();
+ }
- // Read the rules based on the index information.
- // TODO(b/145493956): Provide the identified indexes to the rule reader.
+ // Read the rules based on the index information when available.
try (FileInputStream inputStream =
new FileInputStream(new File(mRulesDir, RULES_FILE))) {
- List<Rule> rules = mRuleParser.parse(inputStream);
+ List<Rule> rules = mRuleParser.parse(inputStream, ruleReadingIndexes);
return rules;
}
}
diff --git a/services/core/java/com/android/server/integrity/model/BitTrackedInputStream.java b/services/core/java/com/android/server/integrity/model/BitTrackedInputStream.java
new file mode 100644
index 000000000000..e555e3e5746e
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/model/BitTrackedInputStream.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An input stream that tracks the total number read bytes since construction and allows moving
+ * fast forward to a certain byte any time during the execution.
+ *
+ * This class is used for efficient reading of rules based on the rule indexing.
+ */
+public class BitTrackedInputStream extends BitInputStream {
+
+ private static int sReadBitsCount;
+
+ /** Constructor with byte array. */
+ public BitTrackedInputStream(byte[] inputStream) {
+ super(inputStream);
+ sReadBitsCount = 0;
+ }
+
+ /** Constructor with input stream. */
+ public BitTrackedInputStream(InputStream inputStream) {
+ super(inputStream);
+ sReadBitsCount = 0;
+ }
+
+ /** Obtains an integer value of the next {@code numOfBits}. */
+ @Override
+ public int getNext(int numOfBits) throws IOException {
+ sReadBitsCount += numOfBits;
+ return super.getNext(numOfBits);
+ }
+
+ /** Returns the current cursor position showing the number of bits that are read. */
+ public int getReadBitsCount() {
+ return sReadBitsCount;
+ }
+
+ /**
+ * Sets the cursor to the specified byte location.
+ *
+ * Note that the integer parameter specifies the location in bytes -- not bits.
+ */
+ public void setCursorToByteLocation(int byteLocation) throws IOException {
+ int bitCountToRead = byteLocation * 8 - sReadBitsCount;
+ if (bitCountToRead < 0) {
+ throw new IllegalStateException("The byte position is already read.");
+ }
+ super.getNext(bitCountToRead);
+ sReadBitsCount = byteLocation * 8;
+ }
+}
diff --git a/services/core/java/com/android/server/integrity/serializer/ByteTrackedOutputStream.java b/services/core/java/com/android/server/integrity/model/ByteTrackedOutputStream.java
index 62815a9806ee..f575599e1c49 100644
--- a/services/core/java/com/android/server/integrity/serializer/ByteTrackedOutputStream.java
+++ b/services/core/java/com/android/server/integrity/model/ByteTrackedOutputStream.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.integrity.serializer;
+package com.android.server.integrity.model;
import java.io.IOException;
import java.io.OutputStream;
diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
index cbb6e4e8e06f..e744326c49db 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
@@ -37,71 +37,103 @@ import android.content.integrity.CompoundFormula;
import android.content.integrity.Formula;
import android.content.integrity.Rule;
-import com.android.server.integrity.model.BitInputStream;
+import com.android.server.integrity.model.BitTrackedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/** A helper class to parse rules into the {@link Rule} model from Binary representation. */
public class RuleBinaryParser implements RuleParser {
- private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
-
@Override
public List<Rule> parse(byte[] ruleBytes) throws RuleParseException {
try {
- BitInputStream bitInputStream = new BitInputStream(ruleBytes);
- return parseRules(bitInputStream);
+ BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(ruleBytes);
+ return parseRules(bitTrackedInputStream, /* indexRanges= */ Collections.emptyList());
} catch (Exception e) {
throw new RuleParseException(e.getMessage(), e);
}
}
@Override
- public List<Rule> parse(InputStream inputStream) throws RuleParseException {
+ public List<Rule> parse(InputStream inputStream, List<RuleIndexRange> indexRanges)
+ throws RuleParseException {
try {
- BitInputStream bitInputStream = new BitInputStream(inputStream);
- return parseRules(bitInputStream);
+ BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(inputStream);
+ return parseRules(bitTrackedInputStream, indexRanges);
} catch (Exception e) {
throw new RuleParseException(e.getMessage(), e);
}
}
- private List<Rule> parseRules(BitInputStream bitInputStream) throws IOException {
- List<Rule> parsedRules = new ArrayList<>();
+ private List<Rule> parseRules(
+ BitTrackedInputStream bitTrackedInputStream,
+ List<RuleIndexRange> indexRanges)
+ throws IOException {
// Read the rule binary file format version.
- bitInputStream.getNext(FORMAT_VERSION_BITS);
+ bitTrackedInputStream.getNext(FORMAT_VERSION_BITS);
+
+ return indexRanges.isEmpty()
+ ? parseAllRules(bitTrackedInputStream)
+ : parseIndexedRules(bitTrackedInputStream, indexRanges);
+ }
+
+ private List<Rule> parseAllRules(BitTrackedInputStream bitTrackedInputStream)
+ throws IOException {
+ List<Rule> parsedRules = new ArrayList<>();
+
+ while (bitTrackedInputStream.hasNext()) {
+ if (bitTrackedInputStream.getNext(SIGNAL_BIT) == 1) {
+ parsedRules.add(parseRule(bitTrackedInputStream));
+ }
+ }
+
+ return parsedRules;
+ }
+
+ private List<Rule> parseIndexedRules(
+ BitTrackedInputStream bitTrackedInputStream, List<RuleIndexRange> indexRanges)
+ throws IOException {
+ List<Rule> parsedRules = new ArrayList<>();
+
+ for (RuleIndexRange range : indexRanges) {
+ // Skip the rules that are not in the range.
+ bitTrackedInputStream.setCursorToByteLocation(range.getStartIndex());
- while (bitInputStream.hasNext()) {
- if (bitInputStream.getNext(SIGNAL_BIT) == 1) {
- parsedRules.add(parseRule(bitInputStream));
+ // Read the rules until we reach the end index.
+ while (bitTrackedInputStream.hasNext()
+ && bitTrackedInputStream.getReadBitsCount() < range.getEndIndex()) {
+ if (bitTrackedInputStream.getNext(SIGNAL_BIT) == 1) {
+ parsedRules.add(parseRule(bitTrackedInputStream));
+ }
}
}
return parsedRules;
}
- private Rule parseRule(BitInputStream bitInputStream) throws IOException {
- Formula formula = parseFormula(bitInputStream);
- int effect = bitInputStream.getNext(EFFECT_BITS);
+ private Rule parseRule(BitTrackedInputStream bitTrackedInputStream) throws IOException {
+ Formula formula = parseFormula(bitTrackedInputStream);
+ int effect = bitTrackedInputStream.getNext(EFFECT_BITS);
- if (bitInputStream.getNext(SIGNAL_BIT) != 1) {
+ if (bitTrackedInputStream.getNext(SIGNAL_BIT) != 1) {
throw new IllegalArgumentException("A rule must end with a '1' bit.");
}
return new Rule(formula, effect);
}
- private Formula parseFormula(BitInputStream bitInputStream) throws IOException {
- int separator = bitInputStream.getNext(SEPARATOR_BITS);
+ private Formula parseFormula(BitTrackedInputStream bitTrackedInputStream) throws IOException {
+ int separator = bitTrackedInputStream.getNext(SEPARATOR_BITS);
switch (separator) {
case ATOMIC_FORMULA_START:
- return parseAtomicFormula(bitInputStream);
+ return parseAtomicFormula(bitTrackedInputStream);
case COMPOUND_FORMULA_START:
- return parseCompoundFormula(bitInputStream);
+ return parseCompoundFormula(bitTrackedInputStream);
case COMPOUND_FORMULA_END:
return null;
default:
@@ -110,37 +142,40 @@ public class RuleBinaryParser implements RuleParser {
}
}
- private CompoundFormula parseCompoundFormula(BitInputStream bitInputStream) throws IOException {
- int connector = bitInputStream.getNext(CONNECTOR_BITS);
+ private CompoundFormula parseCompoundFormula(BitTrackedInputStream bitTrackedInputStream)
+ throws IOException {
+ int connector = bitTrackedInputStream.getNext(CONNECTOR_BITS);
List<Formula> formulas = new ArrayList<>();
- Formula parsedFormula = parseFormula(bitInputStream);
+ Formula parsedFormula = parseFormula(bitTrackedInputStream);
while (parsedFormula != null) {
formulas.add(parsedFormula);
- parsedFormula = parseFormula(bitInputStream);
+ parsedFormula = parseFormula(bitTrackedInputStream);
}
return new CompoundFormula(connector, formulas);
}
- private AtomicFormula parseAtomicFormula(BitInputStream bitInputStream) throws IOException {
- int key = bitInputStream.getNext(KEY_BITS);
- int operator = bitInputStream.getNext(OPERATOR_BITS);
+ private AtomicFormula parseAtomicFormula(BitTrackedInputStream bitTrackedInputStream)
+ throws IOException {
+ int key = bitTrackedInputStream.getNext(KEY_BITS);
+ int operator = bitTrackedInputStream.getNext(OPERATOR_BITS);
switch (key) {
case AtomicFormula.PACKAGE_NAME:
case AtomicFormula.APP_CERTIFICATE:
case AtomicFormula.INSTALLER_NAME:
case AtomicFormula.INSTALLER_CERTIFICATE:
- boolean isHashedValue = bitInputStream.getNext(IS_HASHED_BITS) == 1;
- int valueSize = bitInputStream.getNext(VALUE_SIZE_BITS);
- String stringValue = getStringValue(bitInputStream, valueSize, isHashedValue);
+ boolean isHashedValue = bitTrackedInputStream.getNext(IS_HASHED_BITS) == 1;
+ int valueSize = bitTrackedInputStream.getNext(VALUE_SIZE_BITS);
+ String stringValue = getStringValue(bitTrackedInputStream, valueSize,
+ isHashedValue);
return new AtomicFormula.StringAtomicFormula(key, stringValue, isHashedValue);
case AtomicFormula.VERSION_CODE:
- int intValue = getIntValue(bitInputStream);
+ int intValue = getIntValue(bitTrackedInputStream);
return new AtomicFormula.IntAtomicFormula(key, operator, intValue);
case AtomicFormula.PRE_INSTALLED:
- boolean booleanValue = getBooleanValue(bitInputStream);
+ boolean booleanValue = getBooleanValue(bitTrackedInputStream);
return new AtomicFormula.BooleanAtomicFormula(key, booleanValue);
default:
throw new IllegalArgumentException(String.format("Unknown key: %d", key));
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java b/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java
new file mode 100644
index 000000000000..8c8450e5fdc4
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.parser;
+
+import android.annotation.Nullable;
+
+/**
+ * A wrapper class to represent an indexing range that is identified by the {@link
+ * RuleIndexingController}.
+ */
+public class RuleIndexRange {
+ private static int sStartIndex;
+ private static int sEndIndex;
+
+ /** Constructor with start and end indexes. */
+ public RuleIndexRange(int startIndex, int endIndex) {
+ this.sStartIndex = startIndex;
+ this.sEndIndex = endIndex;
+ }
+
+ /** Returns the startIndex. */
+ public int getStartIndex() {
+ return sStartIndex;
+ }
+
+ /** Returns the end index. */
+ public int getEndIndex() {
+ return sEndIndex;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ return sStartIndex == ((RuleIndexRange) object).getStartIndex()
+ && sEndIndex == ((RuleIndexRange) object).getEndIndex();
+ }
+}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
index b642fa64baaf..c9713220d6e8 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
@@ -17,6 +17,7 @@
package com.android.server.integrity.parser;
import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
+import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY;
import static com.android.server.integrity.parser.BinaryFileOperations.getIntValue;
import static com.android.server.integrity.parser.BinaryFileOperations.getStringValue;
@@ -24,25 +25,27 @@ import android.content.integrity.AppInstallMetadata;
import com.android.server.integrity.model.BitInputStream;
-import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
-import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
/** Helper class to identify the necessary indexes that needs to be read. */
public class RuleIndexingController {
- private static TreeMap<String, Integer> sPackageNameBasedIndexes;
- private static TreeMap<String, Integer> sAppCertificateBasedIndexes;
- private static TreeMap<String, Integer> sUnindexedRuleIndexes;
+ private static LinkedHashMap<String, Integer> sPackageNameBasedIndexes;
+ private static LinkedHashMap<String, Integer> sAppCertificateBasedIndexes;
+ private static LinkedHashMap<String, Integer> sUnindexedRuleIndexes;
/**
* Provide the indexing file to read and the object will be constructed by reading and
* identifying the indexes.
*/
- public RuleIndexingController(FileInputStream fileInputStream) throws IOException {
- BitInputStream bitInputStream = new BitInputStream(fileInputStream);
+ public RuleIndexingController(InputStream inputStream) throws IOException {
+ BitInputStream bitInputStream = new BitInputStream(inputStream);
sPackageNameBasedIndexes = getNextIndexGroup(bitInputStream);
sAppCertificateBasedIndexes = getNextIndexGroup(bitInputStream);
sUnindexedRuleIndexes = getNextIndexGroup(bitInputStream);
@@ -52,24 +55,57 @@ public class RuleIndexingController {
* Returns a list of integers with the starting and ending bytes of the rules that needs to be
* read and evaluated.
*/
- public List<List<Integer>> identifyRulesToEvaluate(AppInstallMetadata appInstallMetadata) {
- // TODO(b/145493956): Identify and return the indexes that needs to be read.
- return new ArrayList<>();
+ public List<RuleIndexRange> identifyRulesToEvaluate(AppInstallMetadata appInstallMetadata) {
+ ArrayList<RuleIndexRange> indexRanges = new ArrayList();
+
+ // Add the range for package name indexes rules.
+ indexRanges.add(
+ searchIndexingKeysRangeContainingKey(
+ sPackageNameBasedIndexes, appInstallMetadata.getPackageName()));
+
+ // Add the range for app certificate indexes rules.
+ indexRanges.add(
+ searchIndexingKeysRangeContainingKey(
+ sAppCertificateBasedIndexes, appInstallMetadata.getAppCertificate()));
+
+ // Add the range for unindexed rules.
+ indexRanges.add(
+ new RuleIndexRange(
+ sUnindexedRuleIndexes.get(START_INDEXING_KEY),
+ sUnindexedRuleIndexes.get(END_INDEXING_KEY)));
+
+ return indexRanges;
}
- private TreeMap<String, Integer> getNextIndexGroup(BitInputStream bitInputStream)
+ private LinkedHashMap<String, Integer> getNextIndexGroup(BitInputStream bitInputStream)
throws IOException {
- TreeMap<String, Integer> keyToIndexMap = new TreeMap<>();
+ LinkedHashMap<String, Integer> keyToIndexMap = new LinkedHashMap<>();
while (bitInputStream.hasNext()) {
String key = getStringValue(bitInputStream);
int value = getIntValue(bitInputStream);
keyToIndexMap.put(key, value);
- if (key == END_INDEXING_KEY) {
+ if (key.matches(END_INDEXING_KEY)) {
break;
}
}
return keyToIndexMap;
}
+
+ private RuleIndexRange searchIndexingKeysRangeContainingKey(
+ LinkedHashMap<String, Integer> indexMap, String searchedKey) {
+ TreeSet<String> keyTreeSet =
+ indexMap.keySet().stream()
+ .filter(key -> !key.matches(START_INDEXING_KEY) && !key.matches(
+ END_INDEXING_KEY))
+ .collect(Collectors.toCollection(TreeSet::new));
+
+ String minIndex = keyTreeSet.floor(searchedKey);
+ String maxIndex = keyTreeSet.ceiling(searchedKey);
+
+ return new RuleIndexRange(
+ indexMap.get(minIndex == null ? START_INDEXING_KEY : minIndex),
+ indexMap.get(maxIndex == null ? END_INDEXING_KEY : maxIndex));
+ }
}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleParser.java b/services/core/java/com/android/server/integrity/parser/RuleParser.java
index 81783d5c7324..a8e9f6134759 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleParser.java
@@ -28,5 +28,6 @@ public interface RuleParser {
List<Rule> parse(byte[] ruleBytes) throws RuleParseException;
/** Parse rules from an input stream. */
- List<Rule> parse(InputStream inputStream) throws RuleParseException;
+ List<Rule> parse(InputStream inputStream, List<RuleIndexRange> ruleIndexRanges)
+ throws RuleParseException;
}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
index d405583442bd..497be8424286 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
@@ -62,7 +62,8 @@ public final class RuleXmlParser implements RuleParser {
}
@Override
- public List<Rule> parse(InputStream inputStream) throws RuleParseException {
+ public List<Rule> parse(InputStream inputStream, List<RuleIndexRange> indexRanges)
+ throws RuleParseException {
try {
XmlPullParser xmlPullParser = Xml.newPullParser();
xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
index b8791c3c3489..f964d4cf2724 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
@@ -42,6 +42,7 @@ import android.content.integrity.Rule;
import com.android.internal.util.Preconditions;
import com.android.server.integrity.IntegrityUtils;
import com.android.server.integrity.model.BitOutputStream;
+import com.android.server.integrity.model.ByteTrackedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -109,7 +110,8 @@ public class RuleBinarySerializer implements RuleSerializer {
}
private void serializeRuleFileMetadata(Optional<Integer> formatVersion,
- ByteTrackedOutputStream outputStream) throws IOException {
+ ByteTrackedOutputStream outputStream)
+ throws IOException {
int formatVersionValue = formatVersion.orElse(DEFAULT_FORMAT_VERSION);
BitOutputStream bitOutputStream = new BitOutputStream();
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index ccfc98e2291b..ed6a759409d4 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -16,11 +16,11 @@
package com.android.server.location;
+import android.annotation.Nullable;
import android.content.Context;
import android.location.Location;
import android.os.Binder;
import android.os.Bundle;
-import android.os.WorkSource;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -29,127 +29,336 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.UnaryOperator;
/**
- * Location Manager's interface for location providers. Always starts as disabled.
+ * Base class for all location providers.
*
* @hide
*/
public abstract class AbstractLocationProvider {
/**
- * Interface for communicating from a location provider back to the location service.
+ * Interface for listening to location providers.
*/
- public interface LocationProviderManager {
+ public interface Listener {
/**
- * May be called to inform the location service of a change in this location provider's
- * enabled/disabled state.
+ * Called when a provider's state changes. May be invoked from any thread. Will be
+ * invoked with a cleared binder identity.
*/
- void onSetEnabled(boolean enabled);
+ void onStateChanged(State oldState, State newState);
/**
- * May be called to inform the location service of a change in this location provider's
- * properties.
+ * Called when a provider has a new location available. May be invoked from any thread. Will
+ * be invoked with a cleared binder identity.
*/
- void onSetProperties(ProviderProperties properties);
+ void onReportLocation(Location location);
/**
- * May be called to inform the location service that this provider has a new location
- * available.
+ * Called when a provider has a new location available. May be invoked from any thread. Will
+ * be invoked with a cleared binder identity.
*/
- void onReportLocation(Location location);
+ void onReportLocation(List<Location> locations);
+ }
+
+ /**
+ * Holds a representation of the public state of a provider.
+ */
+ public static final class State {
/**
- * May be called to inform the location service that this provider has a new location
- * available.
+ * Default state value for a location provider that is disabled with no properties and an
+ * empty provider package list.
*/
- void onReportLocation(List<Location> locations);
+ public static final State EMPTY_STATE = new State(false, null,
+ Collections.emptySet());
+
+ /**
+ * The provider's enabled state.
+ */
+ public final boolean enabled;
+
+ /**
+ * The provider's properties.
+ */
+ @Nullable public final ProviderProperties properties;
+
+ /**
+ * The provider's package name list - provider packages may be afforded special privileges.
+ */
+ public final Set<String> providerPackageNames;
+
+ private State(boolean enabled, ProviderProperties properties,
+ Set<String> providerPackageNames) {
+ this.enabled = enabled;
+ this.properties = properties;
+ this.providerPackageNames = Objects.requireNonNull(providerPackageNames);
+ }
+
+ private State withEnabled(boolean enabled) {
+ if (enabled == this.enabled) {
+ return this;
+ } else {
+ return new State(enabled, properties, providerPackageNames);
+ }
+ }
+
+ private State withProperties(ProviderProperties properties) {
+ if (properties.equals(this.properties)) {
+ return this;
+ } else {
+ return new State(enabled, properties, providerPackageNames);
+ }
+ }
+
+ private State withProviderPackageNames(Set<String> providerPackageNames) {
+ if (providerPackageNames.equals(this.providerPackageNames)) {
+ return this;
+ } else {
+ return new State(enabled, properties, providerPackageNames);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof State)) {
+ return false;
+ }
+ State state = (State) o;
+ return enabled == state.enabled && properties == state.properties
+ && providerPackageNames.equals(state.providerPackageNames);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(enabled, properties, providerPackageNames);
+ }
+ }
+
+ // combines listener and state information so that they can be updated atomically with respect
+ // to each other and an ordering established.
+ private static class InternalState {
+ @Nullable public final Listener listener;
+ public final State state;
+
+ private InternalState(@Nullable Listener listener, State state) {
+ this.listener = listener;
+ this.state = state;
+ }
+
+ private InternalState withListener(Listener listener) {
+ if (listener == this.listener) {
+ return this;
+ } else {
+ return new InternalState(listener, state);
+ }
+ }
+
+ private InternalState withState(State state) {
+ if (state.equals(this.state)) {
+ return this;
+ } else {
+ return new InternalState(listener, state);
+ }
+ }
+
+ private InternalState withState(UnaryOperator<State> operator) {
+ return withState(operator.apply(state));
+ }
}
protected final Context mContext;
- private final LocationProviderManager mLocationProviderManager;
+ protected final Executor mExecutor;
+
+ // we use a lock-free implementation to update state to ensure atomicity between updating the
+ // provider state and setting the listener, so that the state updates a listener sees are
+ // consistent with when the listener was set (a listener should not see any updates that occur
+ // before it was set, and should not miss any updates that occur after it was set).
+ private final AtomicReference<InternalState> mInternalState;
- protected AbstractLocationProvider(
- Context context, LocationProviderManager locationProviderManager) {
+ protected AbstractLocationProvider(Context context, Executor executor) {
+ this(context, executor, Collections.singleton(context.getPackageName()));
+ }
+
+ protected AbstractLocationProvider(Context context, Executor executor,
+ Set<String> packageNames) {
mContext = context;
- mLocationProviderManager = locationProviderManager;
+ mExecutor = executor;
+ mInternalState = new AtomicReference<>(
+ new InternalState(null, State.EMPTY_STATE.withProviderPackageNames(packageNames)));
}
/**
- * Call this method to report a change in provider enabled/disabled status. May be called from
- * any thread.
+ * Sets the listener and returns the state at the moment the listener was set. The listener can
+ * expect to receive all state updates from after this point.
*/
- protected void setEnabled(boolean enabled) {
- long identity = Binder.clearCallingIdentity();
- try {
- mLocationProviderManager.onSetEnabled(enabled);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ State setListener(@Nullable Listener listener) {
+ return mInternalState.updateAndGet(
+ internalState -> internalState.withListener(listener)).state;
+ }
+
+ /**
+ * Retrieves the state of the provider.
+ */
+ State getState() {
+ return mInternalState.get().state;
+ }
+
+ /**
+ * Sets the state of the provider to the new state.
+ */
+ void setState(State newState) {
+ InternalState oldInternalState = mInternalState.getAndUpdate(
+ internalState -> internalState.withState(newState));
+ if (newState.equals(oldInternalState.state)) {
+ return;
+ }
+
+ // we know that we only updated the state, so the listener for the old state is the same as
+ // the listener for the new state.
+ if (oldInternalState.listener != null) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ oldInternalState.listener.onStateChanged(oldInternalState.state, newState);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ private void setState(UnaryOperator<State> operator) {
+ InternalState oldInternalState = mInternalState.getAndUpdate(
+ internalState -> internalState.withState(operator));
+
+ // recreate the new state from our knowledge of the old state - unfortunately may result in
+ // an extra allocation, but oh well...
+ State newState = operator.apply(oldInternalState.state);
+
+ if (newState.equals(oldInternalState.state)) {
+ return;
+ }
+
+ // we know that we only updated the state, so the listener for the old state is the same as
+ // the listener for the new state.
+ if (oldInternalState.listener != null) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ oldInternalState.listener.onStateChanged(oldInternalState.state, newState);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
/**
- * Call this method to report a change in provider properties. May be called from
- * any thread.
+ * The current enabled state of this provider.
+ */
+ protected boolean isEnabled() {
+ return mInternalState.get().state.enabled;
+ }
+
+ /**
+ * The current provider properties of this provider.
+ */
+ @Nullable
+ protected ProviderProperties getProperties() {
+ return mInternalState.get().state.properties;
+ }
+
+ /**
+ * The current package set of this provider.
+ */
+ protected Set<String> getProviderPackages() {
+ return mInternalState.get().state.providerPackageNames;
+ }
+
+ /**
+ * Call this method to report a change in provider enabled/disabled status.
+ */
+ protected void setEnabled(boolean enabled) {
+ setState(state -> state.withEnabled(enabled));
+ }
+
+ /**
+ * Call this method to report a change in provider properties.
*/
protected void setProperties(ProviderProperties properties) {
- long identity = Binder.clearCallingIdentity();
- try {
- mLocationProviderManager.onSetProperties(properties);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ setState(state -> state.withProperties(properties));
+ }
+
+ /**
+ * Call this method to report a change in provider packages.
+ */
+ protected void setPackageNames(Set<String> packageNames) {
+ setState(state -> state.withProviderPackageNames(packageNames));
}
/**
- * Call this method to report a new location. May be called from any thread.
+ * Call this method to report a new location.
*/
protected void reportLocation(Location location) {
- long identity = Binder.clearCallingIdentity();
- try {
- mLocationProviderManager.onReportLocation(location);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ Listener listener = mInternalState.get().listener;
+ if (listener != null) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ listener.onReportLocation(location);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
/**
- * Call this method to report a new location. May be called from any thread.
+ * Call this method to report a new location.
*/
protected void reportLocation(List<Location> locations) {
- long identity = Binder.clearCallingIdentity();
- try {
- mLocationProviderManager.onReportLocation(locations);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ Listener listener = mInternalState.get().listener;
+ if (listener != null) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ listener.onReportLocation(locations);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
/**
- * Invoked by the location service to return a list of packages currently associated with this
- * provider. May be called from any thread.
+ * Sets a new request and worksource for the provider.
*/
- public List<String> getProviderPackages() {
- return Collections.singletonList(mContext.getPackageName());
+ public final void setRequest(ProviderRequest request) {
+ // all calls into the provider must be moved onto the provider thread to prevent deadlock
+ mExecutor.execute(() -> onSetRequest(request));
}
/**
- * Invoked by the location service to deliver a new request for fulfillment to the provider.
- * Replaces any previous requests completely. Will always be invoked from the location service
- * thread with a cleared binder identity.
+ * Always invoked on the provider executor.
*/
- public abstract void onSetRequest(ProviderRequest request, WorkSource source);
+ protected abstract void onSetRequest(ProviderRequest request);
+
+ /**
+ * Sends an extra command to the provider for it to interpret as it likes.
+ */
+ public final void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
+ // all calls into the provider must be moved onto the provider thread to prevent deadlock
+ mExecutor.execute(() -> onExtraCommand(uid, pid, command, extras));
+ }
/**
- * Invoked by the location service to deliver a custom command to this provider. Will always be
- * invoked from the location service thread with a cleared binder identity.
+ * Always invoked on the provider executor.
*/
- public void onSendExtraCommand(int uid, int pid, String command, Bundle extras) {}
+ protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
/**
- * Invoked by the location service to dump debug or log information. May be invoked from any
- * thread.
+ * Dumps debug or log information. May be invoked from any thread.
*/
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index d8561b697caa..15cf190952d1 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -43,6 +43,7 @@ import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
@@ -113,8 +114,15 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
private static final ProviderProperties PROPERTIES = new ProviderProperties(
- true, true, false, false, true, true, true,
- Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
+ /* requiresNetwork = */false,
+ /* requiresSatellite = */true,
+ /* requiresCell = */false,
+ /* hasMonetaryCost = */false,
+ /* supportAltitude = */true,
+ /* supportsSpeed = */true,
+ /* supportsBearing = */true,
+ Criteria.POWER_HIGH,
+ Criteria.ACCURACY_FINE);
// these need to match GnssPositionMode enum in IGnss.hal
private static final int GPS_POSITION_MODE_STANDALONE = 0;
@@ -616,13 +624,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
- public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
- Looper looper) {
- super(context, locationProviderManager);
+ public GnssLocationProvider(Context context, Handler handler) {
+ super(context, new HandlerExecutor(handler));
ensureInitialized();
- mLooper = looper;
+ mLooper = handler.getLooper();
// Create a wake lock
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -639,7 +646,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
- GnssLocationProvider.this::onNetworkAvailable, looper);
+ GnssLocationProvider.this::onNetworkAvailable, mLooper);
// App ops service to keep track of who is accessing the GPS
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -649,7 +656,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
BatteryStats.SERVICE_NAME));
// Construct internal handler
- mHandler = new ProviderHandler(looper);
+ mHandler = new ProviderHandler(mLooper);
// Load GPS configuration and register listeners in the background:
// some operations, such as opening files and registering broadcast receivers, can take a
@@ -693,10 +700,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
};
mGnssMetrics = new GnssMetrics(mBatteryStats);
- mNtpTimeHelper = new NtpTimeHelper(mContext, looper, this);
+ mNtpTimeHelper = new NtpTimeHelper(mContext, mLooper, this);
GnssSatelliteBlacklistHelper gnssSatelliteBlacklistHelper =
new GnssSatelliteBlacklistHelper(mContext,
- looper, this);
+ mLooper, this);
mHandler.post(gnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
mGnssBatchingProvider = new GnssBatchingProvider();
mGnssGeofenceProvider = new GnssGeofenceProvider();
@@ -1047,8 +1054,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
@Override
- public void onSetRequest(ProviderRequest request, WorkSource source) {
- sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
+ public void onSetRequest(ProviderRequest request) {
+ sendMessage(SET_REQUEST, 0, new GpsRequest(request, request.workSource));
}
private void handleSetRequest(ProviderRequest request, WorkSource source) {
@@ -1185,7 +1192,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
@Override
- public void onSendExtraCommand(int uid, int pid, String command, Bundle extras) {
+ public void onExtraCommand(int uid, int pid, String command, Bundle extras) {
long identity = Binder.clearCallingIdentity();
try {
@@ -2064,10 +2071,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
/**
- * This method is bound to {@link #GnssLocationProvider(Context, LocationProviderManager,
- * Looper)}.
- * It is in charge of loading properties and registering for events that will be posted to
- * this handler.
+ * This method is bound to the constructor. It is in charge of loading properties and
+ * registering for events that will be posted to this handler.
*/
private void handleInitialize() {
// class_init_native() already initializes the GNSS service handle during class loading.
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 694f14904668..8a149afa6238 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -23,12 +23,13 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.WorkSource;
+import android.util.ArraySet;
import android.util.Log;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.location.ILocationProvider;
import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderProperties;
@@ -39,10 +40,8 @@ import com.android.server.ServiceWatcher;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
/**
* Proxy for ILocationProvider implementations.
@@ -52,59 +51,64 @@ public class LocationProviderProxy extends AbstractLocationProvider {
private static final String TAG = "LocationProviderProxy";
private static final boolean D = LocationManagerService.D;
- // used to ensure that updates to mProviderPackages are atomic
- private final Object mProviderPackagesLock = new Object();
-
- // used to ensure that updates to mRequest and mWorkSource are atomic
- private final Object mRequestLock = new Object();
+ private static final int MAX_ADDITIONAL_PACKAGES = 2;
private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() {
// executed on binder thread
@Override
public void onSetAdditionalProviderPackages(List<String> packageNames) {
- LocationProviderProxy.this.onSetAdditionalProviderPackages(packageNames);
+ int maxCount = Math.min(MAX_ADDITIONAL_PACKAGES, packageNames.size()) + 1;
+ ArraySet<String> allPackages = new ArraySet<>(maxCount);
+ allPackages.add(mServiceWatcher.getCurrentPackageName());
+ for (String packageName : packageNames) {
+ if (packageNames.size() >= maxCount) {
+ return;
+ }
+
+ try {
+ mContext.getPackageManager().getPackageInfo(packageName, MATCH_SYSTEM_ONLY);
+ allPackages.add(packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, mServiceWatcher + " specified unknown additional provider package: "
+ + packageName);
+ }
+ }
+
+ setPackageNames(allPackages);
}
// executed on binder thread
@Override
public void onSetEnabled(boolean enabled) {
- LocationProviderProxy.this.setEnabled(enabled);
+ setEnabled(enabled);
}
// executed on binder thread
@Override
public void onSetProperties(ProviderProperties properties) {
- LocationProviderProxy.this.setProperties(properties);
+ setProperties(properties);
}
// executed on binder thread
@Override
public void onReportLocation(Location location) {
- LocationProviderProxy.this.reportLocation(location);
+ reportLocation(location);
}
};
private final ServiceWatcher mServiceWatcher;
- @GuardedBy("mProviderPackagesLock")
- private final CopyOnWriteArrayList<String> mProviderPackages = new CopyOnWriteArrayList<>();
-
- @GuardedBy("mRequestLock")
- @Nullable
- private ProviderRequest mRequest;
- @GuardedBy("mRequestLock")
- private WorkSource mWorkSource;
+ @Nullable private ProviderRequest mRequest;
/**
* Creates a new LocationProviderProxy and immediately begins binding to the best applicable
* service.
*/
@Nullable
- public static LocationProviderProxy createAndBind(
- Context context, LocationProviderManager locationProviderManager, String action,
+ public static LocationProviderProxy createAndBind(Context context, String action,
int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId) {
- LocationProviderProxy proxy = new LocationProviderProxy(context, locationProviderManager,
+ LocationProviderProxy proxy = new LocationProviderProxy(context, FgThread.getHandler(),
action, overlaySwitchResId, defaultServicePackageNameResId,
initialPackageNamesResId);
if (proxy.bind()) {
@@ -114,14 +118,13 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
}
- private LocationProviderProxy(Context context, LocationProviderManager locationProviderManager,
- String action, int overlaySwitchResId, int defaultServicePackageNameResId,
+ private LocationProviderProxy(Context context, Handler handler, String action,
+ int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId) {
- super(context, locationProviderManager);
+ super(context, new HandlerExecutor(handler), Collections.emptySet());
mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId,
- defaultServicePackageNameResId, initialPackageNamesResId,
- FgThread.getHandler()) {
+ defaultServicePackageNameResId, initialPackageNamesResId, handler) {
@Override
protected void onBind() {
@@ -130,14 +133,11 @@ public class LocationProviderProxy extends AbstractLocationProvider {
@Override
protected void onUnbind() {
- resetProviderPackages(Collections.emptyList());
- setEnabled(false);
- setProperties(null);
+ setState(State.EMPTY_STATE);
}
};
mRequest = null;
- mWorkSource = new WorkSource();
}
private boolean bind() {
@@ -148,77 +148,34 @@ public class LocationProviderProxy extends AbstractLocationProvider {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher);
- resetProviderPackages(Collections.emptyList());
+ setPackageNames(Collections.singleton(mServiceWatcher.getCurrentPackageName()));
service.setLocationProviderManager(mManager);
- synchronized (mRequestLock) {
- if (mRequest != null) {
- service.setRequest(mRequest, mWorkSource);
- }
- }
- }
-
- @Override
- public List<String> getProviderPackages() {
- synchronized (mProviderPackagesLock) {
- return mProviderPackages;
+ if (mRequest != null) {
+ service.setRequest(mRequest, mRequest.workSource);
}
}
@Override
- public void onSetRequest(ProviderRequest request, WorkSource source) {
- synchronized (mRequestLock) {
- mRequest = request;
- mWorkSource = source;
- }
+ public void onSetRequest(ProviderRequest request) {
mServiceWatcher.runOnBinder(binder -> {
+ mRequest = request;
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- service.setRequest(request, source);
+ service.setRequest(request, request.workSource);
});
}
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("service=" + mServiceWatcher);
- synchronized (mProviderPackagesLock) {
- if (mProviderPackages.size() > 1) {
- pw.println("additional packages=" + mProviderPackages);
- }
- }
- }
-
- @Override
- public void onSendExtraCommand(int uid, int pid, String command, Bundle extras) {
+ public void onExtraCommand(int uid, int pid, String command, Bundle extras) {
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
service.sendExtraCommand(command, extras);
});
}
- private void onSetAdditionalProviderPackages(List<String> packageNames) {
- resetProviderPackages(packageNames);
- }
-
- private void resetProviderPackages(List<String> additionalPackageNames) {
- ArrayList<String> permittedPackages = new ArrayList<>(additionalPackageNames.size());
- for (String packageName : additionalPackageNames) {
- try {
- mContext.getPackageManager().getPackageInfo(packageName, MATCH_SYSTEM_ONLY);
- permittedPackages.add(packageName);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, mServiceWatcher + " specified unknown additional provider package: "
- + packageName);
- }
- }
-
- synchronized (mProviderPackagesLock) {
- mProviderPackages.clear();
- String myPackage = mServiceWatcher.getCurrentPackageName();
- if (myPackage != null) {
- mProviderPackages.add(myPackage);
- mProviderPackages.addAll(permittedPackages);
- }
- }
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("service=" + mServiceWatcher);
}
}
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index b7ccb26da64b..45c833498ac7 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -1,8 +1,29 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server.location;
import android.os.SystemClock;
import android.util.Log;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -17,6 +38,8 @@ public class LocationRequestStatistics {
public final HashMap<PackageProviderKey, PackageStatistics> statistics
= new HashMap<PackageProviderKey, PackageStatistics>();
+ public final RequestSummaryLimitedHistory history = new RequestSummaryLimitedHistory();
+
/**
* Signals that a package has started requesting locations.
*
@@ -34,6 +57,7 @@ public class LocationRequestStatistics {
}
stats.startRequesting(intervalMs);
stats.updateForeground(isForeground);
+ history.addRequest(packageName, providerName, intervalMs);
}
/**
@@ -48,6 +72,7 @@ public class LocationRequestStatistics {
if (stats != null) {
stats.stopRequesting();
}
+ history.removeRequest(packageName, providerName);
}
/**
@@ -77,7 +102,7 @@ public class LocationRequestStatistics {
*/
public final String providerName;
- public PackageProviderKey(String packageName, String providerName) {
+ PackageProviderKey(String packageName, String providerName) {
this.packageName = packageName;
this.providerName = providerName;
}
@@ -100,6 +125,104 @@ public class LocationRequestStatistics {
}
/**
+ * A data structure to hold past requests
+ */
+ public static class RequestSummaryLimitedHistory {
+ @VisibleForTesting
+ static final int MAX_SIZE = 100;
+
+ final ArrayList<RequestSummary> mList = new ArrayList<>(MAX_SIZE);
+
+ /**
+ * Append an added location request to the history
+ */
+ @VisibleForTesting
+ void addRequest(String packageName, String providerName, long intervalMs) {
+ addRequestSummary(new RequestSummary(packageName, providerName, intervalMs));
+ }
+
+ /**
+ * Append a removed location request to the history
+ */
+ @VisibleForTesting
+ void removeRequest(String packageName, String providerName) {
+ addRequestSummary(new RequestSummary(
+ packageName, providerName, RequestSummary.REQUEST_ENDED_INTERVAL));
+ }
+
+ private void addRequestSummary(RequestSummary summary) {
+ while (mList.size() >= MAX_SIZE) {
+ mList.remove(0);
+ }
+ mList.add(summary);
+ }
+
+ /**
+ * Dump history to a printwriter (for dumpsys location)
+ */
+ public void dump(IndentingPrintWriter ipw) {
+ long systemElapsedOffsetMillis = System.currentTimeMillis()
+ - SystemClock.elapsedRealtime();
+
+ ipw.println("Last Several Location Requests:");
+ ipw.increaseIndent();
+
+ for (RequestSummary requestSummary : mList) {
+ requestSummary.dump(ipw, systemElapsedOffsetMillis);
+ }
+
+ ipw.decreaseIndent();
+ }
+ }
+
+ /**
+ * A data structure to hold a single request
+ */
+ static class RequestSummary {
+ /**
+ * Name of package requesting location.
+ */
+ private final String mPackageName;
+ /**
+ * Name of provider being requested (e.g. "gps").
+ */
+ private final String mProviderName;
+ /**
+ * Interval Requested, or REQUEST_ENDED_INTERVAL indicating request has ended
+ */
+ private final long mIntervalMillis;
+ /**
+ * Elapsed time of request
+ */
+ private final long mElapsedRealtimeMillis;
+
+ /**
+ * Placeholder for requested ending (other values indicate request started/changed)
+ */
+ static final long REQUEST_ENDED_INTERVAL = -1;
+
+ RequestSummary(String packageName, String providerName, long intervalMillis) {
+ this.mPackageName = packageName;
+ this.mProviderName = providerName;
+ this.mIntervalMillis = intervalMillis;
+ this.mElapsedRealtimeMillis = SystemClock.elapsedRealtime();
+ }
+
+ void dump(IndentingPrintWriter ipw, long systemElapsedOffsetMillis) {
+ StringBuilder s = new StringBuilder();
+ long systemTimeMillis = systemElapsedOffsetMillis + mElapsedRealtimeMillis;
+ s.append("At ").append(TimeUtils.formatForLogging(systemTimeMillis)).append(": ")
+ .append(mIntervalMillis == REQUEST_ENDED_INTERVAL ? "- " : "+ ")
+ .append(String.format("%7s", mProviderName)).append(" request from ")
+ .append(mPackageName);
+ if (mIntervalMillis != REQUEST_ENDED_INTERVAL) {
+ s.append(" at interval ").append(mIntervalMillis / 1000).append(" seconds");
+ }
+ ipw.println(s);
+ }
+ }
+
+ /**
* Usage statistics for a package/provider pair.
*/
public static class PackageStatistics {
diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/LocationSettingsStore.java
index f625452975c0..0e8720ebb08f 100644
--- a/services/core/java/com/android/server/location/LocationSettingsStore.java
+++ b/services/core/java/com/android/server/location/LocationSettingsStore.java
@@ -16,6 +16,8 @@
package com.android.server.location;
+import static android.location.LocationManager.FUSED_PROVIDER;
+import static android.location.LocationManager.PASSIVE_PROVIDER;
import static android.provider.Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS;
import static android.provider.Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST;
import static android.provider.Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS;
@@ -28,6 +30,7 @@ import android.app.ActivityManager;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
+import android.os.Binder;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
@@ -248,6 +251,9 @@ public class LocationSettingsStore {
DEFAULT_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS);
}
+ /**
+ * Retrieve maximum age of the last location.
+ */
public long getMaxLastLocationAgeMs() {
return Settings.Global.getLong(
mContext.getContentResolver(),
@@ -256,6 +262,29 @@ public class LocationSettingsStore {
}
/**
+ * Set a value for the deprecated LOCATION_PROVIDERS_ALLOWED setting. This is used purely for
+ * backwards compatibility for old clients, and may be removed in the future.
+ */
+ public void setLocationProviderAllowed(String provider, boolean enabled, int userId) {
+ // fused and passive provider never get public updates for legacy reasons
+ if (FUSED_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
+ return;
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ (enabled ? "+" : "-") + provider,
+ userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
* Dump info for debugging.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index 472876bfd86a..60c9fc12c201 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -19,7 +19,6 @@ package com.android.server.location;
import android.annotation.Nullable;
import android.content.Context;
import android.location.Location;
-import android.os.WorkSource;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -34,41 +33,33 @@ import java.io.PrintWriter;
*/
public class MockProvider extends AbstractLocationProvider {
- private boolean mEnabled;
@Nullable private Location mLocation;
- public MockProvider(Context context,
- LocationProviderManager locationProviderManager, ProviderProperties properties) {
- super(context, locationProviderManager);
-
- mEnabled = true;
- mLocation = null;
-
+ public MockProvider(Context context, ProviderProperties properties) {
+ // using a direct executor is only acceptable because this class is so simple it is trivial
+ // to verify that it does not acquire any locks or re-enter LMS from callbacks
+ super(context, Runnable::run);
setProperties(properties);
}
/** Sets the enabled state of this mock provider. */
- public void setEnabled(boolean enabled) {
- mEnabled = enabled;
- super.setEnabled(enabled);
+ public void setProviderEnabled(boolean enabled) {
+ setEnabled(enabled);
}
/** Sets the location to report for this mock provider. */
- public void setLocation(Location l) {
- mLocation = new Location(l);
- if (!mLocation.isFromMockProvider()) {
- mLocation.setIsFromMockProvider(true);
- }
- if (mEnabled) {
- reportLocation(mLocation);
- }
+ public void setProviderLocation(Location l) {
+ Location location = new Location(l);
+ location.setIsFromMockProvider(true);
+ mLocation = location;
+ reportLocation(location);
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("last location=" + mLocation);
+ pw.println("last mock location=" + mLocation);
}
@Override
- public void onSetRequest(ProviderRequest request, WorkSource source) {}
+ public void onSetRequest(ProviderRequest request) {}
}
diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java
new file mode 100644
index 000000000000..f50dfe7edbb7
--- /dev/null
+++ b/services/core/java/com/android/server/location/MockableLocationProvider.java
@@ -0,0 +1,289 @@
+/*
+ * 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 com.android.server.location;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.location.Location;
+import android.os.Bundle;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.location.ProviderRequest;
+import com.android.internal.util.Preconditions;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents a location provider that may switch between a mock implementation and a real
+ * implementation. Requires owners to provide a lock object that will be used internally and held
+ * for the duration of all listener callbacks. Owners are reponsible for ensuring this cannot lead
+ * to deadlock.
+ *
+ * In order to ensure deadlock does not occur, the owner must validate that the ONLY lock which can
+ * be held BOTH when calling into this class AND when receiving a callback from this class is the
+ * lock given to this class via the constructor. Holding any other lock is ok as long as there is no
+ * possibility that it can be obtained within both codepaths.
+ *
+ * Holding the given lock guarantees atomicity of any operations on this class for the duration.
+ *
+ * @hide
+ */
+public class MockableLocationProvider extends AbstractLocationProvider {
+
+ private final Object mOwnerLock;
+
+ @GuardedBy("mOwnerLock")
+ @Nullable private AbstractLocationProvider mProvider;
+ @GuardedBy("mOwnerLock")
+ @Nullable private AbstractLocationProvider mRealProvider;
+ @GuardedBy("mOwnerLock")
+ @Nullable private MockProvider mMockProvider;
+
+ @GuardedBy("mOwnerLock")
+ private ProviderRequest mRequest;
+
+ /**
+ * The given lock object will be held any time the listener is invoked, and may also be acquired
+ * and released during the course of invoking any public methods. Holding the given lock ensures
+ * that provider state cannot change except as result of an explicit call by the owner of the
+ * lock into this class. The client is reponsible for ensuring this cannot cause deadlock.
+ *
+ * The client should expect that it may being to receive callbacks as soon as this constructor
+ * is invoked.
+ */
+ public MockableLocationProvider(Context context, Object ownerLock, Listener listener) {
+ // using a direct executor is acceptable because all inbound calls are delegated to the
+ // actual provider implementations which will use their own executors
+ super(context, Runnable::run, Collections.emptySet());
+ mOwnerLock = ownerLock;
+ mRequest = ProviderRequest.EMPTY_REQUEST;
+
+ setListener(listener);
+ }
+
+ /**
+ * Returns the current provider implementation. May be null if there is no current
+ * implementation.
+ */
+ @Nullable
+ public AbstractLocationProvider getProvider() {
+ synchronized (mOwnerLock) {
+ return mProvider;
+ }
+ }
+
+ /**
+ * Sets the real provider implementation, replacing any previous real provider implementation.
+ * May cause an inline invocation of {@link Listener#onStateChanged(State, State)} if this
+ * results in a state change.
+ */
+ public void setRealProvider(@Nullable AbstractLocationProvider provider) {
+ synchronized (mOwnerLock) {
+ if (mRealProvider == provider) {
+ return;
+ }
+
+ mRealProvider = provider;
+ if (!isMock()) {
+ setProviderLocked(mRealProvider);
+ }
+ }
+ }
+
+ /**
+ * Sets the mock provider implementation, replacing any previous mock provider implementation.
+ * Mock implementations are always used instead of real implementations if set. May cause an
+ * inline invocation of {@link Listener#onStateChanged(State, State)} if this results in a
+ * state change.
+ */
+ public void setMockProvider(@Nullable MockProvider provider) {
+ synchronized (mOwnerLock) {
+ if (mMockProvider == provider) {
+ return;
+ }
+
+ mMockProvider = provider;
+ if (mMockProvider != null) {
+ setProviderLocked(mMockProvider);
+ } else {
+ setProviderLocked(mRealProvider);
+ }
+ }
+ }
+
+ @GuardedBy("mOwnerLock")
+ private void setProviderLocked(@Nullable AbstractLocationProvider provider) {
+ if (mProvider == provider) {
+ return;
+ }
+
+ AbstractLocationProvider oldProvider = mProvider;
+ mProvider = provider;
+
+ if (oldProvider != null) {
+ // do this after switching the provider - so even if the old provider is using a direct
+ // executor, if it re-enters this class within setRequest(), it will be ignored
+ oldProvider.setListener(null);
+ oldProvider.setRequest(ProviderRequest.EMPTY_REQUEST);
+ }
+
+ State newState;
+ if (mProvider != null) {
+ newState = mProvider.setListener(new ListenerWrapper(mProvider));
+ } else {
+ newState = State.EMPTY_STATE;
+ }
+
+ ProviderRequest oldRequest = mRequest;
+ setState(newState);
+
+ if (mProvider != null && oldRequest == mRequest) {
+ mProvider.setRequest(mRequest);
+ }
+ }
+
+ /**
+ * Returns true if the current active provider implementation is the mock implementation, and
+ * false otherwise.
+ */
+ public boolean isMock() {
+ synchronized (mOwnerLock) {
+ return mMockProvider != null && mProvider == mMockProvider;
+ }
+ }
+
+ /**
+ * Sets the mock provider implementation's enabled state. Will throw an exception if the mock
+ * provider is not currently the active implementation.
+ */
+ public void setMockProviderEnabled(boolean enabled) {
+ synchronized (mOwnerLock) {
+ Preconditions.checkState(isMock());
+ mMockProvider.setProviderEnabled(enabled);
+ }
+ }
+ /**
+ * Sets the mock provider implementation's location. Will throw an exception if the mock
+ * provider is not currently the active implementation.
+ */
+ public void setMockProviderLocation(Location location) {
+ synchronized (mOwnerLock) {
+ Preconditions.checkState(isMock());
+ mMockProvider.setProviderLocation(location);
+ }
+ }
+
+ @Override
+ public State getState() {
+ return super.getState();
+ }
+
+ /**
+ * Returns the current location request.
+ */
+ public ProviderRequest getCurrentRequest() {
+ synchronized (mOwnerLock) {
+ return mRequest;
+ }
+ }
+
+ protected void onSetRequest(ProviderRequest request) {
+ synchronized (mOwnerLock) {
+ if (request == mRequest) {
+ return;
+ }
+
+ mRequest = request;
+
+ if (mProvider != null) {
+ mProvider.setRequest(request);
+ }
+ }
+ }
+
+ protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {
+ synchronized (mOwnerLock) {
+ if (mProvider != null) {
+ mProvider.sendExtraCommand(uid, pid, command, extras);
+ }
+ }
+ }
+
+ /**
+ * Dumps the current provider implementation.
+ */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ AbstractLocationProvider provider;
+ synchronized (mOwnerLock) {
+ provider = mProvider;
+ pw.println("request=" + mRequest);
+ }
+
+ if (provider != null) {
+ // dump outside the lock in case the provider wants to acquire its own locks, and since
+ // the default provider dump behavior does not move things onto the provider thread...
+ provider.dump(fd, pw, args);
+ }
+ }
+
+ // ensures that callbacks from the incorrect provider are never visible to clients - this
+ // requires holding the owner's lock for the duration of the callback
+ private class ListenerWrapper implements Listener {
+
+ private final AbstractLocationProvider mListenerProvider;
+
+ private ListenerWrapper(AbstractLocationProvider listenerProvider) {
+ mListenerProvider = listenerProvider;
+ }
+
+ @Override
+ public final void onStateChanged(State oldState, State newState) {
+ synchronized (mOwnerLock) {
+ if (mListenerProvider != mProvider) {
+ return;
+ }
+
+ setState(newState);
+ }
+ }
+
+ @Override
+ public final void onReportLocation(Location location) {
+ synchronized (mOwnerLock) {
+ if (mListenerProvider != mProvider) {
+ return;
+ }
+
+ reportLocation(location);
+ }
+ }
+
+ @Override
+ public final void onReportLocation(List<Location> locations) {
+ synchronized (mOwnerLock) {
+ if (mListenerProvider != mProvider) {
+ return;
+ }
+
+ reportLocation(locations);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index 639b1eb1ed5e..b33877069d70 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -19,7 +19,6 @@ package com.android.server.location;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
-import android.os.WorkSource;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -37,13 +36,22 @@ import java.io.PrintWriter;
public class PassiveProvider extends AbstractLocationProvider {
private static final ProviderProperties PROPERTIES = new ProviderProperties(
- false, false, false, false, false, false, false,
- Criteria.POWER_LOW, Criteria.ACCURACY_COARSE);
+ /* requiresNetwork = */false,
+ /* requiresSatellite = */false,
+ /* requiresCell = */false,
+ /* hasMonetaryCost = */false,
+ /* supportsAltitude = */false,
+ /* supportsSpeed = */false,
+ /* supportsBearing = */false,
+ Criteria.POWER_LOW,
+ Criteria.ACCURACY_COARSE);
- private boolean mReportLocation;
+ private volatile boolean mReportLocation;
- public PassiveProvider(Context context, LocationProviderManager locationProviderManager) {
- super(context, locationProviderManager);
+ public PassiveProvider(Context context) {
+ // using a direct executor is only acceptable because this class is so simple it is trivial
+ // to verify that it does not acquire any locks or re-enter LMS from callbacks
+ super(context, Runnable::run);
mReportLocation = false;
@@ -52,7 +60,7 @@ public class PassiveProvider extends AbstractLocationProvider {
}
@Override
- public void onSetRequest(ProviderRequest request, WorkSource source) {
+ public void onSetRequest(ProviderRequest request) {
mReportLocation = request.reportLocation;
}
@@ -63,7 +71,5 @@ public class PassiveProvider extends AbstractLocationProvider {
}
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("report location=" + mReportLocation);
- }
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 115155ce24b5..9c9a4121830f 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
-import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.RouteSessionInfo;
@@ -47,16 +46,16 @@ abstract class MediaRoute2Provider {
}
public abstract void requestCreateSession(String packageName, String routeId,
- String controlCategory, long requestId);
- public abstract void releaseSession(int sessionId);
+ String routeType, long requestId);
+ public abstract void releaseSession(String sessionId);
- public abstract void selectRoute(int sessionId, MediaRoute2Info route);
- public abstract void deselectRoute(int sessionId, MediaRoute2Info route);
- public abstract void transferToRoute(int sessionId, MediaRoute2Info route);
+ public abstract void selectRoute(String sessionId, String routeId);
+ public abstract void deselectRoute(String sessionId, String routeId);
+ public abstract void transferToRoute(String sessionId, String routeId);
- public abstract void sendControlRequest(MediaRoute2Info route, Intent request);
- public abstract void requestSetVolume(MediaRoute2Info route, int volume);
- public abstract void requestUpdateVolume(MediaRoute2Info route, int delta);
+ public abstract void sendControlRequest(String routeId, Intent request);
+ public abstract void requestSetVolume(String routeId, int volume);
+ public abstract void requestUpdateVolume(String routeId, int delta);
@NonNull
public String getUniqueId() {
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index f8d8f9fd5fbd..635983575226 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -24,7 +24,6 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.media.IMediaRoute2Provider;
import android.media.IMediaRoute2ProviderClient;
-import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
import android.media.RouteSessionInfo;
@@ -77,17 +76,17 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
}
@Override
- public void requestCreateSession(String packageName, String routeId, String controlCategory,
+ public void requestCreateSession(String packageName, String routeId, String routeType,
long requestId) {
if (mConnectionReady) {
- mActiveConnection.requestCreateSession(packageName, routeId, controlCategory,
+ mActiveConnection.requestCreateSession(packageName, routeId, routeType,
requestId);
updateBinding();
}
}
@Override
- public void releaseSession(int sessionId) {
+ public void releaseSession(String sessionId) {
if (mConnectionReady) {
mActiveConnection.releaseSession(sessionId);
updateBinding();
@@ -95,46 +94,46 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
}
@Override
- public void selectRoute(int sessionId, MediaRoute2Info route) {
+ public void selectRoute(String sessionId, String routeId) {
if (mConnectionReady) {
- mActiveConnection.selectRoute(sessionId, route.getId());
+ mActiveConnection.selectRoute(sessionId, routeId);
}
}
@Override
- public void deselectRoute(int sessionId, MediaRoute2Info route) {
+ public void deselectRoute(String sessionId, String routeId) {
if (mConnectionReady) {
- mActiveConnection.deselectRoute(sessionId, route.getId());
+ mActiveConnection.deselectRoute(sessionId, routeId);
}
}
@Override
- public void transferToRoute(int sessionId, MediaRoute2Info route) {
+ public void transferToRoute(String sessionId, String routeId) {
if (mConnectionReady) {
- mActiveConnection.transferToRoute(sessionId, route.getId());
+ mActiveConnection.transferToRoute(sessionId, routeId);
}
}
@Override
- public void sendControlRequest(MediaRoute2Info route, Intent request) {
+ public void sendControlRequest(String routeId, Intent request) {
if (mConnectionReady) {
- mActiveConnection.sendControlRequest(route.getId(), request);
+ mActiveConnection.sendControlRequest(routeId, request);
updateBinding();
}
}
@Override
- public void requestSetVolume(MediaRoute2Info route, int volume) {
+ public void requestSetVolume(String routeId, int volume) {
if (mConnectionReady) {
- mActiveConnection.requestSetVolume(route.getId(), volume);
+ mActiveConnection.requestSetVolume(routeId, volume);
updateBinding();
}
}
@Override
- public void requestUpdateVolume(MediaRoute2Info route, int delta) {
+ public void requestUpdateVolume(String routeId, int delta) {
if (mConnectionReady) {
- mActiveConnection.requestUpdateVolume(route.getId(), delta);
+ mActiveConnection.requestUpdateVolume(routeId, delta);
updateBinding();
}
}
@@ -303,6 +302,11 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
+ mComponentName);
return;
}
+
+ sessionInfo = new RouteSessionInfo.Builder(sessionInfo)
+ .setProviderId(getUniqueId())
+ .build();
+
mCallback.onSessionInfoChanged(this, sessionInfo);
}
@@ -346,17 +350,17 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
mClient.dispose();
}
- public void requestCreateSession(String packageName, String routeId, String controlCategory,
+ public void requestCreateSession(String packageName, String routeId, String routeType,
long requestId) {
try {
mProvider.requestCreateSession(packageName, routeId,
- controlCategory, requestId);
+ routeType, requestId);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to deliver request to create a session.", ex);
}
}
- public void releaseSession(int sessionId) {
+ public void releaseSession(String sessionId) {
try {
mProvider.releaseSession(sessionId);
} catch (RemoteException ex) {
@@ -364,7 +368,7 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
}
}
- public void selectRoute(int sessionId, String routeId) {
+ public void selectRoute(String sessionId, String routeId) {
try {
mProvider.selectRoute(sessionId, routeId);
} catch (RemoteException ex) {
@@ -372,7 +376,7 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
}
}
- public void deselectRoute(int sessionId, String routeId) {
+ public void deselectRoute(String sessionId, String routeId) {
try {
mProvider.deselectRoute(sessionId, routeId);
} catch (RemoteException ex) {
@@ -380,7 +384,7 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
}
}
- public void transferToRoute(int sessionId, String routeId) {
+ public void transferToRoute(String sessionId, String routeId) {
try {
mProvider.transferToRoute(sessionId, routeId);
} catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 562a7200fb38..487ab5201278 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,6 +16,9 @@
package com.android.server.media;
+import static android.media.MediaRouter2Utils.getOriginalId;
+import static android.media.MediaRouter2Utils.getProviderId;
+
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.NonNull;
@@ -28,6 +31,7 @@ import android.media.IMediaRouter2Client;
import android.media.IMediaRouter2Manager;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
+import android.media.RouteDiscoveryRequest;
import android.media.RouteSessionInfo;
import android.os.Binder;
import android.os.Bundle;
@@ -174,18 +178,18 @@ class MediaRouter2ServiceImpl {
}
public void requestCreateSession(IMediaRouter2Client client, MediaRoute2Info route,
- String controlCategory, int requestId) {
+ String routeType, int requestId) {
Objects.requireNonNull(client, "client must not be null");
Objects.requireNonNull(route, "route must not be null");
- if (TextUtils.isEmpty(controlCategory)) {
- throw new IllegalArgumentException("controlCategory must not be empty");
+ if (TextUtils.isEmpty(routeType)) {
+ throw new IllegalArgumentException("routeType must not be empty");
}
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- requestCreateSessionLocked(client, route, controlCategory, requestId);
+ requestCreateSessionLocked(client, route, routeType, requestId);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -196,6 +200,9 @@ class MediaRouter2ServiceImpl {
MediaRoute2Info route) {
Objects.requireNonNull(client, "client must not be null");
Objects.requireNonNull(route, "route must not be null");
+ if (TextUtils.isEmpty(uniqueSessionId)) {
+ throw new IllegalArgumentException("uniqueSessionId must not be empty");
+ }
final long token = Binder.clearCallingIdentity();
try {
@@ -212,6 +219,9 @@ class MediaRouter2ServiceImpl {
MediaRoute2Info route) {
Objects.requireNonNull(client, "client must not be null");
Objects.requireNonNull(route, "route must not be null");
+ if (TextUtils.isEmpty(uniqueSessionId)) {
+ throw new IllegalArgumentException("uniqueSessionId must not be empty");
+ }
final long token = Binder.clearCallingIdentity();
try {
@@ -227,6 +237,9 @@ class MediaRouter2ServiceImpl {
MediaRoute2Info route) {
Objects.requireNonNull(client, "client must not be null");
Objects.requireNonNull(route, "route must not be null");
+ if (TextUtils.isEmpty(uniqueSessionId)) {
+ throw new IllegalArgumentException("uniqueSessionId must not be empty");
+ }
final long token = Binder.clearCallingIdentity();
try {
@@ -240,6 +253,9 @@ class MediaRouter2ServiceImpl {
public void releaseSession(IMediaRouter2Client client, String uniqueSessionId) {
Objects.requireNonNull(client, "client must not be null");
+ if (TextUtils.isEmpty(uniqueSessionId)) {
+ throw new IllegalArgumentException("uniqueSessionId must not be empty");
+ }
final long token = Binder.clearCallingIdentity();
try {
@@ -267,16 +283,16 @@ class MediaRouter2ServiceImpl {
}
}
- public void setControlCategories(@NonNull IMediaRouter2Client client,
- @NonNull List<String> categories) {
+ public void setDiscoveryRequest2(@NonNull IMediaRouter2Client client,
+ @NonNull RouteDiscoveryRequest request) {
Objects.requireNonNull(client, "client must not be null");
- Objects.requireNonNull(categories, "categories must not be null");
+ Objects.requireNonNull(request, "request must not be null");
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
Client2Record clientRecord = mAllClientRecords.get(client.asBinder());
- setControlCategoriesLocked(clientRecord, categories);
+ setDiscoveryRequestLocked(clientRecord, request);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -434,7 +450,7 @@ class MediaRouter2ServiceImpl {
}
private void requestCreateSessionLocked(@NonNull IMediaRouter2Client client,
- @NonNull MediaRoute2Info route, @NonNull String controlCategory, long requestId) {
+ @NonNull MediaRoute2Info route, @NonNull String routeType, long requestId) {
final IBinder binder = client.asBinder();
final Client2Record clientRecord = mAllClientRecords.get(binder);
@@ -447,7 +463,7 @@ class MediaRouter2ServiceImpl {
clientRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::requestCreateSessionOnHandler,
clientRecord.mUserRecord.mHandler,
- clientRecord, route, controlCategory, requestId));
+ clientRecord, route, routeType, requestId));
}
}
@@ -502,13 +518,14 @@ class MediaRouter2ServiceImpl {
}
}
- private void setControlCategoriesLocked(Client2Record clientRecord, List<String> categories) {
+ private void setDiscoveryRequestLocked(Client2Record clientRecord,
+ RouteDiscoveryRequest discoveryRequest) {
if (clientRecord != null) {
- if (clientRecord.mControlCategories.equals(categories)) {
+ if (clientRecord.mDiscoveryRequest.equals(discoveryRequest)) {
return;
}
- clientRecord.mControlCategories = categories;
+ clientRecord.mDiscoveryRequest = discoveryRequest;
clientRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::updateClientUsage,
clientRecord.mUserRecord.mHandler, clientRecord));
@@ -605,9 +622,9 @@ class MediaRouter2ServiceImpl {
}
long uniqueRequestId = toUniqueRequestId(managerRecord.mClientId, requestId);
if (clientRecord != null && managerRecord.mTrusted) {
- //TODO: select category properly
+ //TODO: select route type properly
requestCreateSessionLocked(clientRecord.mClient, route,
- route.getSupportedCategories().get(0), uniqueRequestId);
+ route.getRouteTypes().get(0), uniqueRequestId);
}
}
}
@@ -725,7 +742,7 @@ class MediaRouter2ServiceImpl {
public final boolean mTrusted;
public final int mClientId;
- public List<String> mControlCategories;
+ public RouteDiscoveryRequest mDiscoveryRequest;
public boolean mIsManagerSelecting;
public MediaRoute2Info mSelectingRoute;
public MediaRoute2Info mSelectedRoute;
@@ -735,7 +752,7 @@ class MediaRouter2ServiceImpl {
mUserRecord = userRecord;
mPackageName = packageName;
mSelectRouteSequenceNumbers = new ArrayList<>();
- mControlCategories = Collections.emptyList();
+ mDiscoveryRequest = RouteDiscoveryRequest.EMPTY;
mClient = client;
mUid = uid;
mPid = pid;
@@ -961,7 +978,7 @@ class MediaRouter2ServiceImpl {
}
private void requestCreateSessionOnHandler(Client2Record clientRecord,
- MediaRoute2Info route, String controlCategory, long requestId) {
+ MediaRoute2Info route, String routeType, long requestId) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider == null) {
@@ -971,20 +988,20 @@ class MediaRouter2ServiceImpl {
return;
}
- if (!route.getSupportedCategories().contains(controlCategory)) {
+ if (!route.getRouteTypes().contains(routeType)) {
Slog.w(TAG, "Ignoring session creation request since the given route=" + route
- + " doesn't support the given category=" + controlCategory);
+ + " doesn't support the given type=" + routeType);
notifySessionCreationFailed(clientRecord, toClientRequestId(requestId));
return;
}
// TODO: Apply timeout for each request (How many seconds should we wait?)
SessionCreationRequest request = new SessionCreationRequest(
- clientRecord, route, controlCategory, requestId);
+ clientRecord, route, routeType, requestId);
mSessionCreationRequests.add(request);
- provider.requestCreateSession(clientRecord.mPackageName, route.getId(),
- controlCategory, requestId);
+ provider.requestCreateSession(clientRecord.mPackageName, route.getOriginalId(),
+ routeType, requestId);
}
private void selectRouteOnHandler(@NonNull Client2Record clientRecord,
@@ -1000,7 +1017,7 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.selectRoute(RouteSessionInfo.getSessionId(uniqueSessionId), route);
+ provider.selectRoute(getOriginalId(uniqueSessionId), route.getOriginalId());
}
private void deselectRouteOnHandler(@NonNull Client2Record clientRecord,
@@ -1016,7 +1033,7 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.deselectRoute(RouteSessionInfo.getSessionId(uniqueSessionId), route);
+ provider.deselectRoute(getOriginalId(uniqueSessionId), route.getOriginalId());
}
private void transferToRouteOnHandler(@NonNull Client2Record clientRecord,
@@ -1032,7 +1049,8 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.transferToRoute(RouteSessionInfo.getSessionId(uniqueSessionId), route);
+ provider.transferToRoute(getOriginalId(uniqueSessionId),
+ route.getOriginalId());
}
private boolean checkArgumentsForSessionControl(@NonNull Client2Record clientRecord,
@@ -1063,9 +1081,9 @@ class MediaRouter2ServiceImpl {
return false;
}
- final Integer sessionId = RouteSessionInfo.getSessionId(uniqueSessionId);
+ final String sessionId = getOriginalId(uniqueSessionId);
if (sessionId == null) {
- Slog.w(TAG, "Failed to get int session id from unique session id. "
+ Slog.w(TAG, "Failed to get original session id from unique session id. "
+ "uniqueSessionId=" + uniqueSessionId);
return false;
}
@@ -1088,14 +1106,14 @@ class MediaRouter2ServiceImpl {
return;
}
- final String providerId = RouteSessionInfo.getProviderId(uniqueSessionId);
+ final String providerId = getProviderId(uniqueSessionId);
if (providerId == null) {
Slog.w(TAG, "Ignoring releasing session with invalid unique session ID. "
+ "uniqueSessionId=" + uniqueSessionId);
return;
}
- final Integer sessionId = RouteSessionInfo.getSessionId(uniqueSessionId);
+ final String sessionId = getOriginalId(uniqueSessionId);
if (sessionId == null) {
Slog.w(TAG, "Ignoring releasing session with invalid unique session ID. "
+ "uniqueSessionId=" + uniqueSessionId + " providerId=" + providerId);
@@ -1141,15 +1159,15 @@ class MediaRouter2ServiceImpl {
}
String originalRouteId = matchingRequest.mRoute.getId();
- String originalCategory = matchingRequest.mControlCategory;
+ String originalRouteType = matchingRequest.mRouteType;
Client2Record client2Record = matchingRequest.mClientRecord;
if (!sessionInfo.getSelectedRoutes().contains(originalRouteId)
- || !TextUtils.equals(originalCategory,
- sessionInfo.getControlCategory())) {
+ || !TextUtils.equals(originalRouteType,
+ sessionInfo.getRouteType())) {
Slog.w(TAG, "Created session doesn't match the original request."
+ " originalRouteId=" + originalRouteId
- + ", originalCategory=" + originalCategory + ", requestId=" + requestId
+ + ", originalRouteType=" + originalRouteType + ", requestId=" + requestId
+ ", sessionInfo=" + sessionInfo);
notifySessionCreationFailed(matchingRequest.mClientRecord,
toClientRequestId(requestId));
@@ -1159,41 +1177,34 @@ class MediaRouter2ServiceImpl {
// Succeeded
notifySessionCreated(matchingRequest.mClientRecord,
sessionInfo, toClientRequestId(requestId));
- mSessionToClientMap.put(sessionInfo.getUniqueSessionId(), client2Record);
+ mSessionToClientMap.put(sessionInfo.getId(), client2Record);
// TODO: Tell managers for the session creation
}
private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
@NonNull RouteSessionInfo sessionInfo) {
- RouteSessionInfo sessionInfoWithProviderId = new RouteSessionInfo.Builder(sessionInfo)
- .setProviderId(provider.getUniqueId())
- .build();
Client2Record client2Record = mSessionToClientMap.get(
- sessionInfoWithProviderId.getUniqueSessionId());
+ sessionInfo.getId());
if (client2Record == null) {
- Slog.w(TAG, "No matching client found for session=" + sessionInfoWithProviderId);
+ Slog.w(TAG, "No matching client found for session=" + sessionInfo);
// TODO: Tell managers for the session update
return;
}
- notifySessionInfoChanged(client2Record, sessionInfoWithProviderId);
+ notifySessionInfoChanged(client2Record, sessionInfo);
// TODO: Tell managers for the session update
}
private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider,
@NonNull RouteSessionInfo sessionInfo) {
- RouteSessionInfo sessionInfoWithProviderId = new RouteSessionInfo.Builder(sessionInfo)
- .setProviderId(provider.getUniqueId())
- .build();
- Client2Record client2Record = mSessionToClientMap.get(
- sessionInfoWithProviderId.getUniqueSessionId());
+ Client2Record client2Record = mSessionToClientMap.get(sessionInfo.getId());
if (client2Record == null) {
- Slog.w(TAG, "No matching client found for session=" + sessionInfoWithProviderId);
+ Slog.w(TAG, "No matching client found for session=" + sessionInfo);
// TODO: Tell managers for the session release
return;
}
- notifySessionReleased(client2Record, sessionInfoWithProviderId);
+ notifySessionReleased(client2Record, sessionInfo);
// TODO: Tell managers for the session release
}
@@ -1239,21 +1250,21 @@ class MediaRouter2ServiceImpl {
private void sendControlRequest(MediaRoute2Info route, Intent request) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider != null) {
- provider.sendControlRequest(route, request);
+ provider.sendControlRequest(route.getOriginalId(), request);
}
}
private void requestSetVolume(MediaRoute2Info route, int volume) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider != null) {
- provider.requestSetVolume(route, volume);
+ provider.requestSetVolume(route.getOriginalId(), volume);
}
}
private void requestUpdateVolume(MediaRoute2Info route, int delta) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider != null) {
- provider.requestUpdateVolume(route, delta);
+ provider.requestUpdateVolume(route.getOriginalId(), delta);
}
}
@@ -1401,8 +1412,8 @@ class MediaRouter2ServiceImpl {
try {
manager.notifyRouteSelected(clientRecord.mPackageName,
clientRecord.mSelectedRoute);
- manager.notifyControlCategoriesChanged(clientRecord.mPackageName,
- clientRecord.mControlCategories);
+ manager.notifyRouteTypesChanged(clientRecord.mPackageName,
+ clientRecord.mDiscoveryRequest.getRouteTypes());
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to update client usage. Manager probably died.", ex);
}
@@ -1421,15 +1432,15 @@ class MediaRouter2ServiceImpl {
final class SessionCreationRequest {
public final Client2Record mClientRecord;
public final MediaRoute2Info mRoute;
- public final String mControlCategory;
+ public final String mRouteType;
public final long mRequestId;
SessionCreationRequest(@NonNull Client2Record clientRecord,
@NonNull MediaRoute2Info route,
- @NonNull String controlCategory, long requestId) {
+ @NonNull String routeType, long requestId) {
mClientRecord = clientRecord;
mRoute = route;
- mControlCategory = controlCategory;
+ mRouteType = routeType;
mRequestId = requestId;
}
}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index d77f43b4435d..c76555cf15cf 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -39,6 +39,7 @@ import android.media.MediaRouter;
import android.media.MediaRouterClientState;
import android.media.RemoteDisplayState;
import android.media.RemoteDisplayState.RemoteDisplayInfo;
+import android.media.RouteDiscoveryRequest;
import android.media.RouteSessionInfo;
import android.os.Binder;
import android.os.Handler;
@@ -459,8 +460,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
public void requestCreateSession(IMediaRouter2Client client, MediaRoute2Info route,
- String controlCategory, int requestId) {
- mService2.requestCreateSession(client, route, controlCategory, requestId);
+ String routeType, int requestId) {
+ mService2.requestCreateSession(client, route, routeType, requestId);
}
// Binder call
@@ -519,8 +520,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub
}
// Binder call
@Override
- public void setControlCategories(IMediaRouter2Client client, List<String> categories) {
- mService2.setControlCategories(client, categories);
+ public void setDiscoveryRequest2(IMediaRouter2Client client, RouteDiscoveryRequest request) {
+ mService2.setDiscoveryRequest2(client, request);
}
// Binder call
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
new file mode 100644
index 000000000000..f3241ee44569
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 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 com.android.server.media;
+
+import android.media.MediaController2;
+import android.media.Session2CommandGroup;
+import android.media.Session2Token;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+
+/**
+ * Keeps the record of {@link Session2Token} helps to send command to the corresponding session.
+ */
+// TODO(jaewan): Do not call service method directly -- introduce listener instead.
+public class MediaSession2Record implements MediaSessionRecordImpl {
+ private static final String TAG = "MediaSession2Record";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final Session2Token mSessionToken;
+ @GuardedBy("mLock")
+ private final HandlerExecutor mHandlerExecutor;
+ @GuardedBy("mLock")
+ private final MediaController2 mController;
+ @GuardedBy("mLock")
+ private final MediaSessionService mService;
+ @GuardedBy("mLock")
+ private boolean mIsConnected;
+
+ public MediaSession2Record(Session2Token sessionToken, MediaSessionService service,
+ Looper handlerLooper) {
+ mSessionToken = sessionToken;
+ mService = service;
+ mHandlerExecutor = new HandlerExecutor(new Handler(handlerLooper));
+ mController = new MediaController2.Builder(service.getContext(), sessionToken)
+ .setControllerCallback(mHandlerExecutor, new Controller2Callback())
+ .build();
+ }
+
+ @Override
+ public String getPackageName() {
+ return mSessionToken.getPackageName();
+ }
+
+ public Session2Token getSession2Token() {
+ return mSessionToken;
+ }
+
+ @Override
+ public int getUid() {
+ return mSessionToken.getUid();
+ }
+
+ @Override
+ public int getUserId() {
+ return UserHandle.getUserId(mSessionToken.getUid());
+ }
+
+ @Override
+ public boolean isSystemPriority() {
+ // System priority session is currently only allowed for telephony, and it's OK to stick to
+ // the media1 API at this moment.
+ return false;
+ }
+
+ @Override
+ public void adjustVolume(String packageName, String opPackageName, int pid, int uid,
+ boolean asSystemService, int direction, int flags, boolean useSuggested) {
+ // TODO(jaewan): Add API to adjust volume.
+ }
+
+ @Override
+ public boolean isActive() {
+ synchronized (mLock) {
+ return mIsConnected;
+ }
+ }
+
+ @Override
+ public boolean checkPlaybackActiveState(boolean expected) {
+ synchronized (mLock) {
+ return mIsConnected && mController.isPlaybackActive() == expected;
+ }
+ }
+
+ @Override
+ public boolean isPlaybackTypeLocal() {
+ // TODO(jaewan): Implement -- need API to know whether the playback is remote or local.
+ return true;
+ }
+
+ @Override
+ public void close() {
+ synchronized (mLock) {
+ // Call close regardless of the mIsAvailable. This may be called when it's not yet
+ // connected.
+ mController.close();
+ }
+ }
+
+ @Override
+ public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
+ KeyEvent ke, int sequenceId, ResultReceiver cb) {
+ // TODO(jaewan): Implement.
+ return false;
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "token=" + mSessionToken);
+ pw.println(prefix + "controller=" + mController);
+
+ final String indent = prefix + " ";
+ pw.println(indent + "playbackActive=" + mController.isPlaybackActive());
+ }
+
+ @Override
+ public String toString() {
+ // TODO(jaewan): Also add getId().
+ return getPackageName() + " (userId=" + getUserId() + ")";
+ }
+
+ private class Controller2Callback extends MediaController2.ControllerCallback {
+ @Override
+ public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
+ if (DEBUG) {
+ Log.d(TAG, "connected to " + mSessionToken + ", allowed=" + allowedCommands);
+ }
+ synchronized (mLock) {
+ mIsConnected = true;
+ }
+ mService.onSessionActiveStateChanged(MediaSession2Record.this);
+ }
+
+ @Override
+ public void onDisconnected(MediaController2 controller) {
+ if (DEBUG) {
+ Log.d(TAG, "disconnected from " + mSessionToken);
+ }
+ synchronized (mLock) {
+ mIsConnected = false;
+ }
+ mService.onSessionDied(MediaSession2Record.this);
+ }
+
+ @Override
+ public void onPlaybackActiveChanged(MediaController2 controller, boolean playbackActive) {
+ if (DEBUG) {
+ Log.d(TAG, "playback active changed, " + mSessionToken + ", active="
+ + playbackActive);
+ }
+ mService.onSessionPlaybackStateChanged(MediaSession2Record.this, playbackActive);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index aa24ed26023a..df115d0f2773 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -56,13 +56,15 @@ import com.android.server.LocalServices;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
* This is the system implementation of a Session. Apps will interact with the
* MediaSession wrapper class instead.
*/
-public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable {
+// TODO(jaewan): Do not call service method directly -- introduce listener instead.
+public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionRecordImpl {
private static final String TAG = "MediaSessionRecord";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -72,6 +74,24 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*/
private static final int OPTIMISTIC_VOLUME_TIMEOUT = 1000;
+ /**
+ * These are states that usually indicate the user took an action and should
+ * bump priority regardless of the old state.
+ */
+ private static final List<Integer> ALWAYS_PRIORITY_STATES = Arrays.asList(
+ PlaybackState.STATE_FAST_FORWARDING,
+ PlaybackState.STATE_REWINDING,
+ PlaybackState.STATE_SKIPPING_TO_PREVIOUS,
+ PlaybackState.STATE_SKIPPING_TO_NEXT);
+ /**
+ * These are states that usually indicate the user took an action if they
+ * were entered from a non-priority state.
+ */
+ private static final List<Integer> TRANSITION_PRIORITY_STATES = Arrays.asList(
+ PlaybackState.STATE_BUFFERING,
+ PlaybackState.STATE_CONNECTING,
+ PlaybackState.STATE_PLAYING);
+
private final MessageHandler mHandler;
private final int mOwnerPid;
@@ -170,6 +190,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*
* @return Info that identifies this session.
*/
+ @Override
public String getPackageName() {
return mPackageName;
}
@@ -188,6 +209,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*
* @return The UID for this session.
*/
+ @Override
public int getUid() {
return mOwnerUid;
}
@@ -197,6 +219,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*
* @return The user id for this session.
*/
+ @Override
public int getUserId() {
return mUserId;
}
@@ -207,6 +230,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*
* @return True if this is a system priority session, false otherwise
*/
+ @Override
public boolean isSystemPriority() {
return (mFlags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
}
@@ -220,7 +244,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
* @param opPackageName The op package that made the original volume request.
* @param pid The pid that made the original volume request.
* @param uid The uid that made the original volume request.
- * @param caller caller binder. can be {@code null} if it's from the volume key.
* @param asSystemService {@code true} if the event sent to the session as if it was come from
* the system service instead of the app process. This helps sessions to distinguish
* between the key injection by the app and key events from the hardware devices.
@@ -318,9 +341,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
/**
* Check if this session has been set to active by the app.
+ * <p>
+ * It's not used to prioritize sessions for dispatching media keys since API 26, but still used
+ * to filter session list in MediaSessionManager#getActiveSessions().
*
* @return True if the session is active, false otherwise.
*/
+ @Override
public boolean isActive() {
return mIsActive && !mDestroyed;
}
@@ -333,6 +360,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
* @param expected True if playback is expected to be active. false otherwise.
* @return True if the session's playback matches with the expectation. false otherwise.
*/
+ @Override
public boolean checkPlaybackActiveState(boolean expected) {
if (mPlaybackState == null) {
return false;
@@ -345,13 +373,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*
* @return {@code true} if the playback is local.
*/
- public boolean isPlaybackLocal() {
+ @Override
+ public boolean isPlaybackTypeLocal() {
return mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
}
@Override
public void binderDied() {
- mService.sessionDied(this);
+ mService.onSessionDied(this);
}
/**
@@ -383,7 +412,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
* @param sequenceId (optional) sequence id. Use this only when a wake lock is needed.
* @param cb (optional) result receiver to receive callback. Use this only when a wake lock is
* needed.
- * @return {@code true} if the attempt to send media button was successfuly.
+ * @return {@code true} if the attempt to send media button was successfully.
* {@code false} otherwise.
*/
public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
@@ -392,6 +421,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
cb);
}
+ @Override
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + mTag + " " + this);
@@ -712,7 +742,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
public void destroySession() throws RemoteException {
final long token = Binder.clearCallingIdentity();
try {
- mService.destroySession(MediaSessionRecord.this);
+ mService.onSessionDied(MediaSessionRecord.this);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -734,7 +764,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
mIsActive = active;
final long token = Binder.clearCallingIdentity();
try {
- mService.updateSession(MediaSessionRecord.this);
+ mService.onSessionActiveStateChanged(MediaSessionRecord.this);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -801,12 +831,16 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
? PlaybackState.STATE_NONE : mPlaybackState.getState();
int newState = state == null
? PlaybackState.STATE_NONE : state.getState();
+ boolean shouldUpdatePriority = ALWAYS_PRIORITY_STATES.contains(newState)
+ || (!TRANSITION_PRIORITY_STATES.contains(oldState)
+ && TRANSITION_PRIORITY_STATES.contains(newState));
synchronized (mLock) {
mPlaybackState = state;
}
final long token = Binder.clearCallingIdentity();
try {
- mService.onSessionPlaystateChanged(MediaSessionRecord.this, oldState, newState);
+ mService.onSessionPlaybackStateChanged(
+ MediaSessionRecord.this, shouldUpdatePriority);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
new file mode 100644
index 000000000000..2cde89a7a6f6
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 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 com.android.server.media;
+
+import android.media.AudioManager;
+import android.os.ResultReceiver;
+import android.view.KeyEvent;
+
+import java.io.PrintWriter;
+
+/**
+ * Common interfaces between {@link MediaSessionRecord} and {@link MediaSession2Record}.
+ */
+public interface MediaSessionRecordImpl extends AutoCloseable {
+
+ /**
+ * Get the info for this session.
+ *
+ * @return Info that identifies this session.
+ */
+ String getPackageName();
+
+ /**
+ * Get the UID this session was created for.
+ *
+ * @return The UID for this session.
+ */
+ int getUid();
+
+ /**
+ * Get the user id this session was created for.
+ *
+ * @return The user id for this session.
+ */
+ int getUserId();
+
+ /**
+ * Check if this session has system priorty and should receive media buttons
+ * before any other sessions.
+ *
+ * @return True if this is a system priority session, false otherwise
+ */
+ boolean isSystemPriority();
+
+ /**
+ * Send a volume adjustment to the session owner. Direction must be one of
+ * {@link AudioManager#ADJUST_LOWER}, {@link AudioManager#ADJUST_RAISE},
+ * {@link AudioManager#ADJUST_SAME}.
+ *
+ * @param packageName The package that made the original volume request.
+ * @param opPackageName The op package that made the original volume request.
+ * @param pid The pid that made the original volume request.
+ * @param uid The uid that made the original volume request.
+ * @param asSystemService {@code true} if the event sent to the session as if it was come from
+ * the system service instead of the app process. This helps sessions to distinguish
+ * between the key injection by the app and key events from the hardware devices.
+ * Should be used only when the volume key events aren't handled by foreground
+ * activity. {@code false} otherwise to tell session about the real caller.
+ * @param direction The direction to adjust volume in.
+ * @param flags Any of the flags from {@link AudioManager}.
+ * @param useSuggested True to use adjustSuggestedStreamVolume instead of
+ */
+ void adjustVolume(String packageName, String opPackageName, int pid, int uid,
+ boolean asSystemService, int direction, int flags, boolean useSuggested);
+
+ /**
+ * Check if this session has been set to active by the app. (i.e. ready to receive command and
+ * getters are available).
+ *
+ * @return True if the session is active, false otherwise.
+ */
+ // TODO(jaewan): Find better naming, or remove this from the MediaSessionRecordImpl.
+ boolean isActive();
+
+ /**
+ * Check if the session's playback active state matches with the expectation. This always return
+ * {@code false} if the playback state is unknown (e.g. {@code null}), where we cannot know the
+ * actual playback state associated with the session.
+ *
+ * @param expected True if playback is expected to be active. false otherwise.
+ * @return True if the session's playback matches with the expectation. false otherwise.
+ */
+ boolean checkPlaybackActiveState(boolean expected);
+
+ /**
+ * Check whether the playback type is local or remote.
+ * <p>
+ * <ul>
+ * <li>Local: volume changes the stream volume because playback happens on this device.</li>
+ * <li>Remote: volume is sent to the apps callback because playback happens on the remote
+ * device and we cannot know how to control the volume of it.</li>
+ * </ul>
+ *
+ * @return {@code true} if the playback is local. {@code false} if the playback is remote.
+ */
+ boolean isPlaybackTypeLocal();
+
+ /**
+ * Sends media button.
+ *
+ * @param packageName caller package name
+ * @param pid caller pid
+ * @param uid caller uid
+ * @param asSystemService {@code true} if the event sent to the session as if it was come from
+ * the system service instead of the app process.
+ * @param ke key events
+ * @param sequenceId (optional) sequence id. Use this only when a wake lock is needed.
+ * @param cb (optional) result receiver to receive callback. Use this only when a wake lock is
+ * needed.
+ * @return {@code true} if the attempt to send media button was successfully.
+ * {@code false} otherwise.
+ */
+ boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
+ KeyEvent ke, int sequenceId, ResultReceiver cb);
+
+ /**
+ * Dumps internal state
+ *
+ * @param pw print writer
+ * @param prefix prefix
+ */
+ void dump(PrintWriter pw, String prefix);
+
+ /**
+ * Override {@link AutoCloseable#close} to tell not to throw exception.
+ */
+ @Override
+ void close();
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 0f059dba5274..f71fb582e3ed 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -40,10 +40,7 @@ import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioSystem;
-import android.media.IAudioService;
import android.media.IRemoteVolumeController;
-import android.media.MediaController2;
-import android.media.Session2CommandGroup;
import android.media.Session2Token;
import android.media.session.IActiveSessionsListener;
import android.media.session.IOnMediaKeyEventDispatchedListener;
@@ -61,7 +58,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
@@ -123,11 +119,6 @@ public class MediaSessionService extends SystemService implements Monitor {
@GuardedBy("mLock")
private final ArrayList<SessionsListenerRecord> mSessionsListeners =
new ArrayList<SessionsListenerRecord>();
- // Map user id as index to list of Session2Tokens
- // TODO: Keep session2 info in MediaSessionStack for prioritizing both session1 and session2 in
- // one place.
- @GuardedBy("mLock")
- private final SparseArray<List<Session2Token>> mSession2TokensPerUser = new SparseArray<>();
@GuardedBy("mLock")
private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords =
new ArrayList<>();
@@ -189,16 +180,11 @@ public class MediaSessionService extends SystemService implements Monitor {
updateUser();
}
- private IAudioService getAudioService() {
- IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
- return IAudioService.Stub.asInterface(b);
- }
-
private boolean isGlobalPriorityActiveLocked() {
return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive();
}
- void updateSession(MediaSessionRecord record) {
+ void onSessionActiveStateChanged(MediaSessionRecordImpl record) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(record.getUserId());
if (user == null) {
@@ -215,12 +201,14 @@ public class MediaSessionService extends SystemService implements Monitor {
Log.w(TAG, "Unknown session updated. Ignoring.");
return;
}
- user.mPriorityStack.onSessionStateChange(record);
+ user.mPriorityStack.onSessionActiveStateChanged(record);
}
- mHandler.postSessionsChanged(record.getUserId());
+
+ mHandler.postSessionsChanged(record);
}
}
+ // Currently only media1 can become global priority session.
void setGlobalPrioritySession(MediaSessionRecord record) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(record.getUserId());
@@ -266,11 +254,13 @@ public class MediaSessionService extends SystemService implements Monitor {
List<Session2Token> getSession2TokensLocked(int userId) {
List<Session2Token> list = new ArrayList<>();
if (userId == USER_ALL) {
- for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
- list.addAll(mSession2TokensPerUser.valueAt(i));
+ int size = mUserRecords.size();
+ for (int i = 0; i < size; i++) {
+ list.addAll(mUserRecords.valueAt(i).mPriorityStack.getSession2Tokens(userId));
}
} else {
- list.addAll(mSession2TokensPerUser.get(userId));
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ list.addAll(user.mPriorityStack.getSession2Tokens(userId));
}
return list;
}
@@ -297,14 +287,15 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- void onSessionPlaystateChanged(MediaSessionRecord record, int oldState, int newState) {
+ void onSessionPlaybackStateChanged(MediaSessionRecordImpl record,
+ boolean shouldUpdatePriority) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(record.getUserId());
if (user == null || !user.mPriorityStack.contains(record)) {
Log.d(TAG, "Unknown session changed playback state. Ignoring.");
return;
}
- user.mPriorityStack.onPlaystateChanged(record, oldState, newState);
+ user.mPriorityStack.onPlaybackStateChanged(record, shouldUpdatePriority);
}
}
@@ -347,7 +338,6 @@ public class MediaSessionService extends SystemService implements Monitor {
user.destroySessionsForUserLocked(userId);
}
}
- mSession2TokensPerUser.remove(userId);
updateUser();
}
}
@@ -366,13 +356,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- void sessionDied(MediaSessionRecord session) {
- synchronized (mLock) {
- destroySessionLocked(session);
- }
- }
-
- void destroySession(MediaSessionRecord session) {
+ void onSessionDied(MediaSessionRecordImpl session) {
synchronized (mLock) {
destroySessionLocked(session);
}
@@ -393,9 +377,6 @@ public class MediaSessionService extends SystemService implements Monitor {
mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id));
}
}
- if (mSession2TokensPerUser.get(userInfo.id) == null) {
- mSession2TokensPerUser.put(userInfo.id, new ArrayList<>());
- }
}
}
// Ensure that the current full user exists.
@@ -405,9 +386,6 @@ public class MediaSessionService extends SystemService implements Monitor {
Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
- if (mSession2TokensPerUser.get(currentFullUserId) == null) {
- mSession2TokensPerUser.put(currentFullUserId, new ArrayList<>());
- }
}
mFullUserIds.put(currentFullUserId, currentFullUserId);
}
@@ -444,7 +422,7 @@ public class MediaSessionService extends SystemService implements Monitor {
* 5. We need to unlink to death from the cb binder
* 6. We need to tell the session to do any final cleanup (onDestroy)
*/
- private void destroySessionLocked(MediaSessionRecord session) {
+ private void destroySessionLocked(MediaSessionRecordImpl session) {
if (DEBUG) {
Log.d(TAG, "Destroying " + session);
}
@@ -461,7 +439,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
session.close();
- mHandler.postSessionsChanged(session.getUserId());
+ mHandler.postSessionsChanged(session);
}
private void enforcePackageName(String packageName, int uid) {
@@ -541,15 +519,6 @@ public class MediaSessionService extends SystemService implements Monitor {
return false;
}
- private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
- String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo)
- throws RemoteException {
- synchronized (mLock) {
- return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb,
- tag, sessionInfo);
- }
- }
-
/*
* When a session is created the following things need to happen.
* 1. Its callback binder needs a link to death
@@ -557,29 +526,31 @@ public class MediaSessionService extends SystemService implements Monitor {
* 3. It needs to be added to the priority stack.
* 4. It needs to be added to the relevant user record.
*/
- private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
+ private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo) {
- FullUserRecord user = getFullUserRecordLocked(userId);
- if (user == null) {
- Log.w(TAG, "Request from invalid user: " + userId + ", pkg=" + callerPackageName);
- throw new RuntimeException("Session request from invalid user.");
- }
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null) {
+ Log.w(TAG, "Request from invalid user: " + userId + ", pkg=" + callerPackageName);
+ throw new RuntimeException("Session request from invalid user.");
+ }
- final MediaSessionRecord session;
- try {
- session = new MediaSessionRecord(callerPid, callerUid, userId,
- callerPackageName, cb, tag, sessionInfo, this, mHandler.getLooper());
- } catch (RemoteException e) {
- throw new RuntimeException("Media Session owner died prematurely.", e);
- }
+ final MediaSessionRecord session;
+ try {
+ session = new MediaSessionRecord(callerPid, callerUid, userId,
+ callerPackageName, cb, tag, sessionInfo, this, mHandler.getLooper());
+ } catch (RemoteException e) {
+ throw new RuntimeException("Media Session owner died prematurely.", e);
+ }
- user.mPriorityStack.addSession(session);
- mHandler.postSessionsChanged(userId);
+ user.mPriorityStack.addSession(session);
+ mHandler.postSessionsChanged(session);
- if (DEBUG) {
- Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
+ if (DEBUG) {
+ Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
+ }
+ return session;
}
- return session;
}
private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
@@ -600,16 +571,16 @@ public class MediaSessionService extends SystemService implements Monitor {
return -1;
}
- private void pushSessionsChanged(int userId) {
+ private void pushSession1Changed(int userId) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(userId);
if (user == null) {
- Log.w(TAG, "pushSessionsChanged failed. No user with id=" + userId);
+ Log.w(TAG, "pushSession1ChangedOnHandler failed. No user with id=" + userId);
return;
}
List<MediaSessionRecord> records = getActiveSessionsLocked(userId);
int size = records.size();
- ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
+ ArrayList<MediaSession.Token> tokens = new ArrayList<>();
for (int i = 0; i < size; i++) {
tokens.add(records.get(i).getSessionToken());
}
@@ -629,6 +600,27 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
+ void pushSession2Changed(int userId) {
+ synchronized (mLock) {
+ List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL);
+ List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
+
+ for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
+ Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
+ try {
+ if (listenerRecord.userId == USER_ALL) {
+ listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
+ } else if (listenerRecord.userId == userId) {
+ listenerRecord.listener.onSession2TokensChanged(session2Tokens);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
+ mSession2TokensListenerRecords.remove(i);
+ }
+ }
+ }
+ }
+
private void pushRemoteVolumeUpdateLocked(int userId) {
FullUserRecord user = getFullUserRecordLocked(userId);
if (user == null) {
@@ -638,8 +630,13 @@ public class MediaSessionService extends SystemService implements Monitor {
synchronized (mLock) {
int size = mRemoteVolumeControllers.beginBroadcast();
- MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
- MediaSession.Token token = record == null ? null : record.getSessionToken();
+ MediaSessionRecordImpl record = user.mPriorityStack.getDefaultRemoteSession(userId);
+ if (record instanceof MediaSession2Record) {
+ // TODO(jaewan): Implement
+ return;
+ }
+ MediaSession.Token token = record == null
+ ? null : ((MediaSessionRecord) record).getSessionToken();
for (int i = size - 1; i >= 0; i--) {
try {
@@ -653,34 +650,15 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- void pushSession2TokensChangedLocked(int userId) {
- List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL);
- List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
-
- for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
- Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
- try {
- if (listenerRecord.userId == USER_ALL) {
- listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
- } else if (listenerRecord.userId == userId) {
- listenerRecord.listener.onSession2TokensChanged(session2Tokens);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
- mSession2TokensListenerRecords.remove(i);
- }
- }
- }
-
/**
* Called when the media button receiver for the {@code record} is changed.
*
* @param record the media session whose media button receiver is updated.
*/
- public void onMediaButtonReceiverChanged(MediaSessionRecord record) {
+ public void onMediaButtonReceiverChanged(MediaSessionRecordImpl record) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(record.getUserId());
- MediaSessionRecord mediaButtonSession =
+ MediaSessionRecordImpl mediaButtonSession =
user.mPriorityStack.getMediaButtonSession();
if (record == mediaButtonSession) {
user.rememberMediaButtonReceiverLocked(mediaButtonSession);
@@ -868,39 +846,34 @@ public class MediaSessionService extends SystemService implements Monitor {
pw.println(indent + "Restored MediaButtonReceiverComponentType: "
+ mRestoredMediaButtonReceiverComponentType);
mPriorityStack.dump(pw, indent);
- pw.println(indent + "Session2Tokens:");
- for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
- List<Session2Token> list = mSession2TokensPerUser.valueAt(i);
- if (list == null || list.size() == 0) {
- continue;
- }
- for (Session2Token token : list) {
- pw.println(indent + " " + token);
- }
- }
}
@Override
- public void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
- MediaSessionRecord newMediaButtonSession) {
+ public void onMediaButtonSessionChanged(MediaSessionRecordImpl oldMediaButtonSession,
+ MediaSessionRecordImpl newMediaButtonSession) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Media button session is changed to " + newMediaButtonSession);
}
synchronized (mLock) {
if (oldMediaButtonSession != null) {
- mHandler.postSessionsChanged(oldMediaButtonSession.getUserId());
+ mHandler.postSessionsChanged(oldMediaButtonSession);
}
if (newMediaButtonSession != null) {
rememberMediaButtonReceiverLocked(newMediaButtonSession);
- mHandler.postSessionsChanged(newMediaButtonSession.getUserId());
+ mHandler.postSessionsChanged(newMediaButtonSession);
}
pushAddressedPlayerChangedLocked();
}
}
// Remember media button receiver and keep it in the persistent storage.
- public void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
- PendingIntent receiver = record.getMediaButtonReceiver();
+ public void rememberMediaButtonReceiverLocked(MediaSessionRecordImpl record) {
+ if (record instanceof MediaSession2Record) {
+ // TODO(jaewan): Implement
+ return;
+ }
+ MediaSessionRecord sessionRecord = (MediaSessionRecord) record;
+ PendingIntent receiver = sessionRecord.getMediaButtonReceiver();
mLastMediaButtonReceiver = receiver;
mRestoredMediaButtonReceiver = null;
mRestoredMediaButtonReceiverComponentType = COMPONENT_TYPE_INVALID;
@@ -925,10 +898,15 @@ public class MediaSessionService extends SystemService implements Monitor {
private void pushAddressedPlayerChangedLocked(
IOnMediaKeyEventSessionChangedListener callback) {
try {
- MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
+ MediaSessionRecordImpl mediaButtonSession = getMediaButtonSessionLocked();
if (mediaButtonSession != null) {
- callback.onMediaKeyEventSessionChanged(mediaButtonSession.getPackageName(),
- mediaButtonSession.getSessionToken());
+ if (mediaButtonSession instanceof MediaSessionRecord) {
+ MediaSessionRecord session1 = (MediaSessionRecord) mediaButtonSession;
+ callback.onMediaKeyEventSessionChanged(session1.getPackageName(),
+ session1.getSessionToken());
+ } else {
+ // TODO(jaewan): Implement
+ }
} else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
callback.onMediaKeyEventSessionChanged(
mCurrentFullUserRecord.mLastMediaButtonReceiver
@@ -951,7 +929,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- private MediaSessionRecord getMediaButtonSessionLocked() {
+ private MediaSessionRecordImpl getMediaButtonSessionLocked() {
return isGlobalPriorityActiveLocked()
? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
}
@@ -1132,14 +1110,13 @@ public class MediaSessionService extends SystemService implements Monitor {
throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
+ " but actually=" + sessionToken.getUid());
}
- Controller2Callback callback = new Controller2Callback(sessionToken);
- // Note: It's safe not to keep controller here because it wouldn't be GC'ed until
- // it's closed.
- // TODO: Keep controller as well for better readability
- // because the GC behavior isn't straightforward.
- MediaController2 controller = new MediaController2.Builder(mContext, sessionToken)
- .setControllerCallback(new HandlerExecutor(mHandler), callback)
- .build();
+ MediaSession2Record record = new MediaSession2Record(
+ sessionToken, MediaSessionService.this, mHandler.getLooper());
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+ user.mPriorityStack.addSession(record);
+ }
+ // Do not immediately notify changes -- do so when framework can dispatch command
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1180,7 +1157,8 @@ public class MediaSessionService extends SystemService implements Monitor {
null /* optional packageName */);
List<Session2Token> result;
synchronized (mLock) {
- result = getSession2TokensLocked(resolvedUserId);
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ result = user.mPriorityStack.getSession2Tokens(resolvedUserId);
}
return new ParceledListSlice(result);
} finally {
@@ -2018,7 +1996,7 @@ public class MediaSessionService extends SystemService implements Monitor {
private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid,
int uid, boolean asSystemService, int suggestedStream, int direction, int flags) {
- MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
+ MediaSessionRecordImpl session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
: mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
boolean preferSuggestedStream = false;
@@ -2109,7 +2087,13 @@ public class MediaSessionService extends SystemService implements Monitor {
private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
- MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
+ if (mCurrentFullUserRecord.getMediaButtonSessionLocked()
+ instanceof MediaSession2Record) {
+ // TODO(jaewan): Implement
+ return;
+ }
+ MediaSessionRecord session =
+ (MediaSessionRecord) mCurrentFullUserRecord.getMediaButtonSessionLocked();
if (session != null) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to " + session);
@@ -2389,15 +2373,19 @@ public class MediaSessionService extends SystemService implements Monitor {
}
final class MessageHandler extends Handler {
- private static final int MSG_SESSIONS_CHANGED = 1;
- private static final int MSG_VOLUME_INITIAL_DOWN = 2;
+ private static final int MSG_SESSIONS_1_CHANGED = 1;
+ private static final int MSG_SESSIONS_2_CHANGED = 2;
+ private static final int MSG_VOLUME_INITIAL_DOWN = 3;
private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_SESSIONS_CHANGED:
- pushSessionsChanged((int) msg.obj);
+ case MSG_SESSIONS_1_CHANGED:
+ pushSession1Changed((int) msg.obj);
+ break;
+ case MSG_SESSIONS_2_CHANGED:
+ pushSession2Changed((int) msg.obj);
break;
case MSG_VOLUME_INITIAL_DOWN:
synchronized (mLock) {
@@ -2412,41 +2400,19 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- public void postSessionsChanged(int userId) {
+ public void postSessionsChanged(MediaSessionRecordImpl record) {
// Use object instead of the arguments when posting message to remove pending requests.
- Integer userIdInteger = mIntegerCache.get(userId);
+ Integer userIdInteger = mIntegerCache.get(record.getUserId());
if (userIdInteger == null) {
- userIdInteger = Integer.valueOf(userId);
- mIntegerCache.put(userId, userIdInteger);
+ userIdInteger = Integer.valueOf(record.getUserId());
+ mIntegerCache.put(record.getUserId(), userIdInteger);
}
- removeMessages(MSG_SESSIONS_CHANGED, userIdInteger);
- obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget();
- }
- }
- private class Controller2Callback extends MediaController2.ControllerCallback {
- private final Session2Token mToken;
-
- Controller2Callback(Session2Token token) {
- mToken = token;
- }
-
- @Override
- public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
- synchronized (mLock) {
- int userId = UserHandle.getUserId(mToken.getUid());
- mSession2TokensPerUser.get(userId).add(mToken);
- pushSession2TokensChangedLocked(userId);
- }
- }
-
- @Override
- public void onDisconnected(MediaController2 controller) {
- synchronized (mLock) {
- int userId = UserHandle.getUserId(mToken.getUid());
- mSession2TokensPerUser.get(userId).remove(mToken);
- pushSession2TokensChangedLocked(userId);
- }
+ int msg = (record instanceof MediaSessionRecord)
+ ? MSG_SESSIONS_1_CHANGED : MSG_SESSIONS_2_CHANGED;
+ removeMessages(msg, userIdInteger);
+ obtainMessage(msg, userIdInteger).sendToTarget();
}
}
+
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 732563f6e05e..7bb7cf4b74ad 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -16,8 +16,8 @@
package com.android.server.media;
+import android.media.Session2Token;
import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
import android.os.Debug;
import android.os.UserHandle;
import android.util.IntArray;
@@ -45,51 +45,30 @@ class MediaSessionStack {
/**
* Called when the media button session is changed.
*/
- void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
- MediaSessionRecord newMediaButtonSession);
+ void onMediaButtonSessionChanged(MediaSessionRecordImpl oldMediaButtonSession,
+ MediaSessionRecordImpl newMediaButtonSession);
}
/**
- * These are states that usually indicate the user took an action and should
- * bump priority regardless of the old state.
+ * Sorted list of the media sessions
*/
- private static final int[] ALWAYS_PRIORITY_STATES = {
- PlaybackState.STATE_FAST_FORWARDING,
- PlaybackState.STATE_REWINDING,
- PlaybackState.STATE_SKIPPING_TO_PREVIOUS,
- PlaybackState.STATE_SKIPPING_TO_NEXT };
- /**
- * These are states that usually indicate the user took an action if they
- * were entered from a non-priority state.
- */
- private static final int[] TRANSITION_PRIORITY_STATES = {
- PlaybackState.STATE_BUFFERING,
- PlaybackState.STATE_CONNECTING,
- PlaybackState.STATE_PLAYING };
-
- /**
- * Sorted list of the media sessions.
- * The session of which PlaybackState is changed to ALWAYS_PRIORITY_STATES or
- * TRANSITION_PRIORITY_STATES comes first.
- * @see #shouldUpdatePriority
- */
- private final List<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+ private final List<MediaSessionRecordImpl> mSessions = new ArrayList<>();
private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
private final OnMediaButtonSessionChangedListener mOnMediaButtonSessionChangedListener;
/**
* The media button session which receives media key events.
- * It could be null if the previous media buttion session is released.
+ * It could be null if the previous media button session is released.
*/
- private MediaSessionRecord mMediaButtonSession;
+ private MediaSessionRecordImpl mMediaButtonSession;
- private MediaSessionRecord mCachedVolumeDefault;
+ private MediaSessionRecordImpl mCachedVolumeDefault;
/**
* Cache the result of the {@link #getActiveSessions} per user.
*/
- private final SparseArray<ArrayList<MediaSessionRecord>> mCachedActiveLists =
+ private final SparseArray<List<MediaSessionRecord>> mCachedActiveLists =
new SparseArray<>();
MediaSessionStack(AudioPlayerStateMonitor monitor, OnMediaButtonSessionChangedListener listener) {
@@ -102,7 +81,7 @@ class MediaSessionStack {
*
* @param record The record to add.
*/
- public void addSession(MediaSessionRecord record) {
+ public void addSession(MediaSessionRecordImpl record) {
mSessions.add(record);
clearCache(record.getUserId());
@@ -117,7 +96,7 @@ class MediaSessionStack {
*
* @param record The record to remove.
*/
- public void removeSession(MediaSessionRecord record) {
+ public void removeSession(MediaSessionRecordImpl record) {
mSessions.remove(record);
if (mMediaButtonSession == record) {
// When the media button session is removed, nullify the media button session and do not
@@ -131,7 +110,7 @@ class MediaSessionStack {
/**
* Return if the record exists in the priority tracker.
*/
- public boolean contains(MediaSessionRecord record) {
+ public boolean contains(MediaSessionRecordImpl record) {
return mSessions.contains(record);
}
@@ -142,9 +121,12 @@ class MediaSessionStack {
* @return the MediaSessionRecord. Can be {@code null} if the session is gone meanwhile.
*/
public MediaSessionRecord getMediaSessionRecord(MediaSession.Token sessionToken) {
- for (MediaSessionRecord record : mSessions) {
- if (Objects.equals(record.getSessionToken(), sessionToken)) {
- return record;
+ for (MediaSessionRecordImpl record : mSessions) {
+ if (record instanceof MediaSessionRecord) {
+ MediaSessionRecord session1 = (MediaSessionRecord) record;
+ if (Objects.equals(session1.getSessionToken(), sessionToken)) {
+ return session1;
+ }
}
}
return null;
@@ -154,15 +136,15 @@ class MediaSessionStack {
* Notify the priority tracker that a session's playback state changed.
*
* @param record The record that changed.
- * @param oldState Its old playback state.
- * @param newState Its new playback state.
+ * @param shouldUpdatePriority {@code true} if the record needs to prioritized
*/
- public void onPlaystateChanged(MediaSessionRecord record, int oldState, int newState) {
- if (shouldUpdatePriority(oldState, newState)) {
+ public void onPlaybackStateChanged(
+ MediaSessionRecordImpl record, boolean shouldUpdatePriority) {
+ if (shouldUpdatePriority) {
mSessions.remove(record);
mSessions.add(0, record);
clearCache(record.getUserId());
- } else if (!MediaSession.isActiveState(newState)) {
+ } else if (record.checkPlaybackActiveState(false)) {
// Just clear the volume cache when a state goes inactive
mCachedVolumeDefault = null;
}
@@ -172,7 +154,7 @@ class MediaSessionStack {
// In that case, we pick the media session whose PlaybackState matches
// the audio playback configuration.
if (mMediaButtonSession != null && mMediaButtonSession.getUid() == record.getUid()) {
- MediaSessionRecord newMediaButtonSession =
+ MediaSessionRecordImpl newMediaButtonSession =
findMediaButtonSession(mMediaButtonSession.getUid());
if (newMediaButtonSession != mMediaButtonSession) {
updateMediaButtonSession(newMediaButtonSession);
@@ -185,7 +167,7 @@ class MediaSessionStack {
*
* @param record The record that changed.
*/
- public void onSessionStateChange(MediaSessionRecord record) {
+ public void onSessionActiveStateChanged(MediaSessionRecordImpl record) {
// For now just clear the cache. Eventually we'll selectively clear
// depending on what changed.
clearCache(record.getUserId());
@@ -203,7 +185,7 @@ class MediaSessionStack {
}
IntArray audioPlaybackUids = mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids();
for (int i = 0; i < audioPlaybackUids.size(); i++) {
- MediaSessionRecord mediaButtonSession =
+ MediaSessionRecordImpl mediaButtonSession =
findMediaButtonSession(audioPlaybackUids.get(i));
if (mediaButtonSession != null) {
// Found the media button session.
@@ -225,9 +207,9 @@ class MediaSessionStack {
* @return The media button session. Returns {@code null} if the app doesn't have a media
* session.
*/
- private MediaSessionRecord findMediaButtonSession(int uid) {
- MediaSessionRecord mediaButtonSession = null;
- for (MediaSessionRecord session : mSessions) {
+ private MediaSessionRecordImpl findMediaButtonSession(int uid) {
+ MediaSessionRecordImpl mediaButtonSession = null;
+ for (MediaSessionRecordImpl session : mSessions) {
if (uid == session.getUid()) {
if (session.checkPlaybackActiveState(
mAudioPlayerStateMonitor.isPlaybackActive(session.getUid()))) {
@@ -253,8 +235,8 @@ class MediaSessionStack {
* for all users in this {@link MediaSessionStack}.
* @return All the active sessions in priority order.
*/
- public ArrayList<MediaSessionRecord> getActiveSessions(int userId) {
- ArrayList<MediaSessionRecord> cachedActiveList = mCachedActiveLists.get(userId);
+ public List<MediaSessionRecord> getActiveSessions(int userId) {
+ List<MediaSessionRecord> cachedActiveList = mCachedActiveLists.get(userId);
if (cachedActiveList == null) {
cachedActiveList = getPriorityList(true, userId);
mCachedActiveLists.put(userId, cachedActiveList);
@@ -263,26 +245,46 @@ class MediaSessionStack {
}
/**
+ * Gets the session2 tokens.
+ *
+ * @param userId The user to check. It can be {@link UserHandle#USER_ALL} to get all session2
+ * tokens for all users in this {@link MediaSessionStack}.
+ * @return All session2 tokens.
+ */
+ public List<Session2Token> getSession2Tokens(int userId) {
+ ArrayList<Session2Token> session2Records = new ArrayList<>();
+ for (MediaSessionRecordImpl record : mSessions) {
+ if ((userId == UserHandle.USER_ALL || record.getUserId() == userId)
+ && record.isActive()
+ && record instanceof MediaSession2Record) {
+ MediaSession2Record session2 = (MediaSession2Record) record;
+ session2Records.add(session2.getSession2Token());
+ }
+ }
+ return session2Records;
+ }
+
+ /**
* Get the media button session which receives the media button events.
*
* @return The media button session or null.
*/
- public MediaSessionRecord getMediaButtonSession() {
+ public MediaSessionRecordImpl getMediaButtonSession() {
return mMediaButtonSession;
}
- private void updateMediaButtonSession(MediaSessionRecord newMediaButtonSession) {
- MediaSessionRecord oldMediaButtonSession = mMediaButtonSession;
+ private void updateMediaButtonSession(MediaSessionRecordImpl newMediaButtonSession) {
+ MediaSessionRecordImpl oldMediaButtonSession = mMediaButtonSession;
mMediaButtonSession = newMediaButtonSession;
mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged(
oldMediaButtonSession, newMediaButtonSession);
}
- public MediaSessionRecord getDefaultVolumeSession() {
+ public MediaSessionRecordImpl getDefaultVolumeSession() {
if (mCachedVolumeDefault != null) {
return mCachedVolumeDefault;
}
- ArrayList<MediaSessionRecord> records = getPriorityList(true, UserHandle.USER_ALL);
+ List<MediaSessionRecord> records = getPriorityList(true, UserHandle.USER_ALL);
int size = records.size();
for (int i = 0; i < size; i++) {
MediaSessionRecord record = records.get(i);
@@ -294,13 +296,13 @@ class MediaSessionStack {
return null;
}
- public MediaSessionRecord getDefaultRemoteSession(int userId) {
- ArrayList<MediaSessionRecord> records = getPriorityList(true, userId);
+ public MediaSessionRecordImpl getDefaultRemoteSession(int userId) {
+ List<MediaSessionRecord> records = getPriorityList(true, userId);
int size = records.size();
for (int i = 0; i < size; i++) {
MediaSessionRecord record = records.get(i);
- if (!record.isPlaybackLocal()) {
+ if (!record.isPlaybackTypeLocal()) {
return record;
}
}
@@ -308,16 +310,11 @@ class MediaSessionStack {
}
public void dump(PrintWriter pw, String prefix) {
- ArrayList<MediaSessionRecord> sortedSessions = getPriorityList(false,
- UserHandle.USER_ALL);
- int count = sortedSessions.size();
pw.println(prefix + "Media button session is " + mMediaButtonSession);
- pw.println(prefix + "Sessions Stack - have " + count + " sessions:");
+ pw.println(prefix + "Sessions Stack - have " + mSessions.size() + " sessions:");
String indent = prefix + " ";
- for (int i = 0; i < count; i++) {
- MediaSessionRecord record = sortedSessions.get(i);
+ for (MediaSessionRecordImpl record : mSessions) {
record.dump(pw, indent);
- pw.println();
}
}
@@ -335,17 +332,19 @@ class MediaSessionStack {
* will return sessions for all users.
* @return The priority sorted list of sessions.
*/
- public ArrayList<MediaSessionRecord> getPriorityList(boolean activeOnly, int userId) {
- ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
+ public List<MediaSessionRecord> getPriorityList(boolean activeOnly, int userId) {
+ List<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
int lastPlaybackActiveIndex = 0;
int lastActiveIndex = 0;
- int size = mSessions.size();
- for (int i = 0; i < size; i++) {
- final MediaSessionRecord session = mSessions.get(i);
+ for (MediaSessionRecordImpl record : mSessions) {
+ if (!(record instanceof MediaSessionRecord)) {
+ continue;
+ }
+ final MediaSessionRecord session = (MediaSessionRecord) record;
- if (userId != UserHandle.USER_ALL && userId != session.getUserId()) {
- // Filter out sessions for the wrong user
+ if ((userId != UserHandle.USER_ALL && userId != session.getUserId())) {
+ // Filter out sessions for the wrong user or session2.
continue;
}
@@ -369,26 +368,6 @@ class MediaSessionStack {
return result;
}
- private boolean shouldUpdatePriority(int oldState, int newState) {
- if (containsState(newState, ALWAYS_PRIORITY_STATES)) {
- return true;
- }
- if (!containsState(oldState, TRANSITION_PRIORITY_STATES)
- && containsState(newState, TRANSITION_PRIORITY_STATES)) {
- return true;
- }
- return false;
- }
-
- private boolean containsState(int state, int[] states) {
- for (int i = 0; i < states.length; i++) {
- if (states[i] == state) {
- return true;
- }
- }
- return false;
- }
-
private void clearCache(int userId) {
mCachedVolumeDefault = null;
mCachedActiveLists.remove(userId);
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 8fdfcbfb2ad9..0ea4e63231d4 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -48,8 +48,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
static final String BLUETOOTH_ROUTE_ID = "BLUETOOTH_ROUTE";
// TODO: Move these to a proper place
- public static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
- public static final String CATEGORY_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO";
+ public static final String TYPE_LIVE_AUDIO = "android.media.intent.route.TYPE_LIVE_AUDIO";
+ public static final String TYPE_LIVE_VIDEO = "android.media.intent.route.TYPE_LIVE_VIDEO";
private final AudioManager mAudioManager;
private final IAudioService mAudioService;
@@ -91,44 +91,44 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void requestCreateSession(String packageName, String routeId, String controlCategory,
+ public void requestCreateSession(String packageName, String routeId, String routeType,
long requestId) {
// Do nothing
}
@Override
- public void releaseSession(int sessionId) {
+ public void releaseSession(String sessionId) {
// Do nothing
}
@Override
- public void selectRoute(int sessionId, MediaRoute2Info route) {
+ public void selectRoute(String sessionId, String routeId) {
//TODO: implement method
}
@Override
- public void deselectRoute(int sessionId, MediaRoute2Info route) {
+ public void deselectRoute(String sessionId, String routeId) {
//TODO: implement method
}
@Override
- public void transferToRoute(int sessionId, MediaRoute2Info route) {
+ public void transferToRoute(String sessionId, String routeId) {
//TODO: implement method
}
//TODO: implement method
@Override
- public void sendControlRequest(@NonNull MediaRoute2Info route, @NonNull Intent request) {
+ public void sendControlRequest(@NonNull String routeId, @NonNull Intent request) {
}
//TODO: implement method
@Override
- public void requestSetVolume(MediaRoute2Info route, int volume) {
+ public void requestSetVolume(String routeId, int volume) {
}
//TODO: implement method
@Override
- public void requestUpdateVolume(MediaRoute2Info route, int delta) {
+ public void requestUpdateVolume(String routeId, int delta) {
}
void initializeRoutes() {
@@ -141,8 +141,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
: MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
.setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
- .addSupportedCategory(CATEGORY_LIVE_AUDIO)
- .addSupportedCategory(CATEGORY_LIVE_VIDEO)
+ .addRouteType(TYPE_LIVE_AUDIO)
+ .addRouteType(TYPE_LIVE_VIDEO)
.build();
AudioRoutesInfo newAudioRoutes = null;
@@ -181,8 +181,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
: MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
.setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
- .addSupportedCategory(CATEGORY_LIVE_AUDIO)
- .addSupportedCategory(CATEGORY_LIVE_VIDEO)
+ .addRouteType(TYPE_LIVE_AUDIO)
+ .addRouteType(TYPE_LIVE_VIDEO)
.build();
if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
@@ -193,7 +193,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
mCurAudioRoutesInfo.bluetoothName)
.setDescription(mContext.getResources().getText(
R.string.bluetooth_a2dp_audio_route_name).toString())
- .addSupportedCategory(CATEGORY_LIVE_AUDIO)
+ .addRouteType(TYPE_LIVE_AUDIO)
.build();
} else {
mBluetoothA2dpRoute = null;
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index 3ca1803262e7..22b01bee6c6a 100644
--- a/services/core/java/com/android/server/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -229,7 +229,7 @@ public class NetworkStatsFactory {
entry.txPackets += reader.nextLong();
}
- stats.addValues(entry);
+ stats.addEntry(entry);
reader.finishLine();
}
} catch (NullPointerException|NumberFormatException e) {
@@ -279,7 +279,7 @@ public class NetworkStatsFactory {
entry.txBytes = reader.nextLong();
entry.txPackets = reader.nextLong();
- stats.addValues(entry);
+ stats.addEntry(entry);
reader.finishLine();
}
} catch (NullPointerException|NumberFormatException e) {
@@ -439,7 +439,7 @@ public class NetworkStatsFactory {
if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface))
&& (limitUid == UID_ALL || limitUid == entry.uid)
&& (limitTag == TAG_ALL || limitTag == entry.tag)) {
- stats.addValues(entry);
+ stats.addEntry(entry);
}
reader.finishLine();
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index ec8a8e7c4c1a..7a6f29764f09 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -27,6 +27,7 @@ import static android.net.ConnectivityManager.isNetworkTypeMobile;
import static android.net.NetworkStack.checkNetworkStackPermission;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.IFACE_VT;
import static android.net.NetworkStats.INTERFACES_ALL;
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.ROAMING_ALL;
@@ -211,7 +212,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
/**
* Virtual network interface for video telephony. This is for VT data usage counting purpose.
*/
- public static final String VT_INTERFACE = "vt_data0";
+ // TODO: Remove this after no one is using it.
+ public static final String VT_INTERFACE = NetworkStats.IFACE_VT;
/**
* Settings that can be changed externally.
@@ -712,7 +714,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
final NetworkStats stats = new NetworkStats(end - start, 1);
- stats.addValues(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE,
+ stats.addEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE,
METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets,
entry.txBytes, entry.txPackets, entry.operations));
return stats;
@@ -1179,8 +1181,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
ident.getRoaming(), true /* metered */,
true /* onDefaultNetwork */);
- findOrCreateNetworkIdentitySet(mActiveIfaces, VT_INTERFACE).add(vtIdent);
- findOrCreateNetworkIdentitySet(mActiveUidIfaces, VT_INTERFACE).add(vtIdent);
+ findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
+ findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
}
if (isMobile) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a4f4d079df27..728b297b4d8e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2481,7 +2481,7 @@ public class NotificationManagerService extends SystemService {
.setUid(r.sbn.getUid())
.setChannelId(r.getChannel().getId())
.setChannelName(r.getChannel().getName().toString())
- .setPostedTimeMs(r.sbn.getPostTime())
+ .setPostedTimeMs(System.currentTimeMillis())
.setTitle(getHistoryTitle(r.getNotification()))
.setText(getHistoryText(
r.sbn.getPackageContext(getContext()), r.getNotification()))
diff --git a/services/core/java/com/android/server/notification/OWNERS b/services/core/java/com/android/server/notification/OWNERS
new file mode 100644
index 000000000000..5a19656b36a6
--- /dev/null
+++ b/services/core/java/com/android/server/notification/OWNERS
@@ -0,0 +1,4 @@
+dsandler@android.com
+juliacr@google.com
+beverlyt@google.com
+pixel@google.com
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index b25e1e2160c3..ed7139991937 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -15,35 +15,45 @@
*/
package com.android.server.pm;
+import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import android.Manifest;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
+import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IApplicationThread;
import android.app.admin.DevicePolicyEventLogger;
+import android.app.admin.DevicePolicyManagerInternal;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ICrossProfileApps;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.stats.devicepolicy.DevicePolicyEnums;
import android.text.TextUtils;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
+import com.android.server.appop.AppOpsService;
import com.android.server.wm.ActivityTaskManagerInternal;
import java.util.ArrayList;
@@ -55,6 +65,9 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
private Context mContext;
private Injector mInjector;
+ private AppOpsService mAppOpsService;
+ private final DevicePolicyManagerInternal mDpmi;
+ private final IPackageManager mIpm;
public CrossProfileAppsServiceImpl(Context context) {
this(context, new InjectorImpl(context));
@@ -64,6 +77,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
CrossProfileAppsServiceImpl(Context context, Injector injector) {
mContext = context;
mInjector = injector;
+ mIpm = AppGlobals.getPackageManager();
+ mDpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
}
@Override
@@ -153,6 +168,63 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
userId);
}
+ @Override
+ public boolean canRequestInteractAcrossProfiles(String callingPackage) {
+ Objects.requireNonNull(callingPackage);
+ verifyCallingPackage(callingPackage);
+
+ final List<UserHandle> targetUserProfiles = getTargetUserProfilesUnchecked(
+ callingPackage, mInjector.getCallingUserId());
+ if (targetUserProfiles.isEmpty()) {
+ return false;
+ }
+
+ if (!hasRequestedAppOpPermission(
+ AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), callingPackage)) {
+ return false;
+ }
+ return isCrossProfilePackageWhitelisted(callingPackage);
+ }
+
+ private boolean hasRequestedAppOpPermission(String permission, String packageName) {
+ try {
+ String[] packages = mIpm.getAppOpPermissionPackages(permission);
+ return ArrayUtils.contains(packages, packageName);
+ } catch (RemoteException exc) {
+ Slog.e(TAG, "PackageManager dead. Cannot get permission info");
+ return false;
+ }
+ }
+
+ @Override
+ public boolean canInteractAcrossProfiles(String callingPackage) {
+ Objects.requireNonNull(callingPackage);
+ verifyCallingPackage(callingPackage);
+
+ final List<UserHandle> targetUserProfiles = getTargetUserProfilesUnchecked(
+ callingPackage, mInjector.getCallingUserId());
+ if (targetUserProfiles.isEmpty()) {
+ return false;
+ }
+
+ final int callingUid = mInjector.getCallingUid();
+ return isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid)
+ || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, callingUid)
+ || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_PROFILES, callingUid)
+ || AppOpsManager.MODE_ALLOWED == getAppOpsService().noteOperation(
+ OP_INTERACT_ACROSS_PROFILES, callingUid, callingPackage, /* featureId= */ null,
+ /*shouldCollectAsyncNotedOp= */false, /*message= */null);
+ }
+
+ private boolean isCrossProfilePackageWhitelisted(String packageName) {
+ final long ident = mInjector.clearCallingIdentity();
+ try {
+ return mDpmi.getAllCrossProfilePackages().contains(packageName);
+ } finally {
+ mInjector.restoreCallingIdentity(ident);
+ }
+ }
+
private List<UserHandle> getTargetUserProfilesUnchecked(
String callingPackage, @UserIdInt int callingUserId) {
final long ident = mInjector.clearCallingIdentity();
@@ -239,6 +311,19 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
mInjector.getAppOpsManager().checkPackage(mInjector.getCallingUid(), callingPackage);
}
+ private static boolean isPermissionGranted(String permission, int uid) {
+ return PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
+ permission, uid, /* owningUid= */-1, /* exported= */ true);
+ }
+
+ private AppOpsService getAppOpsService() {
+ if (mAppOpsService == null) {
+ IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
+ mAppOpsService = (AppOpsService) IAppOpsService.Stub.asInterface(b);
+ }
+ return mAppOpsService;
+ }
+
private static class InjectorImpl implements Injector {
private Context mContext;
diff --git a/services/core/java/com/android/server/pm/InstallSource.java b/services/core/java/com/android/server/pm/InstallSource.java
index 0541797523a4..6684e3f8973e 100644
--- a/services/core/java/com/android/server/pm/InstallSource.java
+++ b/services/core/java/com/android/server/pm/InstallSource.java
@@ -18,6 +18,8 @@ package com.android.server.pm;
import android.annotation.Nullable;
+import com.android.internal.util.Preconditions;
+
import java.util.Objects;
/**
@@ -29,16 +31,27 @@ final class InstallSource {
* An instance of InstallSource representing an absence of knowledge of the source of
* a package. Used in preference to null.
*/
- static final InstallSource EMPTY = new InstallSource(null, null, null, false);
+ static final InstallSource EMPTY = new InstallSource(null, null, null, false, false, null);
/** We also memoize this case because it is common - all un-updated system apps. */
- private static final InstallSource EMPTY_ORPHANED = new InstallSource(null, null, null, true);
+ private static final InstallSource EMPTY_ORPHANED = new InstallSource(
+ null, null, null, true, false, null);
- /** The package that requested the installation, if known. */
+ /**
+ * The package that requested the installation, if known. May not correspond to a currently
+ * installed package if {@link #isInitiatingPackageUninstalled} is true.
+ */
@Nullable
final String initiatingPackageName;
/**
+ * The signing details of the initiating package, if known. Always null if
+ * {@link #initiatingPackageName} is null.
+ */
+ @Nullable
+ final PackageSignatures initiatingPackageSignatures;
+
+ /**
* The package on behalf of which the initiating package requested the installation, if any.
* For example if a downloaded APK is installed via the Package Installer this could be the
* app that performed the download. This value is provided by the initiating package and not
@@ -57,76 +70,120 @@ final class InstallSource {
/** Indicates if the package that was the installerPackageName has been uninstalled. */
final boolean isOrphaned;
+ /**
+ * Indicates if the package in initiatingPackageName has been uninstalled. Always false if
+ * {@link #initiatingPackageName} is null.
+ */
+ final boolean isInitiatingPackageUninstalled;
+
+ static InstallSource create(@Nullable String initiatingPackageName,
+ @Nullable String originatingPackageName, @Nullable String installerPackageName) {
+ return create(initiatingPackageName, originatingPackageName, installerPackageName,
+ false, false);
+ }
+
static InstallSource create(@Nullable String initiatingPackageName,
@Nullable String originatingPackageName, @Nullable String installerPackageName,
- boolean isOrphaned) {
+ boolean isOrphaned, boolean isInitiatingPackageUninstalled) {
return createInternal(
intern(initiatingPackageName),
intern(originatingPackageName),
intern(installerPackageName),
- isOrphaned);
+ isOrphaned, isInitiatingPackageUninstalled, null);
}
private static InstallSource createInternal(@Nullable String initiatingPackageName,
@Nullable String originatingPackageName, @Nullable String installerPackageName,
- boolean isOrphaned) {
+ boolean isOrphaned, boolean isInitiatingPackageUninstalled,
+ @Nullable PackageSignatures initiatingPackageSignatures) {
if (initiatingPackageName == null && originatingPackageName == null
- && installerPackageName == null) {
+ && installerPackageName == null && initiatingPackageSignatures == null
+ && !isInitiatingPackageUninstalled) {
return isOrphaned ? EMPTY_ORPHANED : EMPTY;
}
return new InstallSource(initiatingPackageName, originatingPackageName,
- installerPackageName, isOrphaned);
+ installerPackageName, isOrphaned, isInitiatingPackageUninstalled,
+ initiatingPackageSignatures
+ );
}
private InstallSource(@Nullable String initiatingPackageName,
@Nullable String originatingPackageName, @Nullable String installerPackageName,
- boolean isOrphaned) {
+ boolean isOrphaned, boolean isInitiatingPackageUninstalled,
+ @Nullable PackageSignatures initiatingPackageSignatures) {
+ if (initiatingPackageName == null) {
+ Preconditions.checkArgument(initiatingPackageSignatures == null);
+ Preconditions.checkArgument(!isInitiatingPackageUninstalled);
+ }
this.initiatingPackageName = initiatingPackageName;
this.originatingPackageName = originatingPackageName;
this.installerPackageName = installerPackageName;
this.isOrphaned = isOrphaned;
+ this.isInitiatingPackageUninstalled = isInitiatingPackageUninstalled;
+ this.initiatingPackageSignatures = initiatingPackageSignatures;
}
/**
- * Return an InstallSource the same as this one except with the specified installerPackageName.
+ * Return an InstallSource the same as this one except with the specified
+ * {@link #installerPackageName}.
*/
- InstallSource setInstallerPackage(String installerPackageName) {
+ InstallSource setInstallerPackage(@Nullable String installerPackageName) {
if (Objects.equals(installerPackageName, this.installerPackageName)) {
return this;
}
return createInternal(initiatingPackageName, originatingPackageName,
- intern(installerPackageName), isOrphaned);
+ intern(installerPackageName), isOrphaned, isInitiatingPackageUninstalled,
+ initiatingPackageSignatures
+ );
}
/**
- * Return an InstallSource the same as this one except with the specified value for isOrphaned.
+ * Return an InstallSource the same as this one except with the specified value for
+ * {@link #isOrphaned}.
*/
InstallSource setIsOrphaned(boolean isOrphaned) {
if (isOrphaned == this.isOrphaned) {
return this;
}
return createInternal(initiatingPackageName, originatingPackageName, installerPackageName,
- isOrphaned);
+ isOrphaned, isInitiatingPackageUninstalled, initiatingPackageSignatures);
}
/**
- * Return an InstallSource the same as this one except it does not refer to the specified
- * installer package name (which is being uninstalled).
+ * Return an InstallSource the same as this one except with the specified
+ * {@link #initiatingPackageSignatures}.
*/
- InstallSource removeInstallerPackage(String packageName) {
+ InstallSource setInitiatingPackageSignatures(@Nullable PackageSignatures signatures) {
+ if (signatures == initiatingPackageSignatures) {
+ return this;
+ }
+ return createInternal(initiatingPackageName, originatingPackageName, installerPackageName,
+ isOrphaned, isInitiatingPackageUninstalled, signatures);
+ }
+
+ /**
+ * Return an InstallSource the same as this one updated to reflect that the specified installer
+ * package name has been uninstalled.
+ */
+ InstallSource removeInstallerPackage(@Nullable String packageName) {
if (packageName == null) {
return this;
}
boolean modified = false;
- String initiatingPackageName = this.initiatingPackageName;
+ boolean isInitiatingPackageUninstalled = this.isInitiatingPackageUninstalled;
String originatingPackageName = this.originatingPackageName;
String installerPackageName = this.installerPackageName;
boolean isOrphaned = this.isOrphaned;
- if (packageName.equals(initiatingPackageName)) {
- initiatingPackageName = null;
- modified = true;
+ if (packageName.equals(this.initiatingPackageName)) {
+ if (!isInitiatingPackageUninstalled) {
+ // In this case we deliberately do not clear the package name (and signatures).
+ // We allow an app to retrieve details of its own install initiator even after
+ // it has been uninstalled.
+ isInitiatingPackageUninstalled = true;
+ modified = true;
+ }
}
if (packageName.equals(originatingPackageName)) {
originatingPackageName = null;
@@ -141,8 +198,9 @@ final class InstallSource {
if (!modified) {
return this;
}
+
return createInternal(initiatingPackageName, originatingPackageName, installerPackageName,
- isOrphaned);
+ isOrphaned, isInitiatingPackageUninstalled, initiatingPackageSignatures);
}
@Nullable
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index e2dfa126225f..c43f23454ca6 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -635,7 +635,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
InstallSource installSource = InstallSource.create(installerPackageName,
- originatingPackageName, requestedInstallerPackageName, false);
+ originatingPackageName, requestedInstallerPackageName);
session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid,
installSource, params, createdMillis,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 426cd01d3d0b..97a2d43e6183 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -140,6 +140,7 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@@ -209,6 +210,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
private static final int[] EMPTY_CHILD_SESSION_ARRAY = {};
+ private static final String SYSTEM_DATA_LOADER_PACKAGE = "android";
+
// TODO: enforce INSTALL_ALLOW_TEST
// TODO: enforce INSTALL_ALLOW_DOWNGRADE
@@ -555,6 +558,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
params.dataLoaderParams);
}
}
+
+ if (isStreamingInstallation()
+ && this.params.dataLoaderParams.getComponentName().getPackageName()
+ == SYSTEM_DATA_LOADER_PACKAGE) {
+ assertShellOrSystemCalling("System data loaders");
+ }
}
public SessionInfo generateInfo() {
@@ -770,6 +779,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ private void assertShellOrSystemCalling(String operation) {
+ switch (Binder.getCallingUid()) {
+ case android.os.Process.SHELL_UID:
+ case android.os.Process.ROOT_UID:
+ case android.os.Process.SYSTEM_UID:
+ break;
+ default:
+ throw new SecurityException(operation + " only supported from shell or system");
+ }
+ }
+
private void assertCanWrite(boolean reverseMode) {
if (isDataLoaderInstallation()) {
throw new IllegalStateException(
@@ -780,15 +800,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
assertPreparedAndNotSealedLocked("assertCanWrite");
}
if (reverseMode) {
- switch (Binder.getCallingUid()) {
- case android.os.Process.SHELL_UID:
- case android.os.Process.ROOT_UID:
- case android.os.Process.SYSTEM_UID:
- break;
- default:
- throw new SecurityException(
- "Reverse mode only supported from shell or system");
- }
+ assertShellOrSystemCalling("Reverse mode");
}
}
@@ -1025,13 +1037,24 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}
- private class FileSystemConnector extends IPackageInstallerSessionFileSystemConnector.Stub {
+ private final class FileSystemConnector extends
+ IPackageInstallerSessionFileSystemConnector.Stub {
+ final Set<String> mAddedFiles;
+
+ FileSystemConnector(List<InstallationFile> addedFiles) {
+ mAddedFiles = addedFiles.stream().map(file -> file.getName()).collect(
+ Collectors.toSet());
+ }
+
@Override
public void writeData(String name, long offsetBytes, long lengthBytes,
ParcelFileDescriptor incomingFd) {
if (incomingFd == null) {
throw new IllegalArgumentException("incomingFd can't be null");
}
+ if (!mAddedFiles.contains(name)) {
+ throw new SecurityException("File name is not in the list of added files.");
+ }
try {
doWriteInternal(name, offsetBytes, lengthBytes, incomingFd);
} catch (IOException e) {
@@ -1452,7 +1475,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
mInstallerUid = uid;
- mInstallSource = InstallSource.create(packageName, null, packageName, false);
+ mInstallSource = InstallSource.create(packageName, null, packageName);
}
} catch (PackageManager.NameNotFoundException e) {
onSessionTransferStatus(statusReceiver, packageName,
@@ -2467,8 +2490,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return;
}
- FileSystemConnector connector = new FileSystemConnector();
-
List<InstallationFile> addedFiles = mFiles.stream().filter(
file -> sAddedFilter.accept(new File(file.name))).map(
file -> new InstallationFile(
@@ -2480,6 +2501,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
0, file.name.length() - REMOVE_MARKER_EXTENSION.length())).collect(
Collectors.toList());
+ final FileSystemConnector connector = new FileSystemConnector(addedFiles);
+
DataLoaderManager dataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
if (dataLoaderManager == null) {
throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
@@ -2515,11 +2538,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
};
- final DataLoaderParams params = this.params.dataLoaderParams;
-
final FileSystemControlParcel control = new FileSystemControlParcel();
control.callback = connector;
+ final DataLoaderParams params = this.params.dataLoaderParams;
+
Bundle dataLoaderParams = new Bundle();
dataLoaderParams.putParcelable("componentName", params.getComponentName());
dataLoaderParams.putParcelable("control", control);
@@ -3115,7 +3138,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
InstallSource installSource = InstallSource.create(installInitiatingPackageName,
- installOriginatingPackageName, installerPackageName, false);
+ installOriginatingPackageName, installerPackageName);
return new PackageInstallerSession(callback, context, pm, sessionProvider,
installerThread, stagingManager, sessionId, userId, installerUid,
installSource, params, createdMillis, stageDir, stageCid, fileInfosArray,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 70550ee27b8e..b26e6c7021c1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13452,9 +13452,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Okay!
targetPackageSetting.setInstallerPackageName(installerPackageName);
- if (installerPackageName != null) {
- mSettings.mInstallerPackages.add(installerPackageName);
- }
+ mSettings.addInstallerPackageNames(targetPackageSetting.installSource);
scheduleWriteSettingsLocked();
}
}
@@ -15160,9 +15158,10 @@ public class PackageManagerService extends IPackageManager.Stub
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
final String pkgName = pkg.getPackageName();
- final String installerPackageName = installArgs.installSource.installerPackageName;
final int[] installedForUsers = res.origUsers;
final int installReason = installArgs.installReason;
+ InstallSource installSource = installArgs.installSource;
+ final String installerPackageName = installSource.installerPackageName;
if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getCodePath());
synchronized (mLock) {
@@ -15171,7 +15170,7 @@ public class PackageManagerService extends IPackageManager.Stub
// For system-bundled packages, we assume that installing an upgraded version
// of the package implies that the user actually wants to run that new code,
// so we enable the package.
- PackageSetting ps = mSettings.mPackages.get(pkgName);
+ final PackageSetting ps = mSettings.mPackages.get(pkgName);
final int userId = installArgs.user.getIdentifier();
if (ps != null) {
if (isSystemApp(pkg)) {
@@ -15208,8 +15207,16 @@ public class PackageManagerService extends IPackageManager.Stub
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
}
- ps.setInstallSource(installArgs.installSource);
-
+ if (installSource.initiatingPackageName != null) {
+ final PackageSetting ips = mSettings.mPackages.get(
+ installSource.initiatingPackageName);
+ if (ips != null) {
+ installSource = installSource.setInitiatingPackageSignatures(
+ ips.signatures);
+ }
+ }
+ ps.setInstallSource(installSource);
+ mSettings.addInstallerPackageNames(installSource);
// When replacing an existing package, preserve the original install reason for all
// users that had the package installed before.
@@ -15239,7 +15246,6 @@ public class PackageManagerService extends IPackageManager.Stub
res.name = pkgName;
res.uid = pkg.getUid();
res.pkg = pkg;
- mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
//to update install status
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
@@ -19374,7 +19380,7 @@ public class PackageManagerService extends IPackageManager.Stub
// PermissionController manages default home directly.
return false;
}
- mPermissionManager.setDefaultHome(currentPackageName, userId, (successful) -> {
+ mPermissionManager.setDefaultHome(packageName, userId, (successful) -> {
if (successful) {
postPreferredActivityChangedBroadcast(userId);
}
@@ -19978,19 +19984,25 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- // All installSource strings are interned, so == is ok here
- if (installSource.initiatingPackageName == installSource.installerPackageName) {
- // The installer and initiator will often be the same, and when they are
- // we can skip doing the same check again.
- initiatingPackageName = installerPackageName;
+ if (installSource.isInitiatingPackageUninstalled) {
+ // TODO(b/146555198) Allow the app itself to see the info
+ // (at least for non-instant apps)
+ initiatingPackageName = null;
} else {
- initiatingPackageName = installSource.initiatingPackageName;
- final PackageSetting ps = mSettings.mPackages.get(initiatingPackageName);
- if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
- initiatingPackageName = null;
+ // All installSource strings are interned, so == is ok here
+ if (installSource.initiatingPackageName == installSource.installerPackageName) {
+ // The installer and initiator will often be the same, and when they are
+ // we can skip doing the same check again.
+ initiatingPackageName = installerPackageName;
+ } else {
+ initiatingPackageName = installSource.initiatingPackageName;
+ final PackageSetting ps = mSettings.mPackages.get(initiatingPackageName);
+ if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ initiatingPackageName = null;
+ }
}
-
}
+
originatingPackageName = installSource.originatingPackageName;
if (originatingPackageName != null) {
final PackageSetting ps = mSettings.mPackages.get(originatingPackageName);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 10e2780863d8..5adab378bb73 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -34,7 +34,6 @@ import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
-import android.content.pm.DataLoaderParams;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageInstaller;
@@ -137,10 +136,6 @@ class PackageManagerShellCommand extends ShellCommand {
private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
private static final int DEFAULT_WAIT_MS = 60 * 1000;
- private static final String DATA_LOADER_PACKAGE = "android";
- private static final String DATA_LOADER_CLASS =
- "com.android.server.pm.PackageManagerShellCommandDataLoader";
-
final IPackageManager mInterface;
final IPermissionManager mPermissionManager;
final private WeakHashMap<String, Resources> mResourceCache =
@@ -164,7 +159,7 @@ class PackageManagerShellCommand extends ShellCommand {
final PrintWriter pw = getOutPrintWriter();
try {
- switch(cmd) {
+ switch (cmd) {
case "path":
return runPath();
case "dump":
@@ -1163,9 +1158,8 @@ class PackageManagerShellCommand extends ShellCommand {
private int runStreamingInstall() throws RemoteException {
final InstallParams params = makeInstallParams();
if (params.sessionParams.dataLoaderParams == null) {
- final DataLoaderParams dataLoaderParams = DataLoaderParams.forStreaming(
- new ComponentName(DATA_LOADER_PACKAGE, DATA_LOADER_CLASS), "");
- params.sessionParams.setDataLoaderParams(dataLoaderParams);
+ params.sessionParams.setDataLoaderParams(
+ PackageManagerShellCommandDataLoader.getDataLoaderParams(this));
}
return doRunInstall(params);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
index 1ee9ab8927bb..a814cb8942e2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
@@ -17,18 +17,22 @@
package com.android.server.pm;
import android.annotation.NonNull;
+import android.content.ComponentName;
import android.content.pm.DataLoaderParams;
import android.content.pm.InstallationFile;
import android.os.ParcelFileDescriptor;
+import android.os.ShellCommand;
import android.service.dataloader.DataLoaderService;
import android.text.TextUtils;
import android.util.Slog;
+import android.util.SparseArray;
import libcore.io.IoUtils;
-import java.io.File;
import java.io.IOException;
+import java.lang.ref.WeakReference;
import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
import java.util.Collection;
/**
@@ -37,41 +41,109 @@ import java.util.Collection;
public class PackageManagerShellCommandDataLoader extends DataLoaderService {
public static final String TAG = "PackageManagerShellCommandDataLoader";
+ private static final String PACKAGE = "android";
+ private static final String CLASS = PackageManagerShellCommandDataLoader.class.getName();
+
+ static final SecureRandom sRandom = new SecureRandom();
+ static final SparseArray<WeakReference<ShellCommand>> sShellCommands = new SparseArray<>();
+
+ private static final char ARGS_DELIM = '&';
+ private static final String SHELL_COMMAND_ID_PREFIX = "shellCommandId=";
+ private static final int INVALID_SHELL_COMMAND_ID = -1;
+ private static final int TOO_MANY_PENDING_SHELL_COMMANDS = 10;
+
+ private static final String STDIN_PATH = "-";
+
+ static DataLoaderParams getDataLoaderParams(ShellCommand shellCommand) {
+ int commandId;
+ synchronized (sShellCommands) {
+ // Clean up old references.
+ for (int i = sShellCommands.size() - 1; i >= 0; i--) {
+ WeakReference<ShellCommand> oldRef = sShellCommands.valueAt(i);
+ if (oldRef.get() == null) {
+ sShellCommands.removeAt(i);
+ }
+ }
+
+ // Sanity check.
+ if (sShellCommands.size() > TOO_MANY_PENDING_SHELL_COMMANDS) {
+ Slog.e(TAG, "Too many pending shell commands: " + sShellCommands.size());
+ }
+
+ // Generate new id and put ref to the array.
+ do {
+ commandId = sRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
+ } while (sShellCommands.contains(commandId));
+
+ sShellCommands.put(commandId, new WeakReference<>(shellCommand));
+ }
+
+ final String args = SHELL_COMMAND_ID_PREFIX + commandId;
+ return DataLoaderParams.forStreaming(new ComponentName(PACKAGE, CLASS), args);
+ }
+
+ private static int extractShellCommandId(String args) {
+ int sessionIdIdx = args.indexOf(SHELL_COMMAND_ID_PREFIX);
+ if (sessionIdIdx < 0) {
+ Slog.e(TAG, "Missing shell command id param.");
+ return INVALID_SHELL_COMMAND_ID;
+ }
+ sessionIdIdx += SHELL_COMMAND_ID_PREFIX.length();
+ int delimIdx = args.indexOf(ARGS_DELIM, sessionIdIdx);
+ try {
+ if (delimIdx < 0) {
+ return Integer.parseInt(args.substring(sessionIdIdx));
+ } else {
+ return Integer.parseInt(args.substring(sessionIdIdx, delimIdx));
+ }
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Incorrect shell command id format.", e);
+ return INVALID_SHELL_COMMAND_ID;
+ }
+ }
+
static class DataLoader implements DataLoaderService.DataLoader {
- private ParcelFileDescriptor mInFd = null;
+ private DataLoaderParams mParams = null;
private FileSystemConnector mConnector = null;
- private static final String STDIN_PATH = "-";
-
@Override
public boolean onCreate(@NonNull DataLoaderParams dataLoaderParams,
@NonNull FileSystemConnector connector) {
+ mParams = dataLoaderParams;
mConnector = connector;
return true;
}
+
@Override
public boolean onPrepareImage(Collection<InstallationFile> addedFiles,
Collection<String> removedFiles) {
+ final int commandId = extractShellCommandId(mParams.getArguments());
+ if (commandId == INVALID_SHELL_COMMAND_ID) {
+ return false;
+ }
+
+ final WeakReference<ShellCommand> shellCommandRef;
+ synchronized (sShellCommands) {
+ shellCommandRef = sShellCommands.get(commandId, null);
+ }
+ final ShellCommand shellCommand =
+ shellCommandRef != null ? shellCommandRef.get() : null;
+ if (shellCommand == null) {
+ Slog.e(TAG, "Missing shell command.");
+ return false;
+ }
try {
for (InstallationFile fileInfo : addedFiles) {
String filePath = new String(fileInfo.getMetadata(), StandardCharsets.UTF_8);
if (STDIN_PATH.equals(filePath) || TextUtils.isEmpty(filePath)) {
- // TODO(b/146080380): add support for STDIN installations.
- if (mInFd == null) {
- Slog.e(TAG, "Invalid stdin file descriptor.");
- return false;
- }
- ParcelFileDescriptor inFd = ParcelFileDescriptor.dup(
- mInFd.getFileDescriptor());
+ final ParcelFileDescriptor inFd = ParcelFileDescriptor.dup(
+ shellCommand.getInFileDescriptor());
mConnector.writeData(fileInfo.getName(), 0, fileInfo.getSize(), inFd);
} else {
- File localFile = new File(filePath);
ParcelFileDescriptor incomingFd = null;
try {
- // TODO(b/146080380): open files via callback into shell command.
- incomingFd = ParcelFileDescriptor.open(localFile,
- ParcelFileDescriptor.MODE_READ_ONLY);
- mConnector.writeData(fileInfo.getName(), 0, localFile.length(),
+ incomingFd = shellCommand.openFileForSystem(filePath, "r");
+ mConnector.writeData(fileInfo.getName(), 0, incomingFd.getStatSize(),
incomingFd);
} finally {
IoUtils.closeQuietly(incomingFd);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 9642a1a21cf3..ec84b51577f9 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -280,8 +280,11 @@ public final class Settings {
/** Map from package name to settings */
final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
- /** List of packages that installed other packages */
- final ArraySet<String> mInstallerPackages = new ArraySet<>();
+ /**
+ * List of packages that were involved in installing other packages, i.e. are listed
+ * in at least one app's InstallSource.
+ */
+ private final ArraySet<String> mInstallerPackages = new ArraySet<>();
/** Map from package name to appId and excluded userids */
private final ArrayMap<String, KernelPackageState> mKernelMapping = new ArrayMap<>();
@@ -441,16 +444,6 @@ public final class Settings {
return mPermissions.canPropagatePermissionToInstantApp(permName);
}
- void setInstallerPackageName(String pkgName, String installerPkgName) {
- PackageSetting p = mPackages.get(pkgName);
- if (p != null) {
- p.setInstallerPackageName(installerPkgName);
- if (installerPkgName != null) {
- mInstallerPackages.add(installerPkgName);
- }
- }
- }
-
/** Gets and optionally creates a new shared user id. */
SharedUserSetting getSharedUserLPw(String name, int pkgFlags, int pkgPrivateFlags,
boolean create) throws PackageManagerException {
@@ -2826,6 +2819,9 @@ public final class Settings {
if (installSource.initiatingPackageName != null) {
serializer.attribute(null, "installInitiator", installSource.initiatingPackageName);
}
+ if (installSource.isInitiatingPackageUninstalled) {
+ serializer.attribute(null, "installInitiatorUninstalled", "true");
+ }
if (installSource.originatingPackageName != null) {
serializer.attribute(null, "installOriginator", installSource.originatingPackageName);
}
@@ -2843,6 +2839,11 @@ public final class Settings {
pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
+ if (installSource.initiatingPackageSignatures != null) {
+ installSource.initiatingPackageSignatures.writeXml(
+ serializer, "install-initiator-sigs", mPastSignatures);
+ }
+
writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissionStates());
writeSigningKeySetLPr(serializer, pkg.keySetData);
@@ -3578,6 +3579,7 @@ public final class Settings {
String isOrphaned = null;
String installOriginatingPackageName = null;
String installInitiatingPackageName = null;
+ String installInitiatorUninstalled = null;
String volumeUuid = null;
String categoryHintString = null;
String updateAvailable = null;
@@ -3623,6 +3625,8 @@ public final class Settings {
isOrphaned = parser.getAttributeValue(null, "isOrphaned");
installInitiatingPackageName = parser.getAttributeValue(null, "installInitiator");
installOriginatingPackageName = parser.getAttributeValue(null, "installOriginator");
+ installInitiatorUninstalled = parser.getAttributeValue(null,
+ "installInitiatorUninstalled");
volumeUuid = parser.getAttributeValue(null, "volumeUuid");
categoryHintString = parser.getAttributeValue(null, "categoryHint");
if (categoryHintString != null) {
@@ -3777,9 +3781,11 @@ public final class Settings {
}
if (packageSetting != null) {
packageSetting.uidError = "true".equals(uidError);
- packageSetting.installSource = InstallSource.create(
+ InstallSource installSource = InstallSource.create(
installInitiatingPackageName, installOriginatingPackageName,
- installerPackageName, "true".equals(isOrphaned));
+ installerPackageName, "true".equals(isOrphaned),
+ "true".equals(installInitiatorUninstalled));
+ packageSetting.installSource = installSource;
packageSetting.volumeUuid = volumeUuid;
packageSetting.categoryHint = categoryHint;
packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr;
@@ -3809,9 +3815,7 @@ public final class Settings {
packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
}
- if (installerPackageName != null) {
- mInstallerPackages.add(installerPackageName);
- }
+ addInstallerPackageNames(installSource);
int outerDepth = parser.getDepth();
int type;
@@ -3857,6 +3861,11 @@ public final class Settings {
mKeySetRefs.put(id, 1);
}
packageSetting.keySetData.addDefinedKeySet(id, alias);
+ } else if (tagName.equals("install-initiator-sigs")) {
+ final PackageSignatures signatures = new PackageSignatures();
+ signatures.readXml(parser, mPastSignatures);
+ packageSetting.installSource =
+ packageSetting.installSource.setInitiatingPackageSignatures(signatures);
} else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
readDomainVerificationLPw(parser, packageSetting);
} else {
@@ -3870,6 +3879,18 @@ public final class Settings {
}
}
+ void addInstallerPackageNames(InstallSource installSource) {
+ if (installSource.installerPackageName != null) {
+ mInstallerPackages.add(installSource.installerPackageName);
+ }
+ if (installSource.initiatingPackageName != null) {
+ mInstallerPackages.add(installSource.initiatingPackageName);
+ }
+ if (installSource.originatingPackageName != null) {
+ mInstallerPackages.add(installSource.originatingPackageName);
+ }
+ }
+
private void readDisabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser,
int userId) throws IOException, XmlPullParserException {
int outerDepth = parser.getDepth();
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index e7269a6d9498..a86c8d7545b1 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -58,6 +58,7 @@ import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.IntPair;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
@@ -68,7 +69,7 @@ import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
/**
* This is a permission policy that governs over all permission mechanism
@@ -280,7 +281,7 @@ public final class PermissionPolicyService extends SystemService {
if (DEBUG) Slog.i(LOG_TAG, "defaultPermsWereGrantedSinceBoot(" + userId + ")");
// Now call into the permission controller to apply policy around permissions
- final CountDownLatch latch = new CountDownLatch(1);
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
// We need to create a local manager that does not schedule work on the main
// there as we are on the main thread and want to block until the work is
@@ -290,22 +291,22 @@ public final class PermissionPolicyService extends SystemService {
getUserContext(getContext(), UserHandle.of(userId)),
FgThread.getHandler());
permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions(
- FgThread.getExecutor(),
- (Boolean success) -> {
- if (!success) {
+ FgThread.getExecutor(), successful -> {
+ if (successful) {
+ future.complete(null);
+ } else {
// We are in an undefined state now, let us crash and have
// rescue party suggest a wipe to recover to a good one.
- final String message = "Error granting/upgrading runtime permissions";
+ final String message = "Error granting/upgrading runtime permissions"
+ + " for user " + userId;
Slog.wtf(LOG_TAG, message);
- throw new IllegalStateException(message);
+ future.completeExceptionally(new IllegalStateException(message));
}
- latch.countDown();
- }
- );
+ });
try {
- latch.await();
- } catch (InterruptedException e) {
- /* ignore */
+ future.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new IllegalStateException(e);
}
permissionControllerManager.updateUserSensitive();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5a124a717de2..ea83adba4d8a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -562,10 +562,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private boolean mScreenshotChordPowerKeyTriggered;
private long mScreenshotChordPowerKeyTime;
- private static final long MOVING_DISPLAY_TO_TOP_DURATION_MILLIS = 10;
- private volatile boolean mMovingDisplayToTopKeyTriggered;
- private volatile long mMovingDisplayToTopKeyTime;
-
// Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
private int mRingerToggleChord = VOLUME_HUSH_OFF;
@@ -633,7 +629,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private static final int MSG_POWER_VERY_LONG_PRESS = 25;
private static final int MSG_NOTIFY_USER_ACTIVITY = 26;
private static final int MSG_RINGER_TOGGLE_CHORD = 27;
- private static final int MSG_MOVE_DISPLAY_TO_TOP = 28;
private class PolicyHandler extends Handler {
@Override
@@ -697,7 +692,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
accessibilityShortcutActivated();
break;
case MSG_BUGREPORT_TV:
- requestFullBugreport();
+ requestFullBugreportOrLaunchHandlerApp();
break;
case MSG_ACCESSIBILITY_TV:
if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(false)) {
@@ -723,10 +718,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case MSG_RINGER_TOGGLE_CHORD:
handleRingerChordGesture();
break;
- case MSG_MOVE_DISPLAY_TO_TOP:
- mWindowManagerFuncs.moveDisplayToTop(msg.arg1);
- mMovingDisplayToTopKeyTriggered = false;
- break;
}
}
}
@@ -2545,36 +2536,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
int policyFlags) {
- final long result = interceptKeyBeforeDispatchingInner(focusedToken, event, policyFlags);
- final int eventDisplayId = event.getDisplayId();
- if (result == 0 && !mPerDisplayFocusEnabled
- && eventDisplayId != INVALID_DISPLAY && eventDisplayId != mTopFocusedDisplayId) {
- // An event is targeting a non-focused display. Try to move the display to top so that
- // it can become the focused display to interact with the user.
- final long eventDownTime = event.getDownTime();
- if (mMovingDisplayToTopKeyTime < eventDownTime) {
- // We have not handled this event yet. Move the display to top, and then tell
- // dispatcher to try again later.
- mMovingDisplayToTopKeyTime = eventDownTime;
- mMovingDisplayToTopKeyTriggered = true;
- mHandler.sendMessage(
- mHandler.obtainMessage(MSG_MOVE_DISPLAY_TO_TOP, eventDisplayId, 0));
- return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
- } else if (mMovingDisplayToTopKeyTriggered) {
- // The message has not been handled yet. Tell dispatcher to try again later.
- return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
- }
- // The target display is still not the top focused display. Drop the event because the
- // display may not contain any window which can receive keys.
- Slog.w(TAG, "Dropping key targeting non-focused display #" + eventDisplayId
- + " keyCode=" + KeyEvent.keyCodeToString(event.getKeyCode()));
- return -1;
- }
- return result;
- }
-
- private long interceptKeyBeforeDispatchingInner(IBinder focusedToken, KeyEvent event,
- int policyFlags) {
final boolean keyguardOn = keyguardOn();
final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
@@ -3061,12 +3022,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return mAccessibilityTvScheduled;
}
- private void requestFullBugreport() {
+ private void requestFullBugreportOrLaunchHandlerApp() {
if ("1".equals(SystemProperties.get("ro.debuggable"))
|| Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1) {
try {
- ActivityManager.getService().requestFullBugReport();
+ if (!ActivityManager.getService().launchBugReportHandlerApp()) {
+ ActivityManager.getService().requestFullBugReport();
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Error taking bugreport", e);
}
@@ -3613,7 +3576,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
final int displayId = event.getDisplayId();
-
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
// If screen is off then we treat the case where the keyguard is open but hidden
@@ -4035,6 +3997,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY");
}
+ if ((result & ACTION_PASS_TO_USER) != 0) {
+ // If the key event is targeted to a specific display, then the user is interacting with
+ // that display. Therefore, give focus to the display that the user is interacting with.
+ if (!mPerDisplayFocusEnabled
+ && displayId != INVALID_DISPLAY && displayId != mTopFocusedDisplayId) {
+ // An event is targeting a non-focused display. Move the display to top so that
+ // it can become the focused display to interact with the user.
+ // This should be done asynchronously, once the focus logic is fully moved to input
+ // from windowmanager. Currently, we need to ensure the setInputWindows completes,
+ // which would force the focus event to be queued before the current key event.
+ // TODO(b/70668286): post call to 'moveDisplayToTop' to mHandler instead
+ Log.i(TAG, "Moving non-focused display " + displayId + " to top "
+ + "because a key is targeting it");
+ mWindowManagerFuncs.moveDisplayToTop(displayId);
+ }
+ }
+
return result;
}
@@ -5213,7 +5192,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final Intent dock = createHomeDockIntent();
if (dock != null) {
int result = ActivityTaskManager.getService()
- .startActivityAsUser(null, null, dock,
+ .startActivityAsUser(null, mContext.getBasePackageName(), dock,
dock.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
@@ -5224,7 +5203,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
int result = ActivityTaskManager.getService()
- .startActivityAsUser(null, null, mHomeIntent,
+ .startActivityAsUser(null, mContext.getBasePackageName(), mHomeIntent,
mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index b4f4eca5f188..f661b5e0d8a8 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -22,7 +22,7 @@ import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 02656eaf5c6c..da848d87ba71 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -24,10 +24,10 @@ import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
+import android.os.TimestampedValue;
import android.telephony.TelephonyManager;
import android.util.LocalLog;
import android.util.Slog;
-import android.util.TimestampedValue;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 94c2192b620f..23b94bdb74c8 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -751,10 +751,10 @@ class ActivityMetricsLogger {
if (abort) {
launchObserverNotifyActivityLaunchCancelled(info);
} else {
- logAppTransitionFinished(info);
if (info.isInterestingToLoggerAndObserver()) {
launchObserverNotifyActivityLaunchFinished(info, timestampNs);
}
+ logAppTransitionFinished(info);
}
info.mPendingDrawActivities.clear();
mTransitionInfoList.remove(info);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 65d0c4c2515f..26d76a8d6e28 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -243,9 +243,9 @@ import android.app.servertransaction.NewIntentItem;
import android.app.servertransaction.PauseActivityItem;
import android.app.servertransaction.PipModeChangeItem;
import android.app.servertransaction.ResumeActivityItem;
+import android.app.servertransaction.StartActivityItem;
import android.app.servertransaction.StopActivityItem;
import android.app.servertransaction.TopResumedActivityChangeItem;
-import android.app.servertransaction.WindowVisibilityItem;
import android.app.usage.UsageEvents.Event;
import android.content.ComponentName;
import android.content.Intent;
@@ -4497,7 +4497,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
sleeping = false;
app.postPendingUiCleanMsg(true);
if (reportToClient) {
- makeClientVisible();
+ mClientVisibilityDeferred = false;
+ makeActiveIfNeeded(starting);
} else {
mClientVisibilityDeferred = true;
}
@@ -4511,23 +4512,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
handleAlreadyVisible();
}
- /** Send visibility change message to the client and pause if needed. */
- void makeClientVisible() {
- mClientVisibilityDeferred = false;
- try {
- mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
- WindowVisibilityItem.obtain(true /* showWindow */));
- makeActiveIfNeeded(null /* activeActivity*/);
- if (isState(STOPPING, STOPPED)) {
- // Set state to STARTED in order to have consistent state with client while
- // making an non-active activity visible from stopped.
- setState(STARTED, "makeClientVisible");
- }
- } catch (Exception e) {
- Slog.w(TAG, "Exception thrown sending visibility update: " + intent.getComponent(), e);
- }
- }
-
void makeInvisible() {
if (!mVisibleRequested) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this);
@@ -4556,14 +4540,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
switch (getState()) {
case STOPPING:
case STOPPED:
- if (attachedToProcess()) {
- if (DEBUG_VISIBILITY) {
- Slog.v(TAG_VISIBILITY, "Scheduling invisibility: " + this);
- }
- mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(),
- appToken, WindowVisibilityItem.obtain(false /* showWindow */));
- }
-
// Reset the flag indicating that an app can enter picture-in-picture once the
// activity is hidden
supportsEnterPipOnTaskSwitch = false;
@@ -4595,17 +4571,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean makeActiveIfNeeded(ActivityRecord activeActivity) {
if (shouldResumeActivity(activeActivity)) {
if (DEBUG_VISIBILITY) {
- Slog.v("TAG_VISIBILITY", "Resume visible activity, " + this);
+ Slog.v(TAG_VISIBILITY, "Resume visible activity, " + this);
}
return getActivityStack().resumeTopActivityUncheckedLocked(activeActivity /* prev */,
null /* options */);
} else if (shouldPauseActivity(activeActivity)) {
if (DEBUG_VISIBILITY) {
- Slog.v("TAG_VISIBILITY", "Pause visible activity, " + this);
+ Slog.v(TAG_VISIBILITY, "Pause visible activity, " + this);
}
// An activity must be in the {@link PAUSING} state for the system to validate
// the move to {@link PAUSED}.
- setState(PAUSING, "makeVisibleIfNeeded");
+ setState(PAUSING, "makeActiveIfNeeded");
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
PauseActivityItem.obtain(finishing, false /* userLeaving */,
@@ -4613,6 +4589,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
}
+ } else if (shouldStartActivity()) {
+ if (DEBUG_VISIBILITY) {
+ Slog.v(TAG_VISIBILITY, "Start visible activity, " + this);
+ }
+ setState(STARTED, "makeActiveIfNeeded");
+ try {
+ mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
+ StartActivityItem.obtain());
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e);
+ }
}
return false;
}
@@ -4656,6 +4643,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
+ * Check if activity should be moved to STARTED state.
+ * NOTE: This will not check if activity should be made paused or resumed first, so it must only
+ * be called after checking with {@link #shouldResumeActivity(ActivityRecord)}
+ * and {@link #shouldPauseActivity(ActivityRecord)}.
+ */
+ private boolean shouldStartActivity() {
+ return mVisibleRequested && isState(STOPPED);
+ }
+
+ /**
* Check if activity is eligible to be made active (resumed of paused). The activity:
* - should be paused, stopped or stopping
* - should not be the currently active one or launching behind other tasks
@@ -4890,16 +4887,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
setState(STOPPING, "stopIfPossible");
if (DEBUG_VISIBILITY) {
- Slog.v(TAG_VISIBILITY, "Stopping visibleRequested="
- + mVisibleRequested + " for " + this);
- }
- if (!mVisibleRequested) {
- setVisibility(false);
+ Slog.v(TAG_VISIBILITY, "Stopping:" + this);
}
EventLogTags.writeWmStopActivity(
mUserId, System.identityHashCode(this), shortComponentName);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
- StopActivityItem.obtain(mVisibleRequested, configChangeFlags));
+ StopActivityItem.obtain(configChangeFlags));
+
if (stack.shouldSleepOrShutDownActivities()) {
setSleeping(true);
}
@@ -6107,11 +6101,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// This also avoids if the next activity never reports idle (e.g. animating view),
// the previous will need to wait until idle timeout to be stopped or destroyed.
mStackSupervisor.scheduleProcessStoppingAndFinishingActivities();
- } else {
- // Instead of doing the full stop routine here, let's just hide any activities
- // we now can, and let them stop when the normal idle happens.
- mStackSupervisor.processStoppingActivities(null /* launchedActivity */,
- true /* onlyUpdateVisibility */, true /* unused */, null /* unused */);
}
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -7206,7 +7195,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// {@link ActivityTaskManagerService.activityStopped}).
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
- StopActivityItem.obtain(false /* showWindow */, 0 /* configChanges */));
+ StopActivityItem.obtain(0 /* configChanges */));
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown during restart " + this, e);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index e8564fc80ac3..d63165adb2f8 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -83,6 +83,7 @@ import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -2076,54 +2077,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
boolean processPausingActivities, String reason) {
// Stop any activities that are scheduled to do so but have been waiting for the transition
// animation to finish.
- processStoppingActivities(launchedActivity, false /* onlyUpdateVisibility */,
- processPausingActivities, reason);
-
- final int numFinishingActivities = mFinishingActivities.size();
- if (numFinishingActivities == 0) {
- return;
- }
-
- // Finish any activities that are scheduled to do so but have been waiting for the next one
- // to start.
- final ArrayList<ActivityRecord> finishingActivities = new ArrayList<>(mFinishingActivities);
- mFinishingActivities.clear();
- for (int i = 0; i < numFinishingActivities; i++) {
- final ActivityRecord r = finishingActivities.get(i);
- if (r.isInHistory()) {
- r.destroyImmediately(true /* removeFromApp */, "finish-" + reason);
- }
- }
- }
-
- /** Stop or destroy the stopping activities if they are not interactive. */
- void processStoppingActivities(ActivityRecord launchedActivity, boolean onlyUpdateVisibility,
- boolean processPausingActivities, String reason) {
- final int numStoppingActivities = mStoppingActivities.size();
- if (numStoppingActivities == 0) {
- return;
- }
ArrayList<ActivityRecord> readyToStopActivities = null;
-
- final boolean nowVisible = mRootWindowContainer.allResumedActivitiesVisible();
- for (int activityNdx = numStoppingActivities - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord s = mStoppingActivities.get(activityNdx);
- if (nowVisible && s.finishing) {
-
- // If this activity is finishing, it is sitting on top of
- // everyone else but we now know it is no longer needed...
- // so get rid of it. Otherwise, we need to go through the
- // normal flow and hide it once we determine that it is
- // hidden by the activities in front of it.
- if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
- s.setVisibility(false);
- }
- if (onlyUpdateVisibility) {
- continue;
- }
-
- final boolean animating = s.isAnimating(TRANSITION);
- if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
+ for (int i = mStoppingActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord s = mStoppingActivities.get(i);
+ final boolean animating = s.isAnimating(TRANSITION | PARENTS);
+ if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + s.nowVisible
+ " animating=" + animating + " finishing=" + s.finishing);
final ActivityStack stack = s.getActivityStack();
@@ -2145,7 +2103,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
readyToStopActivities.add(s);
- mStoppingActivities.remove(activityNdx);
+ mStoppingActivities.remove(i);
}
}
@@ -2161,6 +2119,22 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
}
}
+
+ final int numFinishingActivities = mFinishingActivities.size();
+ if (numFinishingActivities == 0) {
+ return;
+ }
+
+ // Finish any activities that are scheduled to do so but have been waiting for the next one
+ // to start.
+ final ArrayList<ActivityRecord> finishingActivities = new ArrayList<>(mFinishingActivities);
+ mFinishingActivities.clear();
+ for (int i = 0; i < numFinishingActivities; i++) {
+ final ActivityRecord r = finishingActivities.get(i);
+ if (r.isInHistory()) {
+ r.destroyImmediately(true /* removeFromApp */, "finish-" + reason);
+ }
+ }
}
void removeHistoryRecords(WindowProcessController app) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 76c0e4eeecae..474c5c960eb0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -7203,7 +7203,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
ActivityManagerServiceDumpProcessesProto.VR_CONTROLLER);
if (mController != null) {
final long token = proto.start(CONTROLLER);
- proto.write(CONTROLLER, mController.toString());
+ proto.write(ActivityManagerServiceDumpProcessesProto.Controller.CONTROLLER,
+ mController.toString());
proto.write(IS_A_MONKEY, mControllerIsAMonkey);
proto.end(token);
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 09111d07e8c1..014cb76c0064 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -436,10 +436,9 @@ public class AppTransition implements Dump {
mNextAppTransition = TRANSIT_UNSET;
mNextAppTransitionFlags = 0;
setAppTransitionState(APP_STATE_RUNNING);
- final AnimationAdapter topOpeningAnim =
- (topOpeningApp != null && topOpeningApp.getAnimatingContainer() != null)
- ? topOpeningApp.getAnimatingContainer().getAnimation()
- : null;
+ final WindowContainer wc =
+ topOpeningApp != null ? topOpeningApp.getAnimatingContainer() : null;
+ final AnimationAdapter topOpeningAnim = wc != null ? wc.getAnimation() : null;
int redoLayout = notifyAppTransitionStartingLocked(transit,
topOpeningAnim != null ? topOpeningAnim.getDurationHint() : 0,
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7f944454ecdf..ba9d757d979f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -205,6 +205,7 @@ import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
+import android.view.IDisplayWindowInsetsController;
import android.view.ISystemGestureExclusionListener;
import android.view.IWindow;
import android.view.InputChannel;
@@ -218,6 +219,7 @@ import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.View;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -570,6 +572,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
WindowState mInputMethodTarget;
+ InsetsControlTarget mInputMethodControlTarget;
+
/** If true hold off on modifying the animation layer of mInputMethodTarget */
boolean mInputMethodTargetWaitingAnim;
@@ -598,6 +602,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private final float mWindowCornerRadius;
private final SparseArray<ShellRoot> mShellRoots = new SparseArray<>();
+ RemoteInsetsControlTarget mRemoteInsetsControlTarget = null;
+ private final IBinder.DeathRecipient mRemoteInsetsDeath =
+ () -> {
+ synchronized (mWmService.mGlobalLock) {
+ mRemoteInsetsControlTarget = null;
+ }
+ };
private RootWindowContainer mRootWindowContainer;
@@ -772,7 +783,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// If this is the first layout, we need to initialize the last frames and inset values,
// as otherwise we'd immediately cause an unnecessary resize.
if (firstLayout) {
- w.updateLastFrames();
+ // The client may compute its actual requested size according to the first layout,
+ // so we still request the window to resize if the current frame is empty.
+ if (!w.getFrameLw().isEmpty()) {
+ w.updateLastFrames();
+ }
w.updateLastInsetValues();
w.updateLocationInParentDisplayIfNeeded();
}
@@ -1152,6 +1167,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mShellRoots.remove(windowType);
}
+ void setRemoteInsetsController(IDisplayWindowInsetsController controller) {
+ if (mRemoteInsetsControlTarget != null) {
+ mRemoteInsetsControlTarget.mRemoteInsetsController.asBinder().unlinkToDeath(
+ mRemoteInsetsDeath, 0);
+ mRemoteInsetsControlTarget = null;
+ }
+ if (controller != null) {
+ try {
+ controller.asBinder().linkToDeath(mRemoteInsetsDeath, 0);
+ mRemoteInsetsControlTarget = new RemoteInsetsControlTarget(controller);
+ } catch (RemoteException e) {
+ return;
+ }
+ }
+ }
+
/** Changes the display the input window token is housed on to this one. */
void reParentWindowToken(WindowToken token) {
final DisplayContent prevDc = token.getDisplayContent();
@@ -3379,6 +3410,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
+ boolean isImeAttachedToApp() {
+ return (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null
+ && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ // An activity with override bounds should be letterboxed inside its parent bounds,
+ // so it doesn't fill the screen.
+ && mInputMethodTarget.mActivityRecord.matchParentBounds());
+ }
+
private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) {
if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) {
return;
@@ -3387,7 +3426,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mInputMethodTarget = target;
mInputMethodTargetWaitingAnim = targetWaitingAnim;
assignWindowLayers(false /* setLayoutNeeded */);
- mInsetsStateController.onImeTargetChanged(target);
+ mInputMethodControlTarget = computeImeControlTarget();
+ mInsetsStateController.onImeTargetChanged(mInputMethodControlTarget);
updateImeParent();
}
@@ -3412,11 +3452,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// Attach it to app if the target is part of an app and such app is covering the entire
// screen. If it's not covering the entire screen the IME might extend beyond the apps
// bounds.
- if (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null
- && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- // An activity with override bounds should be letterboxed inside its parent bounds,
- // so it doesn't fill the screen.
- && mInputMethodTarget.mActivityRecord.matchParentBounds()) {
+ if (isImeAttachedToApp()) {
return mInputMethodTarget.mActivityRecord.getSurfaceControl();
}
@@ -3424,6 +3460,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return mWindowContainers.getSurfaceControl();
}
+ /**
+ * Computes which control-target the IME should be attached to.
+ */
+ @VisibleForTesting
+ InsetsControlTarget computeImeControlTarget() {
+ if (!isImeAttachedToApp() && mRemoteInsetsControlTarget != null) {
+ return mRemoteInsetsControlTarget;
+ }
+
+ // Otherwise, we just use the ime target
+ return mInputMethodTarget;
+ }
+
void setLayoutNeeded() {
if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3));
mLayoutNeeded = true;
@@ -6684,4 +6733,50 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
Context getDisplayUiContext() {
return mDisplayPolicy.getSystemUiContext();
}
+
+ class RemoteInsetsControlTarget implements InsetsControlTarget {
+ private final IDisplayWindowInsetsController mRemoteInsetsController;
+
+ RemoteInsetsControlTarget(IDisplayWindowInsetsController controller) {
+ mRemoteInsetsController = controller;
+ }
+
+ void notifyInsetsChanged() {
+ try {
+ mRemoteInsetsController.insetsChanged(
+ getInsetsStateController().getRawInsetsState());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver inset state change", e);
+ }
+ }
+
+ @Override
+ public void notifyInsetsControlChanged() {
+ final InsetsStateController stateController = getInsetsStateController();
+ try {
+ mRemoteInsetsController.insetsControlChanged(stateController.getRawInsetsState(),
+ stateController.getControlsForDispatch(this));
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver inset state change", e);
+ }
+ }
+
+ @Override
+ public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
+ try {
+ mRemoteInsetsController.showInsets(types, fromIme);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver showInsets", e);
+ }
+ }
+
+ @Override
+ public void hideInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
+ try {
+ mRemoteInsetsController.hideInsets(types, fromIme);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver showInsets", e);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 55f5e289377e..c09834f2b3c1 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -79,12 +79,13 @@ class EnsureActivitiesVisibleHelper {
final PooledConsumer f = PooledLambda.obtainConsumer(
EnsureActivitiesVisibleHelper::setActivityVisibilityState, this,
- PooledLambda.__(ActivityRecord.class), resumeTopActivity);
+ PooledLambda.__(ActivityRecord.class), starting, resumeTopActivity);
mContiner.forAllActivities(f);
f.recycle();
}
- private void setActivityVisibilityState(ActivityRecord r, final boolean resumeTopActivity) {
+ private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
+ final boolean resumeTopActivity) {
final boolean isTop = r == mTop;
if (mAboveTop && !isTop) {
return;
@@ -129,7 +130,8 @@ class EnsureActivitiesVisibleHelper {
"Skipping: already visible at " + r);
if (r.mClientVisibilityDeferred && mNotifyClients) {
- r.makeClientVisible();
+ r.makeActiveIfNeeded(r.mClientVisibilityDeferred ? null : starting);
+ r.mClientVisibilityDeferred = false;
}
r.handleAlreadyVisible();
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 05ede21472f2..fb97ecf8bbc4 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -69,7 +69,7 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
mShowImeRunner = () -> {
// Target should still be the same.
if (isImeTargetFromDisplayContentAndImeSame()) {
- mDisplayContent.mInputMethodTarget.showInsets(
+ mDisplayContent.mInputMethodControlTarget.showInsets(
WindowInsets.Type.ime(), true /* fromIme */);
}
abortShowImePostLayout();
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 184e7d61c355..a13383d3991e 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -70,6 +70,9 @@ class InsetsSourceProvider {
*/
private boolean mServerVisible;
+ private boolean mSeamlessRotating;
+ private long mFinishSeamlessRotateFrameNumber = -1;
+
private final boolean mControllable;
InsetsSourceProvider(InsetsSource source, InsetsStateController stateController,
@@ -170,7 +173,9 @@ class InsetsSourceProvider {
updateSourceFrame();
if (mControl != null) {
final Rect frame = mWin.getWindowFrames().mFrame;
- if (mControl.setSurfacePosition(frame.left, frame.top)) {
+ if (mControl.setSurfacePosition(frame.left, frame.top) && mControlTarget != null) {
+ // The leash has been stale, we need to create a new one for the client.
+ updateControlForTarget(mControlTarget, true /* force */);
mStateController.notifyControlChanged(mControlTarget);
}
}
@@ -189,6 +194,11 @@ class InsetsSourceProvider {
}
void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) {
+ if (mSeamlessRotating) {
+ // We are un-rotating the window against the display rotation. We don't want the target
+ // to control the window for now.
+ return;
+ }
if (mWin == null) {
mControlTarget = target;
return;
@@ -203,14 +213,42 @@ class InsetsSourceProvider {
}
mAdapter = new ControlAdapter();
setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
- mWin.startAnimation(mDisplayContent.getPendingTransaction(), mAdapter,
- !mClientVisible /* hidden */);
+ final Transaction t = mDisplayContent.getPendingTransaction();
+ mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */);
+ final SurfaceControl leash = mAdapter.mCapturedLeash;
+ final long frameNumber = mFinishSeamlessRotateFrameNumber;
+ mFinishSeamlessRotateFrameNumber = -1;
+ if (frameNumber >= 0 && mWin.mHasSurface && leash != null) {
+ // We just finished the seamless rotation. We don't want to change the position or the
+ // window crop of the surface controls (including the leash) until the client finishes
+ // drawing the new frame of the new orientation. Although we cannot defer the reparent
+ // operation, it is fine, because reparent won't cause any visual effect.
+ final SurfaceControl barrier = mWin.mWinAnimator.mSurfaceController.mSurfaceControl;
+ t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
+ t.deferTransactionUntil(leash, barrier, frameNumber);
+ }
mControlTarget = target;
- mControl = new InsetsSourceControl(mSource.getType(), mAdapter.mCapturedLeash,
+ mControl = new InsetsSourceControl(mSource.getType(), leash,
new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top));
}
- boolean onInsetsModified(WindowState caller, InsetsSource modifiedSource) {
+ void startSeamlessRotation() {
+ if (!mSeamlessRotating) {
+ mSeamlessRotating = true;
+
+ // This will revoke the leash and clear the control target.
+ mWin.cancelAnimation();
+ }
+ }
+
+ void finishSeamlessRotation(boolean timeout) {
+ if (mSeamlessRotating) {
+ mSeamlessRotating = false;
+ mFinishSeamlessRotateFrameNumber = timeout ? -1 : mWin.getFrameNumber();
+ }
+ }
+
+ boolean onInsetsModified(InsetsControlTarget caller, InsetsSource modifiedSource) {
if (mControlTarget != caller || modifiedSource.isVisible() == mClientVisible) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 152607470ed1..b2234d17984e 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -91,6 +91,10 @@ class InsetsStateController {
return state;
}
+ InsetsState getRawInsetsState() {
+ return mState;
+ }
+
@Nullable InsetsSourceControl[] getControlsForDispatch(InsetsControlTarget target) {
ArrayList<Integer> controlled = mControlTargetTypeMap.get(target);
if (controlled == null) {
@@ -144,7 +148,7 @@ class InsetsStateController {
getImeSourceProvider().onPostInsetsDispatched();
}
- void onInsetsModified(WindowState windowState, InsetsState state) {
+ void onInsetsModified(InsetsControlTarget windowState, InsetsState state) {
boolean changed = false;
for (int i = state.getSourcesCount() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
@@ -199,7 +203,7 @@ class InsetsStateController {
if (target == previous) {
return;
}
- final InsetsSourceProvider provider = getSourceProvider(type);
+ final InsetsSourceProvider provider = mProviders.get(type);
if (provider == null) {
return;
}
@@ -207,6 +211,7 @@ class InsetsStateController {
return;
}
provider.updateControlForTarget(target, false /* force */);
+ target = provider.getControlTarget();
if (previous != null) {
removeFromControlMaps(previous, type, false /* fake */);
mPendingControlChanged.add(previous);
@@ -296,6 +301,9 @@ class InsetsStateController {
void notifyInsetsChanged() {
mDisplayContent.forAllWindows(mDispatchInsetsChanged, true /* traverseTopToBottom */);
+ if (mDisplayContent.mRemoteInsetsControlTarget != null) {
+ mDisplayContent.mRemoteInsetsControlTarget.notifyInsetsChanged();
+ }
}
void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 399c5d3ae45f..eaa0ea72452a 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,8 +16,12 @@
package com.android.server.wm;
+import static com.android.server.wm.AnimationSpecProto.ROTATE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.RotationAnimationSpecProto.DURATION_MS;
+import static com.android.server.wm.RotationAnimationSpecProto.END_LUMA;
+import static com.android.server.wm.RotationAnimationSpecProto.START_LUMA;
import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING;
import static com.android.server.wm.ScreenRotationAnimationProto.STARTED;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -25,7 +29,9 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER;
+import android.animation.ArgbEvaluator;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
@@ -40,7 +46,9 @@ import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
+import com.android.internal.R;
import com.android.server.protolog.common.ProtoLog;
+import com.android.server.wm.utils.RotationAnimationUtils;
import java.io.PrintWriter;
@@ -60,10 +68,10 @@ import java.io.PrintWriter;
* animation first rotate the new content into the old orientation to then be able to
* animate to the new orientation
*
- * <li> The exiting Blackframe: <p>
- * Because the change of orientation might change the width and height of the content (i.e
- * when rotating from portrait to landscape) we "crop" the new content using black frames
- * around the screenshot so the new content does not go beyond the screenshot's bounds
+ * <li> The Background color frame: <p>
+ * To have the animation seem more seamless, we add a color transitioning background behind the
+ * exiting and entering layouts. We compute the brightness of the start and end
+ * layouts and transition from the two brightness values as grayscale underneath the animation
*
* <li> The entering Blackframe: <p>
* The enter Blackframe is similar to the exit Blackframe but is only used when a custom
@@ -81,8 +89,6 @@ class ScreenRotationAnimation {
*/
private static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER;
private static final int SCREEN_FREEZE_LAYER_ENTER = SCREEN_FREEZE_LAYER_BASE;
- private static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1;
- private static final int SCREEN_FREEZE_LAYER_EXIT = SCREEN_FREEZE_LAYER_BASE + 2;
private final Context mContext;
private final DisplayContent mDisplayContent;
@@ -90,16 +96,18 @@ class ScreenRotationAnimation {
private final Transformation mRotateExitTransformation = new Transformation();
private final Transformation mRotateEnterTransformation = new Transformation();
// Complete transformations being applied.
- private final Transformation mExitTransformation = new Transformation();
private final Transformation mEnterTransformation = new Transformation();
- private final Matrix mFrameInitialMatrix = new Matrix();
private final Matrix mSnapshotInitialMatrix = new Matrix();
- private final Matrix mSnapshotFinalMatrix = new Matrix();
- private final Matrix mExitFrameFinalMatrix = new Matrix();
private final WindowManagerService mService;
+ /** Only used for custom animations and not screen rotation. */
private SurfaceControl mEnterBlackFrameLayer;
- private SurfaceControl mRotationLayer;
- private SurfaceControl mSurfaceControl;
+ /** This layer contains the actual screenshot that is to be faded out. */
+ private SurfaceControl mScreenshotLayer;
+ /**
+ * Only used for screen rotation and not custom animations. Layered behind all other layers
+ * to avoid showing any "empty" spots
+ */
+ private SurfaceControl mBackColorSurface;
private BlackFrame mEnteringBlackFrame;
private int mWidth, mHeight;
@@ -120,8 +128,11 @@ class ScreenRotationAnimation {
private boolean mFinishAnimReady;
private long mFinishAnimStartTime;
private boolean mForceDefaultOrientation;
- private BlackFrame mExitingBlackFrame;
private SurfaceRotationAnimationController mSurfaceRotationAnimationController;
+ /** Intensity of light/whiteness of the layout before rotation occurs. */
+ private float mStartLuma;
+ /** Intensity of light/whiteness of the layout after rotation occurs. */
+ private float mEndLuma;
public ScreenRotationAnimation(Context context, DisplayContent displayContent,
boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) {
@@ -162,9 +173,15 @@ class ScreenRotationAnimation {
final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
try {
- mRotationLayer = displayContent.makeOverlay()
+ mBackColorSurface = displayContent.makeChildSurface(null)
+ .setName("BackColorSurface")
+ .setColorLayer()
+ .build();
+
+ mScreenshotLayer = displayContent.makeOverlay()
.setName("RotationLayer")
- .setContainerLayer()
+ .setBufferSize(mWidth, mHeight)
+ .setSecure(isSecure)
.build();
mEnterBlackFrameLayer = displayContent.makeOverlay()
@@ -172,26 +189,21 @@ class ScreenRotationAnimation {
.setContainerLayer()
.build();
- mSurfaceControl = mService.makeSurfaceBuilder(null)
- .setName("ScreenshotSurface")
- .setParent(mRotationLayer)
- .setBufferSize(mWidth, mHeight)
- .setSecure(isSecure)
- .build();
-
// In case display bounds change, screenshot buffer and surface may mismatch so set a
// scaling mode.
SurfaceControl.Transaction t2 = mService.mTransactionFactory.get();
- t2.setOverrideScalingMode(mSurfaceControl, Surface.SCALING_MODE_SCALE_TO_WINDOW);
+ t2.setOverrideScalingMode(mScreenshotLayer, Surface.SCALING_MODE_SCALE_TO_WINDOW);
t2.apply(true /* sync */);
// Capture a screenshot into the surface we just created.
final int displayId = display.getDisplayId();
final Surface surface = mService.mSurfaceFactory.get();
- surface.copyFrom(mSurfaceControl);
+ surface.copyFrom(mScreenshotLayer);
SurfaceControl.ScreenshotGraphicBuffer gb =
mService.mDisplayManagerInternal.screenshot(displayId);
if (gb != null) {
+ mStartLuma = RotationAnimationUtils.getAvgBorderLuma(gb.getGraphicBuffer(),
+ gb.getColorSpace());
try {
surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(),
gb.getColorSpace());
@@ -202,13 +214,15 @@ class ScreenRotationAnimation {
// screenshot surface we display it in also has FLAG_SECURE so that
// the user can not screenshot secure layers via the screenshot surface.
if (gb.containsSecureLayers()) {
- t.setSecure(mSurfaceControl, true);
+ t.setSecure(mScreenshotLayer, true);
}
- t.setLayer(mRotationLayer, SCREEN_FREEZE_LAYER_BASE);
- t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
- t.setAlpha(mSurfaceControl, 0);
- t.show(mRotationLayer);
- t.show(mSurfaceControl);
+ t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE);
+ t.reparent(mBackColorSurface, displayContent.getSurfaceControl());
+ t.setLayer(mBackColorSurface, -1);
+ t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
+ t.setAlpha(mBackColorSurface, 1);
+ t.show(mScreenshotLayer);
+ t.show(mBackColorSurface);
} else {
Slog.w(TAG, "Unable to take screenshot of display " + displayId);
}
@@ -218,32 +232,11 @@ class ScreenRotationAnimation {
}
ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
- " FREEZE %s: CREATE", mSurfaceControl);
+ " FREEZE %s: CREATE", mScreenshotLayer);
setRotation(t, originalRotation);
t.apply();
}
- private static void createRotationMatrix(int rotation, int width, int height,
- Matrix outMatrix) {
- switch (rotation) {
- case Surface.ROTATION_0:
- outMatrix.reset();
- break;
- case Surface.ROTATION_90:
- outMatrix.setRotate(90, 0, 0);
- outMatrix.postTranslate(height, 0);
- break;
- case Surface.ROTATION_180:
- outMatrix.setRotate(180, 0, 0);
- outMatrix.postTranslate(width, height);
- break;
- case Surface.ROTATION_270:
- outMatrix.setRotate(270, 0, 0);
- outMatrix.postTranslate(0, width);
- break;
- }
- }
-
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(STARTED, mStarted);
@@ -252,11 +245,11 @@ class ScreenRotationAnimation {
}
boolean hasScreenshot() {
- return mSurfaceControl != null;
+ return mScreenshotLayer != null;
}
private void setRotationTransform(SurfaceControl.Transaction t, Matrix matrix) {
- if (mRotationLayer == null) {
+ if (mScreenshotLayer == null) {
return;
}
matrix.getValues(mTmpFloats);
@@ -267,24 +260,19 @@ class ScreenRotationAnimation {
x -= mCurrentDisplayRect.left;
y -= mCurrentDisplayRect.top;
}
- t.setPosition(mRotationLayer, x, y);
- t.setMatrix(mRotationLayer,
+ t.setPosition(mScreenshotLayer, x, y);
+ t.setMatrix(mScreenshotLayer,
mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
- t.setAlpha(mSurfaceControl, (float) 1.0);
- t.setAlpha(mRotationLayer, (float) 1.0);
- t.show(mRotationLayer);
+ t.setAlpha(mScreenshotLayer, (float) 1.0);
+ t.show(mScreenshotLayer);
}
public void printTo(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl);
+ pw.print(prefix); pw.print("mSurface="); pw.print(mScreenshotLayer);
pw.print(" mWidth="); pw.print(mWidth);
pw.print(" mHeight="); pw.println(mHeight);
- pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame);
- if (mExitingBlackFrame != null) {
- mExitingBlackFrame.printTo(prefix + " ", pw);
- }
pw.print(prefix);
pw.print("mEnteringBlackFrame=");
pw.println(mEnteringBlackFrame);
@@ -303,20 +291,10 @@ class ScreenRotationAnimation {
pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
- pw.print(prefix); pw.print("mExitTransformation=");
- mExitTransformation.printShortString(pw); pw.println();
pw.print(prefix); pw.print("mEnterTransformation=");
mEnterTransformation.printShortString(pw); pw.println();
- pw.print(prefix); pw.print("mFrameInitialMatrix=");
- mFrameInitialMatrix.printShortString(pw);
- pw.println();
pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
- mSnapshotInitialMatrix.printShortString(pw);
- pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
- pw.println();
- pw.print(prefix); pw.print("mExitFrameFinalMatrix=");
- mExitFrameFinalMatrix.printShortString(pw);
- pw.println();
+ mSnapshotInitialMatrix.printShortString(pw);pw.println();
pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation);
if (mForceDefaultOrientation) {
pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString());
@@ -331,7 +309,7 @@ class ScreenRotationAnimation {
// to the snapshot to make it stay in the same original position
// with the current screen rotation.
int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
- createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
+ RotationAnimationUtils.createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
setRotationTransform(t, mSnapshotInitialMatrix);
}
@@ -341,7 +319,7 @@ class ScreenRotationAnimation {
*/
private boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
- if (mSurfaceControl == null) {
+ if (mScreenshotLayer == null) {
// Can't do animation.
return false;
}
@@ -354,89 +332,58 @@ class ScreenRotationAnimation {
// Figure out how the screen has moved from the original rotation.
int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
- mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_alpha);
final boolean customAnim;
if (exitAnim != 0 && enterAnim != 0) {
customAnim = true;
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
+ mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
+ R.anim.screen_rotate_alpha);
} else {
customAnim = false;
- switch (delta) {
+ switch (delta) { /* Counter-Clockwise Rotations */
case Surface.ROTATION_0:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_0_exit);
+ R.anim.screen_rotate_0_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_0_enter);
+ R.anim.screen_rotate_0_enter);
break;
case Surface.ROTATION_90:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_plus_90_exit);
+ R.anim.screen_rotate_plus_90_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_plus_90_enter);
+ R.anim.screen_rotate_plus_90_enter);
break;
case Surface.ROTATION_180:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_180_exit);
+ R.anim.screen_rotate_180_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_180_enter);
+ R.anim.screen_rotate_180_enter);
break;
case Surface.ROTATION_270:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_minus_90_exit);
+ R.anim.screen_rotate_minus_90_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_minus_90_enter);
+ R.anim.screen_rotate_minus_90_enter);
break;
}
}
- // Initialize the animations. This is a hack, redefining what "parent"
- // means to allow supplying the last and next size. In this definition
- // "%p" is the original (let's call it "previous") size, and "%" is the
- // screen's current/new size.
- mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
- mAnimRunning = false;
- mFinishAnimReady = false;
- mFinishAnimStartTime = -1;
-
mRotateExitAnimation.restrictDuration(maxAnimationDuration);
mRotateExitAnimation.scaleCurrentDuration(animationScale);
+ mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
mRotateEnterAnimation.scaleCurrentDuration(animationScale);
- mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
- mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
- if (!customAnim && mExitingBlackFrame == null) {
- try {
- // Compute the transformation matrix that must be applied
- // the the black frame to make it stay in the initial position
- // before the new screen rotation. This is different than the
- // snapshot transformation because the snapshot is always based
- // of the native orientation of the screen, not the orientation
- // we were last in.
- createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
-
- final Rect outer;
- final Rect inner;
- if (mForceDefaultOrientation) {
- // Going from a smaller Display to a larger Display, add curtains to sides
- // or top and bottom. Going from a larger to smaller display will result in
- // no BlackSurfaces being constructed.
- outer = mCurrentDisplayRect;
- inner = mOriginalDisplayRect;
- } else {
- outer = new Rect(-mWidth, -mHeight, mWidth * 2, mHeight * 2);
- inner = new Rect(0, 0, mWidth, mHeight);
- }
- mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
- SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation,
- mRotationLayer);
- } catch (OutOfResourcesException e) {
- Slog.w(TAG, "Unable to allocate black surface", e);
- }
+ mAnimRunning = false;
+ mFinishAnimReady = false;
+ mFinishAnimStartTime = -1;
+
+ if (customAnim) {
+ mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
+ mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
}
if (customAnim && mEnteringBlackFrame == null) {
@@ -451,7 +398,12 @@ class ScreenRotationAnimation {
}
}
- mSurfaceRotationAnimationController.startAnimation();
+ if (customAnim) {
+ mSurfaceRotationAnimationController.startCustomAnimation();
+ } else {
+ mSurfaceRotationAnimationController.startScreenRotationAnimation();
+ }
+
return true;
}
@@ -460,11 +412,13 @@ class ScreenRotationAnimation {
*/
public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
- if (mSurfaceControl == null) {
+ if (mScreenshotLayer == null) {
// Can't do animation.
return false;
}
if (!mStarted) {
+ mEndLuma = RotationAnimationUtils.getLumaOfSurfaceControl(mDisplayContent.getDisplay(),
+ mDisplayContent.getWindowingLayer());
startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,
exitAnim, enterAnim);
}
@@ -480,28 +434,28 @@ class ScreenRotationAnimation {
mSurfaceRotationAnimationController.cancel();
mSurfaceRotationAnimationController = null;
}
- if (mSurfaceControl != null) {
- ProtoLog.i(WM_SHOW_SURFACE_ALLOC, " FREEZE %s: DESTROY", mSurfaceControl);
- mSurfaceControl = null;
+
+ if (mScreenshotLayer != null) {
+ ProtoLog.i(WM_SHOW_SURFACE_ALLOC, " FREEZE %s: DESTROY", mScreenshotLayer);
SurfaceControl.Transaction t = mService.mTransactionFactory.get();
- if (mRotationLayer != null) {
- if (mRotationLayer.isValid()) {
- t.remove(mRotationLayer);
- }
- mRotationLayer = null;
+ if (mScreenshotLayer.isValid()) {
+ t.remove(mScreenshotLayer);
}
+ mScreenshotLayer = null;
+
if (mEnterBlackFrameLayer != null) {
if (mEnterBlackFrameLayer.isValid()) {
t.remove(mEnterBlackFrameLayer);
}
mEnterBlackFrameLayer = null;
}
+ if (mBackColorSurface != null) {
+ t.remove(mBackColorSurface);
+ mBackColorSurface = null;
+ }
t.apply();
}
- if (mExitingBlackFrame != null) {
- mExitingBlackFrame.kill();
- mExitingBlackFrame = null;
- }
+
if (mEnteringBlackFrame != null) {
mEnteringBlackFrame.kill();
mEnteringBlackFrame = null;
@@ -537,18 +491,28 @@ class ScreenRotationAnimation {
* Utility class that runs a {@link ScreenRotationAnimation} on the {@link
* SurfaceAnimationRunner}.
* <p>
- * The rotation animation is divided into the following hierarchy:
+ * The rotation animation supports both screen rotation and custom animations
+ *
+ * For custom animations:
+ * <ul>
+ * <li>
+ * The screenshot layer which has an added animation of it's alpha channel
+ * ("screen_rotate_alpha") and that will be applied along with the custom animation.
+ * </li>
+ * <li> A device layer that is animated with the provided custom animation </li>
+ * </ul>
+ *
+ * For screen rotation:
* <ul>
- * <li> A first rotation layer, containing the blackframes. This layer is animated by the
- * "screen_rotate_X_exit" that applies a scale and rotate and where X is value of the rotation.
- * <ul>
- * <li> A child layer containing the screenshot on which is added an animation of it's
- * alpha channel ("screen_rotate_alpha") and that will rotate with his parent layer.</li>
- * </ul>
- * <li> A second rotation layer used when custom animations are passed in
+ * <li> A rotation layer that is both rotated and faded out during a single animation </li>
+ * <li> A device layer that is both rotated and faded in during a single animation </li>
+ * <li> A background color layer that transitions colors behind the first two layers </li>
+ * </ul>
+ *
* {@link ScreenRotationAnimation#startAnimation(
* SurfaceControl.Transaction, long, float, int, int, int, int)}.
* </ul>
+ *
* <p>
* Thus an {@link LocalAnimationAdapter.AnimationSpec} is created for each of
* this three {@link SurfaceControl}s which then delegates the animation to the
@@ -556,22 +520,35 @@ class ScreenRotationAnimation {
*/
class SurfaceRotationAnimationController {
private SurfaceAnimator mDisplayAnimator;
- private SurfaceAnimator mEnterBlackFrameAnimator;
private SurfaceAnimator mScreenshotRotationAnimator;
private SurfaceAnimator mRotateScreenAnimator;
+ private SurfaceAnimator mEnterBlackFrameAnimator;
+
+ void startCustomAnimation() {
+ try {
+ mService.mSurfaceAnimationRunner.deferStartingAnimations();
+ mRotateScreenAnimator = startScreenshotAlphaAnimation();
+ mDisplayAnimator = startDisplayRotation();
+ if (mEnteringBlackFrame != null) {
+ mEnterBlackFrameAnimator = startEnterBlackFrameAnimation();
+ }
+ } finally {
+ mService.mSurfaceAnimationRunner.continueStartingAnimations();
+ }
+ }
/**
* Start the rotation animation of the display and the screenshot on the
* {@link SurfaceAnimationRunner}.
*/
- void startAnimation() {
- mRotateScreenAnimator = startScreenshotAlphaAnimation();
- mDisplayAnimator = startDisplayRotation();
- if (mExitingBlackFrame != null) {
+ void startScreenRotationAnimation() {
+ try {
+ mService.mSurfaceAnimationRunner.deferStartingAnimations();
+ mDisplayAnimator = startDisplayRotation();
mScreenshotRotationAnimator = startScreenshotRotationAnimation();
- }
- if (mEnteringBlackFrame != null) {
- mEnterBlackFrameAnimator = startEnterBlackFrameAnimation();
+ startColorAnimation();
+ } finally {
+ mService.mSurfaceAnimationRunner.continueStartingAnimations();
}
}
@@ -596,8 +573,8 @@ class ScreenRotationAnimation {
private SurfaceAnimator startScreenshotAlphaAnimation() {
return startAnimation(initializeBuilder()
- .setSurfaceControl(mSurfaceControl)
- .setAnimationLeashParent(mRotationLayer)
+ .setSurfaceControl(mScreenshotLayer)
+ .setAnimationLeashParent(mDisplayContent.getOverlayLayer())
.setWidth(mWidth)
.setHeight(mHeight)
.build(),
@@ -616,13 +593,67 @@ class ScreenRotationAnimation {
private SurfaceAnimator startScreenshotRotationAnimation() {
return startAnimation(initializeBuilder()
- .setSurfaceControl(mRotationLayer)
+ .setSurfaceControl(mScreenshotLayer)
.setAnimationLeashParent(mDisplayContent.getOverlayLayer())
.build(),
createWindowAnimationSpec(mRotateExitAnimation),
this::onAnimationEnd);
}
+
+ /**
+ * Applies the color change from {@link #mStartLuma} to {@link #mEndLuma} as a
+ * grayscale color
+ */
+ private void startColorAnimation() {
+ int colorTransitionMs = mContext.getResources().getInteger(
+ R.integer.config_screen_rotation_color_transition);
+ final SurfaceAnimationRunner runner = mService.mSurfaceAnimationRunner;
+ final float[] rgbTmpFloat = new float[3];
+ final int startColor = Color.rgb(mStartLuma, mStartLuma, mStartLuma);
+ final int endColor = Color.rgb(mEndLuma, mEndLuma, mEndLuma);
+ final long duration = colorTransitionMs * (long) mService.getCurrentAnimatorScale();
+ final ArgbEvaluator va = ArgbEvaluator.getInstance();
+ runner.startAnimation(
+ new LocalAnimationAdapter.AnimationSpec() {
+ @Override
+ public long getDuration() {
+ return duration;
+ }
+
+ @Override
+ public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
+ long currentPlayTime) {
+ float fraction = (float)currentPlayTime / (float)getDuration();
+ int color = (Integer) va.evaluate(fraction, startColor, endColor);
+ Color middleColor = Color.valueOf(color);
+ rgbTmpFloat[0] = middleColor.red();
+ rgbTmpFloat[1] = middleColor.green();
+ rgbTmpFloat[2] = middleColor.blue();
+ if (leash.isValid()) {
+ t.setColor(leash, rgbTmpFloat);
+ }
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "startLuma=" + mStartLuma
+ + " endLuma=" + mEndLuma
+ + " durationMs=" + colorTransitionMs);
+ }
+
+ @Override
+ public void dumpDebugInner(ProtoOutputStream proto) {
+ final long token = proto.start(ROTATE);
+ proto.write(START_LUMA, mStartLuma);
+ proto.write(END_LUMA, mEndLuma);
+ proto.write(DURATION_MS, colorTransitionMs);
+ proto.end(token);
+ }
+ },
+ mBackColorSurface, mDisplayContent.getPendingTransaction(), null);
+ }
+
private WindowAnimationSpec createWindowAnimationSpec(Animation mAnimation) {
return new WindowAnimationSpec(mAnimation, new Point(0, 0) /* position */,
false /* canSkipFirstFrame */, 0 /* WindowCornerRadius */);
@@ -646,7 +677,6 @@ class ScreenRotationAnimation {
LocalAnimationAdapter localAnimationAdapter = new LocalAnimationAdapter(
animationSpec, mService.mSurfaceAnimationRunner);
-
animator.startAnimation(mDisplayContent.getPendingTransaction(),
localAnimationAdapter, false);
return animator;
@@ -692,7 +722,6 @@ class ScreenRotationAnimation {
if (mEnterBlackFrameAnimator != null) {
mEnterBlackFrameAnimator.cancelAnimation();
}
-
if (mScreenshotRotationAnimator != null) {
mScreenshotRotationAnimator.cancelAnimation();
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 50cea2ed52cc..5633b6be87b9 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -78,6 +78,10 @@ class SurfaceAnimationRunner {
@GuardedBy("mLock")
private boolean mAnimationStartDeferred;
+ /**
+ * There should only ever be one instance of this class. Usual spot for it is with
+ * {@link WindowManagerService}
+ */
SurfaceAnimationRunner(Supplier<Transaction> transactionFactory,
PowerManagerInternal powerManagerInternal) {
this(null /* callbackProvider */, null /* animatorFactory */,
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 976730ec4337..5286a6e32958 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -322,12 +322,16 @@ class SurfaceAnimator {
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash()
.setParent(mAnimatable.getAnimationLeashParent())
+ .setHidden(hidden)
.setName(surface + " - animation-leash");
final SurfaceControl leash = builder.build();
t.setWindowCrop(leash, width, height);
+
+ // TODO: rely on builder.setHidden(hidden) instead of show and setAlpha when b/138459974 is
+ // fixed.
t.show(leash);
- // TODO: change this back to use show instead of alpha when b/138459974 is fixed.
t.setAlpha(leash, hidden ? 0 : 1);
+
t.reparent(surface, leash);
return leash;
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index cefef37a1363..8ac212f7ef03 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -777,7 +777,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* otherwise.
*/
boolean isWaitingForTransitionStart() {
- return getActivity(app -> app.isWaitingForTransitionStart()) != null;
+ return false;
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 223e9b9e3df2..74fdba1cd13e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -205,6 +205,7 @@ import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDisplayFoldListener;
+import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
import android.view.IDisplayWindowRotationController;
import android.view.IDockedStackListener;
@@ -2768,6 +2769,7 @@ public class WindowManagerService extends IWindowManager.Stub
true /* includingParents */);
}
}
+ syncInputTransactions();
}
/**
@@ -3727,6 +3729,48 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public void setDisplayWindowInsetsController(
+ int displayId, IDisplayWindowInsetsController insetsController) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ return;
+ }
+ dc.setRemoteInsetsController(insetsController);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void modifyDisplayWindowInsets(int displayId, InsetsState state) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null || dc.mRemoteInsetsControlTarget == null) {
+ return;
+ }
+ dc.getInsetsStateController().onInsetsModified(
+ dc.mRemoteInsetsControlTarget, state);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
public int watchRotation(IRotationWatcher watcher, int displayId) {
final DisplayContent displayContent;
synchronized (mGlobalLock) {
@@ -7314,7 +7358,8 @@ public class WindowManagerService extends IWindowManager.Stub
// If there was a pending IME show(), reset it as IME has been
// requested to be hidden.
dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
- dc.mInputMethodTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */);
+ dc.mInputMethodControlTarget.hideInsets(WindowInsets.Type.ime(),
+ true /* fromIme */);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4e768da18041..ba40f623ea66 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -688,6 +688,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
if (mForceSeamlesslyRotate || requested) {
+ if (mControllableInsetProvider != null) {
+ mControllableInsetProvider.startSeamlessRotation();
+ }
mPendingSeamlessRotate = new SeamlessRotator(oldRotation, rotation, getDisplayInfo());
mPendingSeamlessRotate.unrotate(transaction, this);
getDisplayContent().getDisplayRotation().markForSeamlessRotation(this,
@@ -702,6 +705,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mPendingSeamlessRotate = null;
getDisplayContent().getDisplayRotation().markForSeamlessRotation(this,
false /* seamlesslyRotated */);
+ if (mControllableInsetProvider != null) {
+ mControllableInsetProvider.finishSeamlessRotation(timeout);
+ }
}
}
@@ -792,8 +798,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mSeq = seq;
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
- mRequestedInsetsState =
- getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this);
+ mRequestedInsetsState = new InsetsState(
+ getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this),
+ true /* copySources */);
if (DEBUG) {
Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
diff --git a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
new file mode 100644
index 000000000000..94f66768d5ef
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
@@ -0,0 +1,97 @@
+/*
+ * 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 com.android.server.wm.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+
+/** Helper functions for the {@link com.android.server.wm.ScreenRotationAnimation} class*/
+public class RotationAnimationUtils {
+
+ /**
+ * Converts the provided {@link GraphicBuffer} and converts it to a bitmap to then sample the
+ * luminance at the borders of the bitmap
+ * @return the average luminance of all the pixels at the borders of the bitmap
+ */
+ public static float getAvgBorderLuma(GraphicBuffer graphicBuffer, ColorSpace colorSpace) {
+ Bitmap hwBitmap = Bitmap.wrapHardwareBuffer(graphicBuffer, colorSpace);
+ if (hwBitmap == null) {
+ return 0;
+ }
+
+ Bitmap swaBitmap = hwBitmap.copy(Bitmap.Config.ARGB_8888, false);
+ float totalLuma = 0;
+ int height = swaBitmap.getHeight();
+ int width = swaBitmap.getWidth();
+ int i;
+ for (i = 0; i < width; i++) {
+ totalLuma += swaBitmap.getColor(i, 0).luminance();
+ totalLuma += swaBitmap.getColor(i, height - 1).luminance();
+ }
+ for (i = 0; i < height; i++) {
+ totalLuma += swaBitmap.getColor(0, i).luminance();
+ totalLuma += swaBitmap.getColor(width - 1, i).luminance();
+ }
+ return totalLuma / (2 * width + 2 * height);
+ }
+
+ /**
+ * Gets the average border luma by taking a screenshot of the {@param surfaceControl}.
+ * @see #getAvgBorderLuma(GraphicBuffer, ColorSpace)
+ */
+ public static float getLumaOfSurfaceControl(Display display, SurfaceControl surfaceControl) {
+ if (surfaceControl == null) {
+ return 0;
+ }
+
+ Point size = new Point();
+ display.getSize(size);
+ Rect crop = new Rect(0, 0, size.x, size.y);
+ SurfaceControl.ScreenshotGraphicBuffer buffer =
+ SurfaceControl.captureLayers(surfaceControl, crop, 1);
+ return RotationAnimationUtils.getAvgBorderLuma(buffer.getGraphicBuffer(),
+ buffer.getColorSpace());
+ }
+
+ public static void createRotationMatrix(int rotation, int width, int height, Matrix outMatrix) {
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ outMatrix.reset();
+ break;
+ case Surface.ROTATION_90:
+ outMatrix.setRotate(90, 0, 0);
+ outMatrix.postTranslate(height, 0);
+ break;
+ case Surface.ROTATION_180:
+ outMatrix.setRotate(180, 0, 0);
+ outMatrix.postTranslate(width, height);
+ break;
+ case Surface.ROTATION_270:
+ outMatrix.setRotate(270, 0, 0);
+ outMatrix.postTranslate(0, width);
+ break;
+ }
+ }
+}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 2e8e5e7b706a..c0891d739788 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1757,6 +1757,12 @@ static jboolean nativeCanDispatchToDisplay(JNIEnv* env, jclass /* clazz */, jlon
return im->getInputManager()->getReader()->canDispatchToDisplay(deviceId, displayId);
}
+static void nativeNotifyPortAssociationsChanged(JNIEnv* env, jclass /* clazz */, jlong ptr) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+ im->getInputManager()->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gInputManagerMethods[] = {
@@ -1842,6 +1848,8 @@ static const JNINativeMethod gInputManagerMethods[] = {
(void*) nativeSetCustomPointerIcon },
{ "nativeCanDispatchToDisplay", "(JII)Z",
(void*) nativeCanDispatchToDisplay },
+ { "nativeNotifyPortAssociationsChanged", "(J)V",
+ (void*) nativeNotifyPortAssociationsChanged },
};
#define FIND_CLASS(var, className) \
diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp
index 380ee942af98..cdbe77a3d64c 100644
--- a/services/devicepolicy/Android.bp
+++ b/services/devicepolicy/Android.bp
@@ -18,8 +18,3 @@ java_library_static {
"compat-changeid-annotation-processor",
],
}
-
-platform_compat_config {
- name: "services-devicepolicy-platform-compat-config",
- src: ":services.devicepolicy",
-}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 5a1d552bf325..8641059aebd5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -64,4 +64,8 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
}
public void setLocationEnabled(ComponentName who, boolean locationEnabled) {}
+
+ public boolean isOrganizationOwnedDeviceWithManagedProfile() {
+ return false;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 13246ba9e587..d5ff2802499c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8607,6 +8607,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public boolean isOrganizationOwnedDeviceWithManagedProfile() {
+ if (!mHasFeature) {
+ return false;
+ }
+ enforceManageUsers();
+
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ for (UserInfo ui : mUserManager.getUsers()) {
+ if (ui.isManagedProfile() && isProfileOwnerOfOrganizationOwnedDevice(ui.id)) {
+ return true;
+ }
+ }
+
+ return false;
+ });
+ }
+
+ @Override
public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
ensureCallerIdentityMatchesIfNotSystem(packageName, pid, uid);
@@ -11705,6 +11723,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mStateCache;
}
+ @Override
+ public List<String> getAllCrossProfilePackages() {
+ return DevicePolicyManagerService.this.getAllCrossProfilePackages();
+ }
+
}
private Intent createShowAdminSupportIntent(ComponentName admin, int userId) {
@@ -14584,8 +14607,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
for (int i = 0; i < users.length; i++) {
final ComponentName componentName = getProfileOwner(users[i]);
if (componentName != null) {
- admins.add(getActiveAdminForCallerLocked(
- componentName, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(componentName, users[i]);
+ if (admin != null) {
+ admins.add(admin);
+ }
}
}
return admins;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index bfec51c92651..b6a8ca447213 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -751,6 +751,7 @@ public final class SystemServer {
// Now that we have the bare essentials of the OS up and running, take
// note that we just booted, which might send out a rescue party if
// we're stuck in a runtime restart loop.
+ RescueParty.registerHealthObserver(mSystemContext);
RescueParty.noteBoot(mSystemContext);
// Manages LEDs and display backlight so we need it to bring up the display.
diff --git a/services/net/java/android/net/ip/IpClientCallbacks.java b/services/net/java/android/net/ip/IpClientCallbacks.java
index 61cd88aac921..c93e5c5e4759 100644
--- a/services/net/java/android/net/ip/IpClientCallbacks.java
+++ b/services/net/java/android/net/ip/IpClientCallbacks.java
@@ -17,6 +17,7 @@
package android.net.ip;
import android.net.DhcpResults;
+import android.net.DhcpResultsParcelable;
import android.net.Layer2PacketParcelable;
import android.net.LinkProperties;
@@ -69,6 +70,18 @@ public class IpClientCallbacks {
public void onNewDhcpResults(DhcpResults dhcpResults) {}
/**
+ * Callback called when new DHCP results are available.
+ *
+ * <p>This is purely advisory and not an indication of provisioning success or failure. This is
+ * only here for callers that want to expose DHCPv4 results to other APIs
+ * (e.g., WifiInfo#setInetAddress).
+ *
+ * <p>DHCPv4 or static IPv4 configuration failure or success can be determined by whether or not
+ * the passed-in DhcpResults object is null.
+ */
+ public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) {}
+
+ /**
* Indicates that provisioning was successful.
*/
public void onProvisioningSuccess(LinkProperties newLp) {}
diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java
index 4d60e6239376..7f723b1c232b 100644
--- a/services/net/java/android/net/ip/IpClientUtil.java
+++ b/services/net/java/android/net/ip/IpClientUtil.java
@@ -119,6 +119,7 @@ public class IpClientUtil {
@Override
public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) {
mCb.onNewDhcpResults(fromStableParcelable(dhcpResults));
+ mCb.onNewDhcpResults(dhcpResults);
}
@Override
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 8632ca4c2898..8b2f15c2babb 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -81,7 +81,10 @@ import org.robolectric.shadows.ShadowLooper;
import org.robolectric.shadows.ShadowPackageManager;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.List;
/**
@@ -1238,13 +1241,49 @@ public class UserBackupManagerServiceTest {
assertThat(service.getAncestralSerialNumber()).isEqualTo(testSerialNumber2);
}
+ /**
+ * Test that {@link UserBackupManagerService#dump()} for system user does not prefix dump with
+ * "User 0:".
+ */
+ @Test
+ public void testDump_forSystemUser_DoesNotHaveUserPrefix() throws Exception {
+ mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+ UserBackupManagerService service =
+ BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks(
+ UserHandle.USER_SYSTEM,
+ mContext,
+ mBackupThread,
+ mBaseStateDir,
+ mDataDir,
+ mTransportManager);
+
+ StringWriter dump = new StringWriter();
+ service.dump(new FileDescriptor(), new PrintWriter(dump), new String[0]);
+
+ assertThat(dump.toString()).startsWith("Backup Manager is ");
+ }
+
+ /**
+ * Test that {@link UserBackupManagerService#dump()} for non-system user prefixes dump with
+ * "User <userid>:".
+ */
+ @Test
+ public void testDump_forNonSystemUser_HasUserPrefix() throws Exception {
+ mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+ UserBackupManagerService service = createUserBackupManagerServiceAndRunTasks();
+
+ StringWriter dump = new StringWriter();
+ service.dump(new FileDescriptor(), new PrintWriter(dump), new String[0]);
+
+ assertThat(dump.toString()).startsWith("User " + USER_ID + ":" + "Backup Manager is ");
+ }
+
private File createTestFile() throws IOException {
File testFile = new File(mContext.getFilesDir(), "test");
testFile.createNewFile();
return testFile;
}
-
/**
* We can't mock the void method {@link #schedule(Context, long, BackupManagerConstants)} so we
* extend {@link ShadowKeyValueBackupJob} and throw an exception at the end of the method.
diff --git a/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java
new file mode 100644
index 000000000000..4cbdbd178944
--- /dev/null
+++ b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Unit tests for {@link LocationRequestStatistics}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class LocationRequestStatisticsTest {
+
+ /**
+ * Check adding and removing requests & strings
+ */
+ @Test
+ public void testRequestSummary() {
+ LocationRequestStatistics.RequestSummary summary =
+ new LocationRequestStatistics.RequestSummary(
+ "com.example", "gps", 1000);
+ StringWriter stringWriter = new StringWriter();
+ summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriter), " "), 1234);
+ assertThat(stringWriter.toString()).startsWith("At");
+
+ StringWriter stringWriterRemove = new StringWriter();
+ summary = new LocationRequestStatistics.RequestSummary(
+ "com.example", "gps",
+ LocationRequestStatistics.RequestSummary.REQUEST_ENDED_INTERVAL);
+ summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriterRemove), " "), 2345);
+ assertThat(stringWriterRemove.toString()).contains("-");
+ }
+
+ /**
+ * Check summary list size capping
+ */
+ @Test
+ public void testSummaryList() {
+ LocationRequestStatistics statistics = new LocationRequestStatistics();
+ statistics.history.addRequest("com.example", "gps", 1000);
+ assertThat(statistics.history.mList.size()).isEqualTo(1);
+ // Try (not) to overflow
+ for (int i = 0; i < LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE; i++) {
+ statistics.history.addRequest("com.example", "gps", 1000);
+ }
+ assertThat(statistics.history.mList.size()).isEqualTo(
+ LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE);
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 0d6020c3d06d..30d89d31ba64 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -32,6 +32,7 @@ import static org.mockito.ArgumentMatchers.isNull;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.VersionedPackage;
import android.os.RecoverySystem;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -39,6 +40,8 @@ import android.provider.DeviceConfig;
import android.provider.Settings;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
+import com.android.server.RescueParty.RescuePartyObserver;
import com.android.server.am.SettingsToPropertiesMapper;
import com.android.server.utils.FlagNamespaceUtils;
@@ -57,13 +60,15 @@ import java.util.HashMap;
* Test RescueParty.
*/
public class RescuePartyTest {
- private static final int PERSISTENT_APP_UID = 12;
private static final long CURRENT_NETWORK_TIME_MILLIS = 0L;
private static final String FAKE_NATIVE_NAMESPACE1 = "native1";
private static final String FAKE_NATIVE_NAMESPACE2 = "native2";
private static final String[] FAKE_RESET_NATIVE_NAMESPACES =
{FAKE_NATIVE_NAMESPACE1, FAKE_NATIVE_NAMESPACE2};
+ private static VersionedPackage sFailingPackage = new VersionedPackage("com.package.name", 1);
+ private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
+
private MockitoSession mSession;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -182,25 +187,25 @@ public class RescuePartyTest {
@Test
public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
- notePersistentAppCrash(RescueParty.TRIGGER_COUNT);
+ notePersistentAppCrash();
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
- notePersistentAppCrash(RescueParty.TRIGGER_COUNT);
+ notePersistentAppCrash();
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
- notePersistentAppCrash(RescueParty.TRIGGER_COUNT);
+ notePersistentAppCrash();
verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
- notePersistentAppCrash(RescueParty.TRIGGER_COUNT);
+ notePersistentAppCrash();
verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
assertEquals(RescueParty.LEVEL_FACTORY_RESET,
@@ -221,20 +226,6 @@ public class RescuePartyTest {
}
@Test
- public void testPersistentAppCrashDetectionWithWrongInterval() {
- notePersistentAppCrash(RescueParty.TRIGGER_COUNT - 1);
-
- // last persistent app crash is just outside of the boot loop detection window
- doReturn(CURRENT_NETWORK_TIME_MILLIS
- + RescueParty.PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS + 1)
- .when(() -> RescueParty.getElapsedRealtime());
- notePersistentAppCrash(/*numTimes=*/1);
-
- assertEquals(RescueParty.LEVEL_NONE,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
- }
-
- @Test
public void testBootLoopDetectionWithProperInterval() {
noteBoot(RescueParty.TRIGGER_COUNT - 1);
@@ -249,21 +240,6 @@ public class RescuePartyTest {
}
@Test
- public void testPersistentAppCrashDetectionWithProperInterval() {
- notePersistentAppCrash(RescueParty.TRIGGER_COUNT - 1);
-
- // last persistent app crash is just inside of the boot loop detection window
- doReturn(CURRENT_NETWORK_TIME_MILLIS
- + RescueParty.PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS)
- .when(() -> RescueParty.getElapsedRealtime());
- notePersistentAppCrash(/*numTimes=*/1);
-
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
- }
-
- @Test
public void testBootLoopDetectionWithWrongTriggerCount() {
noteBoot(RescueParty.TRIGGER_COUNT - 1);
assertEquals(RescueParty.LEVEL_NONE,
@@ -271,13 +247,6 @@ public class RescuePartyTest {
}
@Test
- public void testPersistentAppCrashDetectionWithWrongTriggerCount() {
- notePersistentAppCrash(RescueParty.TRIGGER_COUNT - 1);
- assertEquals(RescueParty.LEVEL_NONE,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
- }
-
- @Test
public void testIsAttemptingFactoryReset() {
noteBoot(RescueParty.TRIGGER_COUNT * 4);
@@ -319,6 +288,77 @@ public class RescuePartyTest {
FAKE_NATIVE_NAMESPACE2, /*makeDefault=*/true));
}
+ @Test
+ public void testExplicitlyEnablingAndDisablingRescue() {
+ SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
+ SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true));
+ assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING), false);
+
+ SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
+ assertTrue(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING));
+ }
+
+ @Test
+ public void testHealthCheckLevels() {
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+
+ // Ensure that no action is taken for cases where the failure reason is unknown
+ SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
+ RescueParty.LEVEL_FACTORY_RESET));
+ assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_UNKNOWN),
+ PackageHealthObserverImpact.USER_IMPACT_NONE);
+
+ /*
+ For the following cases, ensure that the returned user impact corresponds with the user
+ impact of the next available rescue level, not the current one.
+ */
+ SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
+ RescueParty.LEVEL_NONE));
+ assertEquals(observer.onHealthCheckFailed(null,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
+ PackageHealthObserverImpact.USER_IMPACT_LOW);
+
+ SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
+ RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS));
+ assertEquals(observer.onHealthCheckFailed(null,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
+ PackageHealthObserverImpact.USER_IMPACT_LOW);
+
+
+ SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
+ RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES));
+ assertEquals(observer.onHealthCheckFailed(null,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
+ PackageHealthObserverImpact.USER_IMPACT_HIGH);
+
+
+ SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
+ RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS));
+ assertEquals(observer.onHealthCheckFailed(null,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
+ PackageHealthObserverImpact.USER_IMPACT_HIGH);
+
+
+ SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
+ RescueParty.LEVEL_FACTORY_RESET));
+ assertEquals(observer.onHealthCheckFailed(null,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
+ PackageHealthObserverImpact.USER_IMPACT_HIGH);
+ }
+
+ @Test
+ public void testRescueLevelIncrementsWhenExecuted() {
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+ SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
+ RescueParty.LEVEL_NONE));
+ observer.execute(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_CRASH);
+ assertEquals(SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, -1),
+ RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
+ }
+
private void verifySettingsResets(int resetMode) {
verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
resetMode, UserHandle.USER_SYSTEM));
@@ -332,9 +372,8 @@ public class RescuePartyTest {
}
}
- private void notePersistentAppCrash(int numTimes) {
- for (int i = 0; i < numTimes; i++) {
- RescueParty.noteAppCrash(mMockContext, PERSISTENT_APP_UID);
- }
+ private void notePersistentAppCrash() {
+ RescuePartyObserver.getInstance(mMockContext).execute(new VersionedPackage(
+ "com.package.name", 1), PackageWatchdog.FAILURE_REASON_UNKNOWN);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index d11d98766b01..591c3a385e23 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -85,6 +85,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.WindowManagerInternal;
import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
new file mode 100644
index 000000000000..75239db92121
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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 com.android.server.accessibility;
+
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.Manifest;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Icon;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.server.LocalServices;
+import com.android.server.accessibility.AccessibilityManagerService.AccessibilityDisplayListener;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * APCT tests for {@link AccessibilityManagerService}.
+ */
+public class AccessibilityManagerServiceTest extends AndroidTestCase {
+ private static final String TAG = "A11Y_MANAGER_SERVICE_TEST";
+ private static final int ACTION_ID = 20;
+ private static final String LABEL = "label";
+ private static final String INTENT_ACTION = "TESTACTION";
+ private static final String DESCRIPTION = "description";
+ private static final PendingIntent TEST_PENDING_INTENT = PendingIntent.getBroadcast(
+ InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION), 0);
+ private static final RemoteAction TEST_ACTION = new RemoteAction(
+ Icon.createWithContentUri("content://test"),
+ LABEL,
+ DESCRIPTION,
+ TEST_PENDING_INTENT);
+ private static final AccessibilityAction NEW_ACCESSIBILITY_ACTION =
+ new AccessibilityAction(ACTION_ID, LABEL);
+
+ @Mock private PackageManager mMockPackageManager;
+ @Mock private WindowManagerInternal mMockWindowManagerService;
+ @Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
+ @Mock private SystemActionPerformer mMockSystemActionPerformer;
+ @Mock private AccessibilityWindowManager mMockA11yWindowManager;
+ @Mock private AccessibilityDisplayListener mMockA11yDisplayListener;
+ @Mock private ActivityTaskManagerInternal mMockActivityTaskManagerInternal;
+
+ private AccessibilityManagerService mA11yms;
+
+ @Override
+ protected void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ LocalServices.removeServiceForTest(WindowManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
+ LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerService);
+ LocalServices.addService(
+ ActivityTaskManagerInternal.class, mMockActivityTaskManagerInternal);
+ mA11yms = new AccessibilityManagerService(
+ InstrumentationRegistry.getContext(),
+ mMockPackageManager,
+ mMockSecurityPolicy,
+ mMockSystemActionPerformer,
+ mMockA11yWindowManager,
+ mMockA11yDisplayListener);
+ }
+
+ @SmallTest
+ public void testRegisterSystemActionWithoutPermission() throws Exception {
+ doThrow(SecurityException.class).when(mMockSecurityPolicy).enforceCallingPermission(
+ Manifest.permission.MANAGE_ACCESSIBILITY,
+ AccessibilityManagerService.FUNCTION_REGISTER_SYSTEM_ACTION);
+
+ try {
+ mA11yms.registerSystemAction(TEST_ACTION, ACTION_ID);
+ fail();
+ } catch (SecurityException expected) {
+ }
+ verify(mMockSystemActionPerformer, never()).registerSystemAction(ACTION_ID, TEST_ACTION);
+ }
+
+ @SmallTest
+ public void testRegisterSystemAction() throws Exception {
+ mA11yms.registerSystemAction(TEST_ACTION, ACTION_ID);
+ verify(mMockSystemActionPerformer).registerSystemAction(ACTION_ID, TEST_ACTION);
+ }
+
+ @SmallTest
+ public void testUnregisterSystemActionWithoutPermission() throws Exception {
+ doThrow(SecurityException.class).when(mMockSecurityPolicy).enforceCallingPermission(
+ Manifest.permission.MANAGE_ACCESSIBILITY,
+ AccessibilityManagerService.FUNCTION_UNREGISTER_SYSTEM_ACTION);
+
+ try {
+ mA11yms.unregisterSystemAction(ACTION_ID);
+ fail();
+ } catch (SecurityException expected) {
+ }
+ verify(mMockSystemActionPerformer, never()).unregisterSystemAction(ACTION_ID);
+ }
+
+ @SmallTest
+ public void testUnregisterSystemAction() throws Exception {
+ mA11yms.unregisterSystemAction(ACTION_ID);
+ verify(mMockSystemActionPerformer).unregisterSystemAction(ACTION_ID);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 99dd9a12eb72..2ce70b6f0889 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -44,6 +44,7 @@ import android.os.UserHandle;
import android.testing.DexmakerShareClassLoaderRule;
import android.view.Display;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 67075edb0143..9db5a080c093 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -53,6 +53,7 @@ import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
index 44a514f7623c..96ae102e53f3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
@@ -31,6 +31,8 @@ import android.accessibilityservice.FingerprintGestureController;
import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback;
import android.accessibilityservice.IAccessibilityServiceConnection;
+import com.android.server.accessibility.test.MessageCapturingHandler;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
index de7bc443b8c5..30d00ad716e6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
@@ -31,6 +31,7 @@ import android.hardware.fingerprint.IFingerprintService;
import android.view.KeyEvent;
import com.android.server.accessibility.FingerprintGestureDispatcher.FingerprintGestureClient;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import org.junit.After;
import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
index 23ce483be107..41235560dc91 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
@@ -44,6 +44,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.accessibility.KeyEventDispatcher.KeyEventFilter;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.policy.WindowManagerPolicy;
import org.hamcrest.Description;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
index 322653b4115c..78e651b7a3c1 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
@@ -33,6 +33,7 @@ import android.view.KeyEvent;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.policy.WindowManagerPolicy;
import org.hamcrest.Description;
@@ -212,4 +213,4 @@ public class KeyboardInterceptorTest {
description.appendText("Matches key event");
}
}
-} \ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
index 773b8778c7bf..82c6498bd9be 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
@@ -47,6 +47,7 @@ import android.view.MagnificationSpec;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index 36e854ca77cd..1ac4a8ed96d0 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -54,6 +54,7 @@ import android.view.accessibility.AccessibilityEvent;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.accessibility.utils.MotionEventMatcher;
import org.hamcrest.Description;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
index 8da927dcb4ab..c8baca610bdc 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
@@ -37,6 +37,7 @@ import android.hardware.display.DisplayManager;
import android.os.IBinder;
import android.view.accessibility.AccessibilityEvent;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
diff --git a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
index d4182f3d31e2..5a1ad8655ab0 100644
--- a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
@@ -672,6 +672,30 @@ public final class AdbDebuggingManagerTest {
connectionTime2, mKeyStore.getLastConnectionTime(TEST_KEY_2));
}
+ @Test
+ public void testClearAuthorizationsBeforeAdbEnabled() throws Exception {
+ // The adb key store is not instantiated until adb is enabled; however if the user attempts
+ // to clear the adb authorizations when adb is disabled after a boot a NullPointerException
+ // was thrown as deleteKeyStore is invoked against the key store. This test ensures the
+ // key store can be successfully cleared when adb is disabled.
+ mHandler = mManager.new AdbDebuggingHandler(FgThread.get().getLooper());
+
+ clearKeyStore();
+ }
+
+ @Test
+ public void testClearAuthorizationsDeletesKeyFiles() throws Exception {
+ mAdbKeyFile.createNewFile();
+ mAdbKeyXmlFile.createNewFile();
+
+ clearKeyStore();
+
+ assertFalse("The adb key file should have been deleted after revocation of the grants",
+ mAdbKeyFile.exists());
+ assertFalse("The adb xml key file should have been deleted after revocation of the grants",
+ mAdbKeyXmlFile.exists());
+ }
+
/**
* Runs an adb test with the provided configuration.
*
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index f3c76b609c25..8871348d0027 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManagerInternal;
import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetManagerInternal;
import android.appwidget.AppWidgetProviderInfo;
import android.appwidget.PendingHostUpdate;
import android.content.BroadcastReceiver;
@@ -80,6 +81,7 @@ public class AppWidgetServiceImplTest extends InstrumentationTestCase {
super.setUp();
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
+ LocalServices.removeServiceForTest(AppWidgetManagerInternal.class);
mTestContext = new TestContext();
mPkgName = mTestContext.getOpPackageName();
diff --git a/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
index 2326dfda7e12..d44476ed971d 100644
--- a/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -27,6 +27,7 @@ import static junit.framework.Assert.fail;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -59,6 +60,7 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -83,6 +85,8 @@ public class BackupManagerServiceTest {
@Mock
private UserBackupManagerService mUserBackupManagerService;
@Mock
+ private UserBackupManagerService mNonSystemUserBackupManagerService;
+ @Mock
private Context mContextMock;
@Mock
private PrintWriter mPrintWriterMock;
@@ -105,7 +109,7 @@ public class BackupManagerServiceTest {
mUserServices = new SparseArray<>();
mUserServices.append(UserHandle.USER_SYSTEM, mUserBackupManagerService);
- mUserServices.append(NON_USER_SYSTEM, mUserBackupManagerService);
+ mUserServices.append(NON_USER_SYSTEM, mNonSystemUserBackupManagerService);
when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
@@ -512,6 +516,26 @@ public class BackupManagerServiceTest {
mService.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]);
verifyNoMoreInteractions(mUserBackupManagerService);
+ verifyNoMoreInteractions(mNonSystemUserBackupManagerService);
+ }
+
+ /**
+ * Test that {@link BackupManagerService#dump()} dumps system user information before non-system
+ * user information.
+ */
+
+ @Test
+ public void testDump_systemUserFirst() {
+ String[] args = new String[0];
+ mService.dumpWithoutCheckingPermission(mFileDescriptorStub, mPrintWriterMock, args);
+
+ InOrder inOrder =
+ inOrder(mUserBackupManagerService, mNonSystemUserBackupManagerService);
+ inOrder.verify(mUserBackupManagerService)
+ .dump(mFileDescriptorStub, mPrintWriterMock, args);
+ inOrder.verify(mNonSystemUserBackupManagerService)
+ .dump(mFileDescriptorStub, mPrintWriterMock, args);
+ inOrder.verifyNoMoreInteractions();
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
new file mode 100644
index 000000000000..d0767ccb6f87
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * 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 com.android.server.compat;
+
+import android.content.pm.ApplicationInfo;
+
+class ApplicationInfoBuilder {
+ private boolean mIsDebuggable;
+ private int mTargetSdk;
+ private String mPackageName;
+
+ private ApplicationInfoBuilder() {
+ mTargetSdk = -1;
+ }
+
+ static ApplicationInfoBuilder create() {
+ return new ApplicationInfoBuilder();
+ }
+
+ ApplicationInfoBuilder withTargetSdk(int targetSdk) {
+ mTargetSdk = targetSdk;
+ return this;
+ }
+
+ ApplicationInfoBuilder debuggable() {
+ mIsDebuggable = true;
+ return this;
+ }
+
+ ApplicationInfoBuilder withPackageName(String packageName) {
+ mPackageName = packageName;
+ return this;
+ }
+
+ ApplicationInfo build() {
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ if (mIsDebuggable) {
+ applicationInfo.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
+ }
+ applicationInfo.packageName = mPackageName;
+ applicationInfo.targetSdkVersion = mTargetSdk;
+ return applicationInfo;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
new file mode 100644
index 000000000000..328c71dbc7db
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -0,0 +1,99 @@
+/*
+ * 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 com.android.server.compat;
+
+import android.content.Context;
+
+import com.android.internal.compat.AndroidBuildClassifier;
+
+import java.util.ArrayList;
+
+/**
+ * Helper class for creating a CompatConfig.
+ */
+class CompatConfigBuilder {
+ private ArrayList<CompatChange> mChanges;
+ private AndroidBuildClassifier mBuildClassifier;
+ private Context mContext;
+
+ private CompatConfigBuilder(AndroidBuildClassifier buildClassifier, Context context) {
+ mChanges = new ArrayList<>();
+ mBuildClassifier = buildClassifier;
+ mContext = context;
+ }
+
+ static CompatConfigBuilder create(AndroidBuildClassifier buildClassifier, Context context) {
+ return new CompatConfigBuilder(buildClassifier, context);
+ }
+
+ CompatConfigBuilder addTargetSdkChangeWithId(int sdk, long id) {
+ mChanges.add(new CompatChange(id, "", sdk, false, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addTargetSdkDisabledChangeWithId(int sdk, long id) {
+ mChanges.add(new CompatChange(id, "", sdk, true, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addTargetSdkChangeWithIdAndName(int sdk, long id, String name) {
+ mChanges.add(new CompatChange(id, name, sdk, false, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addTargetSdkChangeWithIdAndDescription(int sdk, long id,
+ String description) {
+ mChanges.add(new CompatChange(id, "", sdk, false, description));
+ return this;
+ }
+
+ CompatConfigBuilder addEnabledChangeWithId(long id) {
+ mChanges.add(new CompatChange(id, "", -1, false, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) {
+ mChanges.add(new CompatChange(id, name, -1, false, ""));
+ return this;
+ }
+ CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) {
+ mChanges.add(new CompatChange(id, "", -1, false, description));
+ return this;
+ }
+
+ CompatConfigBuilder addDisabledChangeWithId(long id) {
+ mChanges.add(new CompatChange(id, "", -1, true, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) {
+ mChanges.add(new CompatChange(id, name, -1, true, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) {
+ mChanges.add(new CompatChange(id, "", -1, true, description));
+ return this;
+ }
+
+ CompatConfig build() {
+ CompatConfig config = new CompatConfig(mBuildClassifier, mContext);
+ for (CompatChange change : mChanges) {
+ config.addChange(change);
+ }
+ return config;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index cb99c118a407..407f67e2fd8e 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -18,12 +18,25 @@ package com.android.server.compat;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.compat.AndroidBuildClassifier;
+
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.File;
import java.io.FileOutputStream;
@@ -34,12 +47,12 @@ import java.util.UUID;
@RunWith(AndroidJUnit4.class)
public class CompatConfigTest {
- private ApplicationInfo makeAppInfo(String pName, int targetSdkVersion) {
- ApplicationInfo ai = new ApplicationInfo();
- ai.packageName = pName;
- ai.targetSdkVersion = targetSdkVersion;
- return ai;
- }
+ @Mock
+ private Context mContext;
+ @Mock
+ PackageManager mPackageManager;
+ @Mock
+ private AndroidBuildClassifier mBuildClassifier;
private File createTempDir() {
String base = System.getProperty("java.io.tmpdir");
@@ -54,112 +67,206 @@ public class CompatConfigTest {
os.close();
}
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ // Assume userdebug/eng non-final build
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(false);
+ }
+
+ @Test
+ public void testUnknownChangeEnabled() throws Exception {
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build()))
+ .isTrue();
+ }
+
@Test
- public void testUnknownChangeEnabled() {
- CompatConfig pc = new CompatConfig();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
+ public void testDisabledChangeDisabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build()))
+ .isFalse();
}
@Test
- public void testDisabledChangeDisabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, ""));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
+ public void testTargetSdkChangeDisabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addTargetSdkChangeWithId(2, 1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(2).build()))
+ .isFalse();
}
@Test
- public void testTargetSdkChangeDisabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, null));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
+ public void testTargetSdkChangeEnabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addTargetSdkChangeWithId(2, 1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
}
@Test
- public void testTargetSdkChangeEnabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, ""));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
+ public void testDisabledOverrideTargetSdkChange() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addTargetSdkDisabledChangeWithId(2, 1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isFalse();
}
@Test
- public void testDisabledOverrideTargetSdkChange() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isFalse();
+ public void testGetDisabledChanges() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .addEnabledChangeWithId(2345L)
+ .build();
+
+ assertThat(compatConfig.getDisabledChanges(
+ ApplicationInfoBuilder.create().build())).asList().containsExactly(1234L);
}
@Test
- public void testGetDisabledChanges() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null));
- pc.addChange(new CompatChange(2345L, "OTHER_CHANGE", -1, false, null));
- assertThat(pc.getDisabledChanges(
- makeAppInfo("com.some.package", 2))).asList().containsExactly(1234L);
+ public void testGetDisabledChangesSorted() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .addDisabledChangeWithId(123L)
+ .addDisabledChangeWithId(12L)
+ .build();
+
+ assertThat(compatConfig.getDisabledChanges(ApplicationInfoBuilder.create().build()))
+ .asList().containsExactly(12L, 123L, 1234L);
}
@Test
- public void testGetDisabledChangesSorted() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null));
- pc.addChange(new CompatChange(123L, "OTHER_CHANGE", 2, true, null));
- pc.addChange(new CompatChange(12L, "THIRD_CHANGE", 2, true, null));
- assertThat(pc.getDisabledChanges(
- makeAppInfo("com.some.package", 2))).asList().containsExactly(12L, 123L, 1234L);
+ public void testPackageOverrideEnabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+
+ compatConfig.addOverride(1234L, "com.some.package", true);
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.other.package").build())).isFalse();
}
@Test
- public void testPackageOverrideEnabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null)); // disabled
- pc.addOverride(1234L, "com.some.package", true);
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isFalse();
+ public void testPackageOverrideDisabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1234L)
+ .build();
+
+ compatConfig.addOverride(1234L, "com.some.package", false);
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.other.package").build())).isTrue();
}
@Test
- public void testPackageOverrideDisabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
- pc.addOverride(1234L, "com.some.package", false);
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
+ public void testPackageOverrideUnknownPackage() throws Exception {
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+
+ compatConfig.addOverride(1234L, "com.some.package", false);
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.other.package").build())).isTrue();
}
@Test
- public void testPackageOverrideUnknownPackage() {
- CompatConfig pc = new CompatConfig();
- pc.addOverride(1234L, "com.some.package", false);
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
+ public void testPreventAddOverride() throws Exception {
+ final long changeId = 1234L;
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+ PackageManager packageManager = mock(PackageManager.class);
+ when(mContext.getPackageManager()).thenReturn(packageManager);
+ when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(applicationInfo);
+
+ // Force the validator to prevent overriding the change by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+ assertThrows(SecurityException.class,
+ () -> compatConfig.addOverride(1234L, "com.some.package", true)
+ );
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
}
@Test
- public void testPackageOverrideUnknownChange() {
- CompatConfig pc = new CompatConfig();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
+ public void testPreventRemoveOverride() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+ when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(applicationInfo);
+ // Assume the override was allowed to be added.
+ compatConfig.addOverride(1234L, "com.some.package", true);
+
+ // Validator allows turning on the change.
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
+
+ // Reject all override attempts.
+ // Force the validator to prevent overriding the change by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+ // Try to turn off change, but validator prevents it.
+ assertThrows(SecurityException.class,
+ () -> compatConfig.removeOverride(1234L, "com.some.package"));
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
}
@Test
- public void testRemovePackageOverride() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
- pc.addOverride(1234L, "com.some.package", false);
- pc.removeOverride(1234L, "com.some.package");
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
+ public void testRemovePackageOverride() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+
+ assertThat(compatConfig.addOverride(1234L, "com.some.package", false)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
+
+ compatConfig.removeOverride(1234L, "com.some.package");
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
}
@Test
- public void testLookupChangeId() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
- pc.addChange(new CompatChange(2345L, "ANOTHER_CHANGE", -1, false, null));
- assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
+ public void testLookupChangeId() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithIdAndName(1234L, "MY_CHANGE")
+ .addEnabledChangeWithIdAndName(2345L, "MY_OTHER_CHANGE")
+ .build();
+
+ assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
}
@Test
- public void testLookupChangeIdNotPresent() {
- CompatConfig pc = new CompatConfig();
- assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
+ public void testLookupChangeIdNotPresent() throws Exception {
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
}
@Test
@@ -172,14 +279,17 @@ public class CompatConfigTest {
File dir = createTempDir();
writeToFile(dir, "platform_compat_config.xml", configXml);
-
- CompatConfig pc = new CompatConfig();
- pc.initConfigFromLib(dir);
-
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
- assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse();
- assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue();
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ compatConfig.initConfigFromLib(dir);
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1235L,
+ ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1236L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
}
@Test
@@ -195,15 +305,16 @@ public class CompatConfigTest {
File dir = createTempDir();
writeToFile(dir, "libcore_platform_compat_config.xml", configXml1);
writeToFile(dir, "frameworks_platform_compat_config.xml", configXml2);
-
- CompatConfig pc = new CompatConfig();
- pc.initConfigFromLib(dir);
-
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
- assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse();
- assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue();
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ compatConfig.initConfigFromLib(dir);
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1235L,
+ ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1236L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
}
}
-
-
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java
new file mode 100644
index 000000000000..793296e88169
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java
@@ -0,0 +1,52 @@
+/*
+ * 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 com.android.server.compat;
+
+import android.compat.Compatibility;
+
+import com.android.internal.compat.CompatibilityChangeConfig;
+
+import java.util.HashSet;
+import java.util.Set;
+
+class CompatibilityChangeConfigBuilder {
+ private Set<Long> mEnabled;
+ private Set<Long> mDisabled;
+
+ private CompatibilityChangeConfigBuilder() {
+ mEnabled = new HashSet<>();
+ mDisabled = new HashSet<>();
+ }
+
+ static CompatibilityChangeConfigBuilder create() {
+ return new CompatibilityChangeConfigBuilder();
+ }
+
+ CompatibilityChangeConfigBuilder enable(Long id) {
+ mEnabled.add(id);
+ return this;
+ }
+
+ CompatibilityChangeConfigBuilder disable(Long id) {
+ mDisabled.add(id);
+ return this;
+ }
+
+ CompatibilityChangeConfig build() {
+ return new CompatibilityChangeConfig(new Compatibility.ChangeConfig(mEnabled, mDisabled));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
new file mode 100644
index 000000000000..ecd07bdc4544
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -0,0 +1,383 @@
+/*
+ * 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 com.android.server.compat;
+
+import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.compat.AndroidBuildClassifier;
+import com.android.internal.compat.IOverrideValidator;
+import com.android.internal.compat.OverrideAllowedState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class OverrideValidatorImplTest {
+ private static final String PACKAGE_NAME = "my.package";
+ private static final int TARGET_SDK = 10;
+ private static final int TARGET_SDK_BEFORE = 9;
+ private static final int TARGET_SDK_AFTER = 11;
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ Context mContext;
+
+ private AndroidBuildClassifier debuggableBuild() {
+ AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
+ when(buildClassifier.isDebuggableBuild()).thenReturn(true);
+ return buildClassifier;
+ }
+
+ private AndroidBuildClassifier betaBuild() {
+ AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
+ when(buildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(buildClassifier.isFinalBuild()).thenReturn(false);
+ return buildClassifier;
+ }
+
+ private AndroidBuildClassifier finalBuild() {
+ AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
+ when(buildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(buildClassifier.isFinalBuild()).thenReturn(true);
+ return buildClassifier;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ }
+
+ @Test
+ public void getOverrideAllowedState_debugBuildAnyChangeDebugApp_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withTargetSdk(TARGET_SDK)
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_debugBuildAnyChangeReleaseApp_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildTargetSdkChangeDebugApp_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withTargetSdk(TARGET_SDK)
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_BEFORE));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildEnabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addEnabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable()
+ .build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildDisabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addDisabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildAnyChangeReleaseApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptin_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withTargetSdk(TARGET_SDK)
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptout_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK)
+ .debuggable()
+ .build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange).isEqualTo(
+ new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK,
+ TARGET_SDK_BEFORE));
+ assertThat(stateTargetSdkEqualChange).isEqualTo(
+ new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK, TARGET_SDK));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addEnabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable().build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildDisabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addDisabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable().build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildAnyChangeReleaseApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index c406876c5cee..ce5d6d9be770 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -26,21 +26,20 @@ import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import static org.testng.Assert.assertThrows;
-import android.compat.Compatibility;
import android.content.Context;
import android.content.pm.PackageManager;
-import com.android.internal.compat.CompatibilityChangeConfig;
+import androidx.test.runner.AndroidJUnit4;
-import com.google.common.collect.ImmutableSet;
+import com.android.internal.compat.AndroidBuildClassifier;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.MockitoAnnotations;
-@RunWith(MockitoJUnitRunner.class)
+@RunWith(AndroidJUnit4.class)
public class PlatformCompatTest {
private static final String PACKAGE_NAME = "my.package";
@@ -50,84 +49,77 @@ public class PlatformCompatTest {
private PackageManager mPackageManager;
@Mock
CompatChange.ChangeListener mListener1, mListener2;
-
+ PlatformCompat mPlatformCompat;
+ CompatConfig mCompatConfig;
+ @Mock
+ private AndroidBuildClassifier mBuildClassifier;
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow(
new PackageManager.NameNotFoundException());
- CompatConfig.get().clearChanges();
+ mCompatConfig = new CompatConfig(mBuildClassifier, mContext);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ // Assume userdebug/eng non-final build
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(false);
}
@Test
- public void testRegisterListenerToSameIdThrows() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
+ public void testRegisterListenerToSameIdThrows() throws Exception {
// Registering a listener to change 1 is successful.
- pc.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(1, mListener1);
// Registering a listener to change 2 is successful.
- pc.registerListener(2, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
// Trying to register another listener to change id 1 fails.
- assertThrows(IllegalStateException.class, () -> pc.registerListener(1, mListener1));
+ assertThrows(IllegalStateException.class,
+ () -> mPlatformCompat.registerListener(1, mListener1));
}
@Test
- public void testRegisterListenerReturn() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ public void testRegisterListenerReturn() throws Exception {
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
// Change id 1 is known (added in setOverrides).
- assertThat(pc.registerListener(1, mListener1)).isTrue();
+ assertThat(mPlatformCompat.registerListener(1, mListener1)).isTrue();
// Change 2 is unknown.
- assertThat(pc.registerListener(2, mListener1)).isFalse();
+ assertThat(mPlatformCompat.registerListener(2, mListener1)).isFalse();
}
@Test
- public void testListenerCalledOnSetOverrides() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnSetOverrides() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener1);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerNotCalledOnWrongPackage() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener1);
+ public void testListenerNotCalledOnWrongPackage() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, never()).onCompatChange("other.package");
}
@Test
- public void testListenerCalledOnSetOverridesTwoListeners() {
- PlatformCompat pc = new PlatformCompat(mContext);
- pc.registerListener(1, mListener1);
+ public void testListenerCalledOnSetOverridesTwoListeners() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
- final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
- final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -136,11 +128,10 @@ public class PlatformCompatTest {
reset(mListener1);
reset(mListener2);
- pc.registerListener(2, mListener2);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -148,31 +139,23 @@ public class PlatformCompatTest {
}
@Test
- public void testListenerCalledOnSetOverridesForTest() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener1);
+ public void testListenerCalledOnSetOverridesForTest() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnSetOverridesTwoListenersForTest() {
- PlatformCompat pc = new PlatformCompat(mContext);
- pc.registerListener(1, mListener1);
+ public void testListenerCalledOnSetOverridesTwoListenersForTest() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
- final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
- final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
-
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -181,10 +164,10 @@ public class PlatformCompatTest {
reset(mListener1);
reset(mListener2);
- pc.registerListener(2, mListener2);
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.registerListener(2, mListener2);
+
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -192,15 +175,12 @@ public class PlatformCompatTest {
}
@Test
- public void testListenerCalledOnClearOverrides() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnClearOverrides() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener2);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
@@ -208,21 +188,18 @@ public class PlatformCompatTest {
reset(mListener1);
reset(mListener2);
- pc.clearOverrides(PACKAGE_NAME);
+ mPlatformCompat.clearOverrides(PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnClearOverridesMultipleOverrides() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener2);
+ public void testListenerCalledOnClearOverridesMultipleOverrides() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
@@ -230,21 +207,18 @@ public class PlatformCompatTest {
reset(mListener1);
reset(mListener2);
- pc.clearOverrides(PACKAGE_NAME);
+ mPlatformCompat.clearOverrides(PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnClearOverrideExists() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnClearOverrideExists() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener2);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
@@ -252,21 +226,17 @@ public class PlatformCompatTest {
reset(mListener1);
reset(mListener2);
- pc.clearOverride(1, PACKAGE_NAME);
+ mPlatformCompat.clearOverride(1, PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnClearOverrideDoesntExist() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.registerListener(1, mListener1);
+ public void testListenerCalledOnClearOverrideDoesntExist() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
- pc.clearOverride(1, PACKAGE_NAME);
+ mPlatformCompat.clearOverride(1, PACKAGE_NAME);
// Listener not called when a non existing override is removed.
verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
}
-
-
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index a16e14f61a66..175c7565a005 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3636,6 +3636,29 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
}
+ public void testIsOrganizationOwnedDevice() throws Exception {
+ setupProfileOwner();
+ // Set up the user manager to return correct user info
+ UserInfo managedProfileUserInfo = new UserInfo(DpmMockContext.CALLER_USER_HANDLE,
+ "managed profile",
+ UserInfo.FLAG_MANAGED_PROFILE);
+ when(getServices().userManager.getUsers())
+ .thenReturn(Arrays.asList(managedProfileUserInfo));
+
+ // Any caller without the MANAGE_USERS permission should get a security exception.
+ assertExpectException(SecurityException.class, null, () ->
+ dpm.isOrganizationOwnedDeviceWithManagedProfile());
+ // But when the right permission is granted, this should succeed.
+ mContext.permissions.add(android.Manifest.permission.MANAGE_USERS);
+ assertFalse(dpm.isOrganizationOwnedDeviceWithManagedProfile());
+ configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile());
+
+ // A random caller from another user should also be able to get the right result.
+ mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
+ assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile());
+ }
+
public void testSetTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index ebca240819e8..25d077823a3f 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -78,7 +78,7 @@ public class DisplayModeDirectorTest {
int displayId = 0;
// With no votes present, DisplayModeDirector should allow any refresh rate.
- assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*defaultModeId=*/60,
+ assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/60,
new DisplayModeDirector.RefreshRateRange(0f, Float.POSITIVE_INFINITY)),
createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayModeSpecs(
displayId));
@@ -105,7 +105,7 @@ public class DisplayModeDirectorTest {
director.injectVotesByDisplay(votesByDisplay);
assertEquals(
new DisplayModeDirector.DesiredDisplayModeSpecs(
- /*defaultModeId=*/minFps + i,
+ /*baseModeId=*/minFps + i,
new DisplayModeDirector.RefreshRateRange(minFps + i, maxFps - i)),
director.getDesiredDisplayModeSpecs(displayId));
}
@@ -126,7 +126,7 @@ public class DisplayModeDirectorTest {
votes.put(DisplayModeDirector.Vote.MIN_PRIORITY,
DisplayModeDirector.Vote.forRefreshRates(70, 80));
director.injectVotesByDisplay(votesByDisplay);
- assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*defaultModeId=*/70,
+ assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/70,
new DisplayModeDirector.RefreshRateRange(70, 80)),
director.getDesiredDisplayModeSpecs(displayId));
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/BitTrackedInputStreamTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/BitTrackedInputStreamTest.java
new file mode 100644
index 000000000000..1eb5eb51504a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/BitTrackedInputStreamTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.model;
+
+import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START;
+import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END;
+import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START;
+import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
+import static com.android.server.integrity.utils.TestUtils.getBits;
+import static com.android.server.integrity.utils.TestUtils.getBytes;
+import static com.android.server.integrity.utils.TestUtils.getValueBits;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Rule;
+
+import com.android.server.integrity.parser.BinaryFileOperations;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.IOException;
+
+@RunWith(JUnit4.class)
+public class BitTrackedInputStreamTest {
+ private static final String COMPOUND_FORMULA_START_BITS =
+ getBits(COMPOUND_FORMULA_START, SEPARATOR_BITS);
+ private static final String COMPOUND_FORMULA_END_BITS =
+ getBits(COMPOUND_FORMULA_END, SEPARATOR_BITS);
+ private static final String ATOMIC_FORMULA_START_BITS =
+ getBits(ATOMIC_FORMULA_START, SEPARATOR_BITS);
+ private static final String NOT = getBits(CompoundFormula.NOT, CONNECTOR_BITS);
+ private static final String PACKAGE_NAME = getBits(AtomicFormula.PACKAGE_NAME, KEY_BITS);
+ private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS);
+ private static final String DENY = getBits(Rule.DENY, EFFECT_BITS);
+
+ private static final String IS_NOT_HASHED = "0";
+ private static final String START_BIT = "1";
+ private static final String END_BIT = "1";
+
+ @Test
+ public void testBitOperationsCountBitsCorrectly() throws IOException {
+ String packageName = "com.test.app";
+ byte[] testInput =
+ getBytes(
+ START_BIT
+ + COMPOUND_FORMULA_START_BITS
+ + NOT
+ + ATOMIC_FORMULA_START_BITS
+ + PACKAGE_NAME
+ + EQ
+ + IS_NOT_HASHED
+ + getBits(packageName.length(), VALUE_SIZE_BITS)
+ + getValueBits(packageName)
+ + COMPOUND_FORMULA_END_BITS
+ + DENY
+ + END_BIT);
+
+ BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(testInput);
+
+ // Right after construction, the read bits count should be 0.
+ assertThat(bitTrackedInputStream.getReadBitsCount()).isEqualTo(0);
+
+ // Get next 10 bits should result with 10 bits read.
+ bitTrackedInputStream.getNext(10);
+ assertThat(bitTrackedInputStream.getReadBitsCount()).isEqualTo(10);
+
+ // When we move the cursor 8 bytes, we should point to 64 bits.
+ bitTrackedInputStream.setCursorToByteLocation(8);
+ assertThat(bitTrackedInputStream.getReadBitsCount()).isEqualTo(64);
+
+ // Read until the end and the total size of the input stream should be available.
+ while (bitTrackedInputStream.hasNext()) {
+ bitTrackedInputStream.getNext(1);
+ }
+ assertThat(bitTrackedInputStream.getReadBitsCount()).isEqualTo(128);
+ }
+
+ @Test
+ public void testBitInputStreamOperationsStillWork() throws IOException {
+ String packageName = "com.test.app";
+ byte[] testInput =
+ getBytes(
+ IS_NOT_HASHED
+ + getBits(packageName.length(), VALUE_SIZE_BITS)
+ + getValueBits(packageName));
+
+ BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(testInput);
+ assertThat(bitTrackedInputStream.getReadBitsCount()).isEqualTo(0);
+
+ // Read until the string parameter.
+ String stringValue = BinaryFileOperations.getStringValue(bitTrackedInputStream);
+
+ // Verify that the read bytes are counted.
+ assertThat(stringValue).isEqualTo(packageName);
+ assertThat(bitTrackedInputStream.getReadBitsCount()).isGreaterThan(0);
+ }
+
+ @Test
+ public void testBitTrackedInputStream_moveCursorForwardFailsIfAlreadyRead() throws IOException {
+ String packageName = "com.test.app";
+ byte[] testInput =
+ getBytes(
+ IS_NOT_HASHED
+ + getBits(packageName.length(), VALUE_SIZE_BITS)
+ + getValueBits(packageName));
+
+ BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(testInput);
+
+ // Read more than two bytes.
+ bitTrackedInputStream.getNext(20);
+
+ // Ask to move the cursor to the second byte.
+ assertThrows(
+ IllegalStateException.class,
+ () -> bitTrackedInputStream.setCursorToByteLocation(2));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/ByteTrackedOutputStreamTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/ByteTrackedOutputStreamTest.java
index 5ecb8b5c8169..c7cc343dd77e 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/ByteTrackedOutputStreamTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/ByteTrackedOutputStreamTest.java
@@ -14,12 +14,10 @@
* limitations under the License.
*/
-package com.android.server.integrity.serializer;
+package com.android.server.integrity.model;
import static com.google.common.truth.Truth.assertThat;
-import com.android.server.integrity.model.BitOutputStream;
-
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
index 9cc0ed85a044..51f5c755754c 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
@@ -48,6 +48,7 @@ import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -97,8 +98,10 @@ public class RuleBinaryParserTest {
private static final byte[] DEFAULT_FORMAT_VERSION_BYTES =
getBytes(getBits(DEFAULT_FORMAT_VERSION, FORMAT_VERSION_BITS));
+ private static final List<RuleIndexRange> NO_INDEXING = Collections.emptyList();
+
@Test
- public void testBinaryStream_validCompoundFormula() throws Exception {
+ public void testBinaryStream_validCompoundFormula_noIndexing() throws Exception {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -131,13 +134,13 @@ public class RuleBinaryParserTest {
/* isHashedValue= */ false))),
Rule.DENY);
- List<Rule> rules = binaryParser.parse(inputStream);
+ List<Rule> rules = binaryParser.parse(inputStream, NO_INDEXING);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
- public void testBinaryString_validCompoundFormula_notConnector() throws Exception {
+ public void testBinaryString_validCompoundFormula_notConnector_noIndexing() throws Exception {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -175,7 +178,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_validCompoundFormula_andConnector() throws Exception {
+ public void testBinaryString_validCompoundFormula_andConnector_noIndexing() throws Exception {
String packageName = "com.test.app";
String appCertificate = "test_cert";
String ruleBits =
@@ -223,7 +226,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_validCompoundFormula_orConnector() throws Exception {
+ public void testBinaryString_validCompoundFormula_orConnector_noIndexing() throws Exception {
String packageName = "com.test.app";
String appCertificate = "test_cert";
String ruleBits =
@@ -272,7 +275,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_validAtomicFormula_stringValue() throws Exception {
+ public void testBinaryString_validAtomicFormula_stringValue_noIndexing() throws Exception {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -304,7 +307,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_validAtomicFormula_hashedValue() throws Exception {
+ public void testBinaryString_validAtomicFormula_hashedValue_noIndexing() throws Exception {
String appCertificate = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
String ruleBits =
START_BIT
@@ -337,7 +340,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_validAtomicFormula_integerValue() throws Exception {
+ public void testBinaryString_validAtomicFormula_integerValue_noIndexing() throws Exception {
int versionCode = 1;
String ruleBits =
START_BIT
@@ -365,7 +368,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_validAtomicFormula_booleanValue() throws Exception {
+ public void testBinaryString_validAtomicFormula_booleanValue_noIndexing() throws Exception {
String isPreInstalled = "1";
String ruleBits =
START_BIT
@@ -392,7 +395,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_invalidAtomicFormula() throws Exception {
+ public void testBinaryString_invalidAtomicFormula_noIndexing() {
int versionCode = 1;
String ruleBits =
START_BIT
@@ -415,7 +418,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_withNoRuleList() throws RuleParseException {
+ public void testBinaryString_withNoRuleList_noIndexing() throws RuleParseException {
ByteBuffer rule = ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length);
rule.put(DEFAULT_FORMAT_VERSION_BYTES);
RuleParser binaryParser = new RuleBinaryParser();
@@ -426,7 +429,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_withEmptyRule() throws RuleParseException {
+ public void testBinaryString_withEmptyRule_noIndexing() {
String ruleBits = START_BIT;
byte[] ruleBytes = getBytes(ruleBits);
ByteBuffer rule =
@@ -442,7 +445,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_invalidCompoundFormula_invalidNumberOfFormulas() throws Exception {
+ public void testBinaryString_invalidCompoundFormula_invalidNumberOfFormulas_noIndexing() {
String packageName = "com.test.app";
String appCertificate = "test_cert";
String ruleBits =
@@ -478,7 +481,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_invalidRule_invalidOperator() throws Exception {
+ public void testBinaryString_invalidRule_invalidOperator_noIndexing() {
int versionCode = 1;
String ruleBits =
START_BIT
@@ -506,7 +509,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_invalidRule_invalidEffect() throws Exception {
+ public void testBinaryString_invalidRule_invalidEffect_noIndexing() {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -536,7 +539,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_invalidRule_invalidConnector() throws Exception {
+ public void testBinaryString_invalidRule_invalidConnector_noIndexing() {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -566,7 +569,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_invalidRule_invalidKey() throws Exception {
+ public void testBinaryString_invalidRule_invalidKey_noIndexing() {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -596,7 +599,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_invalidRule_invalidSeparator() throws Exception {
+ public void testBinaryString_invalidRule_invalidSeparator_noIndexing() {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -626,7 +629,7 @@ public class RuleBinaryParserTest {
}
@Test
- public void testBinaryString_invalidRule_invalidEndMarker() throws Exception {
+ public void testBinaryString_invalidRule_invalidEndMarker_noIndexing() {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -653,4 +656,65 @@ public class RuleBinaryParserTest {
/* expectedExceptionMessageRegex */ "A rule must end with a '1' bit",
() -> binaryParser.parse(rule.array()));
}
+
+ @Test
+ public void testBinaryStream_multipleRules_indexingIdentifiesParsesIndexRangeCorrectly()
+ throws Exception {
+ String packageName2 = "com.test.2";
+
+ byte[] ruleBytes1 = getBytes(getRulesWithPackageName("com.test.1"));
+ byte[] ruleBytes2 = getBytes(getRulesWithPackageName(packageName2));
+ byte[] ruleBytes3 = getBytes(getRulesWithPackageName("com.test.3"));
+
+ ByteBuffer rule =
+ ByteBuffer.allocate(
+ DEFAULT_FORMAT_VERSION_BYTES.length
+ + ruleBytes1.length
+ + ruleBytes2.length
+ + ruleBytes3.length);
+ rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+ rule.put(ruleBytes1);
+ rule.put(ruleBytes2);
+ rule.put(ruleBytes3);
+ InputStream inputStream = new ByteArrayInputStream(rule.array());
+
+ RuleParser binaryParser = new RuleBinaryParser();
+
+ List<RuleIndexRange> indexRanges = new ArrayList<>();
+ indexRanges.add(
+ new RuleIndexRange(
+ DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes1.length,
+ DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes1.length
+ + ruleBytes2.length));
+ List<Rule> rules = binaryParser.parse(inputStream, indexRanges);
+
+ Rule expectedRule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.NOT,
+ Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ packageName2,
+ /* isHashedValue= */ false))),
+ Rule.DENY);
+
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+ }
+
+ private static String getRulesWithPackageName(String packageName) {
+ return START_BIT
+ + COMPOUND_FORMULA_START_BITS
+ + NOT
+ + ATOMIC_FORMULA_START_BITS
+ + PACKAGE_NAME
+ + EQ
+ + IS_NOT_HASHED
+ + getBits(packageName.length(), VALUE_SIZE_BITS)
+ + getValueBits(packageName)
+ + COMPOUND_FORMULA_END_BITS
+ + DENY
+ + END_BIT;
+
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
new file mode 100644
index 000000000000..742952e056bc
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.parser;
+
+import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
+import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
+import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY;
+import static com.android.server.integrity.utils.TestUtils.getBits;
+import static com.android.server.integrity.utils.TestUtils.getBytes;
+import static com.android.server.integrity.utils.TestUtils.getValueBits;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.integrity.AppInstallMetadata;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class RuleIndexingControllerTest {
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect() throws IOException {
+ InputStream inputStream = obtainDefaultIndexingMapForTest();
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("ddd")
+ .setAppCertificate("777")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(200, 300),
+ new RuleIndexRange(700, 800),
+ new RuleIndexRange(900, 945));
+ }
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect_keysInFirstAndLastBlock() throws IOException {
+ InputStream inputStream = obtainDefaultIndexingMapForTest();
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("bbb")
+ .setAppCertificate("999")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(100, 200),
+ new RuleIndexRange(800, 900),
+ new RuleIndexRange(900, 945));
+ }
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect_keysMatchWithValues() throws IOException {
+ InputStream inputStream = obtainDefaultIndexingMapForTest();
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("ccc")
+ .setAppCertificate("444")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(200, 300),
+ new RuleIndexRange(700, 800),
+ new RuleIndexRange(900, 945));
+ }
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect_noIndexesAvailable() throws IOException {
+ byte[] stringBytes =
+ getBytes(
+ getKeyValueString(START_INDEXING_KEY, 100)
+ + getKeyValueString(END_INDEXING_KEY, 500)
+ + getKeyValueString(START_INDEXING_KEY, 500)
+ + getKeyValueString(END_INDEXING_KEY, 900)
+ + getKeyValueString(START_INDEXING_KEY, 900)
+ + getKeyValueString(END_INDEXING_KEY, 945));
+ ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
+ rule.put(stringBytes);
+ InputStream inputStream = new ByteArrayInputStream(rule.array());
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("ccc")
+ .setAppCertificate("444")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(100, 500),
+ new RuleIndexRange(500, 900),
+ new RuleIndexRange(900, 945));
+ }
+
+ private static InputStream obtainDefaultIndexingMapForTest() {
+ byte[] stringBytes =
+ getBytes(
+ getKeyValueString(START_INDEXING_KEY, 100)
+ + getKeyValueString("ccc", 200)
+ + getKeyValueString("eee", 300)
+ + getKeyValueString("hhh", 400)
+ + getKeyValueString(END_INDEXING_KEY, 500)
+ + getKeyValueString(START_INDEXING_KEY, 500)
+ + getKeyValueString("111", 600)
+ + getKeyValueString("444", 700)
+ + getKeyValueString("888", 800)
+ + getKeyValueString(END_INDEXING_KEY, 900)
+ + getKeyValueString(START_INDEXING_KEY, 900)
+ + getKeyValueString(END_INDEXING_KEY, 945));
+ ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
+ rule.put(stringBytes);
+ return new ByteArrayInputStream(rule.array());
+ }
+
+ private static String getKeyValueString(String key, int value) {
+ String isNotHashed = "0";
+ return isNotHashed
+ + getBits(key.length(), VALUE_SIZE_BITS)
+ + getValueBits(key)
+ + getBits(value, /* numOfBits= */ 32);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
index a14197b17529..6944aee7fcb9 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
@@ -73,7 +73,7 @@ public class RuleXmlParserTest {
/* isHashedValue= */ false))),
Rule.DENY);
- List<Rule> rules = xmlParser.parse(inputStream);
+ List<Rule> rules = xmlParser.parse(inputStream, Collections.emptyList());
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@@ -623,7 +623,7 @@ public class RuleXmlParserTest {
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "Rules must start with RuleList <RL> tag",
- () -> xmlParser.parse(inputStream));
+ () -> xmlParser.parse(inputStream, Collections.emptyList()));
}
private String generateTagWithAttribute(
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 28e6830515f0..c7dbad83e384 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -1273,11 +1273,11 @@ public class NetworkPolicyManagerServiceTest {
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
stats.clear();
- stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
+ stats.addEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
- stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
+ stats.addEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
- stats.addValues(IFACE_ALL, UID_C, SET_ALL, TAG_ALL,
+ stats.addEntry(IFACE_ALL, UID_C, SET_ALL, TAG_ALL,
DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
reset(mNotifManager);
@@ -1301,9 +1301,9 @@ public class NetworkPolicyManagerServiceTest {
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
stats.clear();
- stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
+ stats.addEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
DataUnit.MEGABYTES.toBytes(960), 0, 0, 0, 0);
- stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
+ stats.addEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
reset(mNotifManager);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index c478ec472e61..15327b6e5463 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -156,8 +156,7 @@ public class PackageInstallerSessionTest {
if (isMultiPackage) {
params.isMultiPackage = true;
}
- InstallSource installSource = InstallSource.create("testInstaller", null, "testInstaller",
- false);
+ InstallSource installSource = InstallSource.create("testInstaller", null, "testInstaller");
return new PackageInstallerSession(
/* callback */ null,
/* context */null,
diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
new file mode 100644
index 000000000000..7666ab9ed5ae
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.SensorManager;
+import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.BatteryStats;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ServiceManager;
+import android.os.Vibrator;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.testing.TestableContext;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.BatteryStatsImpl;
+import com.android.server.LocalServices;
+import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.power.batterysaver.BatterySaverPolicy;
+import com.android.server.power.batterysaver.BatterySavingStats;
+import com.android.server.statusbar.StatusBarManagerInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.server.power.Notifier}
+ */
+public class NotifierTest {
+ private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
+ private static final int USER_ID = 0;
+
+ @Mock private BatterySaverPolicy mBatterySaverPolicyMock;
+ @Mock private PowerManagerService.NativeWrapper mNativeWrapperMock;
+ @Mock private Notifier mNotifierMock;
+ @Mock private WirelessChargerDetector mWirelessChargerDetectorMock;
+ @Mock private AmbientDisplayConfiguration mAmbientDisplayConfigurationMock;
+ @Mock private SystemPropertiesWrapper mSystemPropertiesMock;
+ @Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
+ @Mock private BatteryStatsImpl mBatteryStats;
+ @Mock private Vibrator mVibrator;
+ @Mock private StatusBarManagerInternal mStatusBarManagerInternal;
+
+ private PowerManagerService mService;
+ private Context mContextSpy;
+ private Resources mResourcesSpy;
+ private TestLooper mTestLooper = new TestLooper();
+ private Notifier mNotifier;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
+ LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal);
+
+ mContextSpy = spy(new TestableContext(InstrumentationRegistry.getContext()));
+ mResourcesSpy = spy(mContextSpy.getResources());
+ when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
+ when(mContextSpy.getSystemService(Vibrator.class)).thenReturn(mVibrator);
+
+ mService = new PowerManagerService(mContextSpy, mInjector);
+ }
+
+ @Test
+ public void testVibrateEnabled_wiredCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is enabled
+ enableChargingVibration(true);
+
+ // WHEN wired charging starts
+ mNotifier.onWiredChargingStarted(USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the device vibrates once
+ verify(mVibrator, times(1)).vibrate(any(), any());
+ }
+
+ @Test
+ public void testVibrateDisabled_wiredCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is disabled
+ enableChargingVibration(false);
+
+ // WHEN wired charging starts
+ mNotifier.onWiredChargingStarted(USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the device doesn't vibrate
+ verify(mVibrator, never()).vibrate(any(), any());
+ }
+
+ @Test
+ public void testVibrateEnabled_wirelessCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is enabled
+ enableChargingVibration(true);
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the device vibrates once
+ verify(mVibrator, times(1)).vibrate(any(), any());
+ }
+
+ @Test
+ public void testVibrateDisabled_wirelessCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is disabeld
+ enableChargingVibration(false);
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the device doesn't vibrate
+ verify(mVibrator, never()).vibrate(any(), any());
+ }
+
+ @Test
+ public void testVibrateEnabled_dndOn() {
+ createNotifier();
+
+ // GIVEN the charging vibration is enabled but dnd is on
+ enableChargingVibration(true);
+ enableChargingFeedback(
+ /* chargingFeedbackEnabled */ true,
+ /* dndOn */ true);
+
+ // WHEN wired charging starts
+ mNotifier.onWiredChargingStarted(USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the device doesn't vibrate
+ verify(mVibrator, never()).vibrate(any(), any());
+ }
+
+ @Test
+ public void testWirelessAnimationEnabled() {
+ // GIVEN the wireless charging animation is enabled
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim))
+ .thenReturn(true);
+ createNotifier();
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the charging animation is triggered
+ verify(mStatusBarManagerInternal, times(1)).showChargingAnimation(5);
+ }
+
+ @Test
+ public void testWirelessAnimationDisabled() {
+ // GIVEN the wireless charging animation is disabled
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim))
+ .thenReturn(false);
+ createNotifier();
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the charging animation never gets called
+ verify(mStatusBarManagerInternal, never()).showChargingAnimation(anyInt());
+ }
+
+ private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() {
+ @Override
+ Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
+ SuspendBlocker suspendBlocker, WindowManagerPolicy policy) {
+ return mNotifierMock;
+ }
+
+ @Override
+ SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
+ return super.createSuspendBlocker(service, name);
+ }
+
+ @Override
+ BatterySaverPolicy createBatterySaverPolicy(
+ Object lock, Context context, BatterySavingStats batterySavingStats) {
+ return mBatterySaverPolicyMock;
+ }
+
+ @Override
+ PowerManagerService.NativeWrapper createNativeWrapper() {
+ return mNativeWrapperMock;
+ }
+
+ @Override
+ WirelessChargerDetector createWirelessChargerDetector(
+ SensorManager sensorManager, SuspendBlocker suspendBlocker, Handler handler) {
+ return mWirelessChargerDetectorMock;
+ }
+
+ @Override
+ AmbientDisplayConfiguration createAmbientDisplayConfiguration(Context context) {
+ return mAmbientDisplayConfigurationMock;
+ }
+
+ @Override
+ InattentiveSleepWarningController createInattentiveSleepWarningController() {
+ return mInattentiveSleepWarningControllerMock;
+ }
+
+ @Override
+ public SystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return mSystemPropertiesMock;
+ }
+ };
+
+ private void enableChargingFeedback(boolean chargingFeedbackEnabled, boolean dndOn) {
+ // enable/disable charging feedback
+ Settings.Secure.putIntForUser(
+ mContextSpy.getContentResolver(),
+ Settings.Secure.CHARGING_SOUNDS_ENABLED,
+ chargingFeedbackEnabled ? 1 : 0,
+ USER_ID);
+
+ // toggle on/off dnd
+ Settings.Global.putInt(
+ mContextSpy.getContentResolver(),
+ Settings.Global.ZEN_MODE,
+ dndOn ? Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ : Settings.Global.ZEN_MODE_OFF);
+ }
+
+ private void enableChargingVibration(boolean enable) {
+ enableChargingFeedback(true, false);
+
+ Settings.Secure.putIntForUser(
+ mContextSpy.getContentResolver(),
+ Settings.Secure.CHARGING_VIBRATION_ENABLED,
+ enable ? 1 : 0,
+ USER_ID);
+ }
+
+ private void createNotifier() {
+ mNotifier = new Notifier(
+ mTestLooper.getLooper(),
+ mContextSpy,
+ IBatteryStats.Stub.asInterface(ServiceManager.getService(
+ BatteryStats.SERVICE_NAME)),
+ mInjector.createSuspendBlocker(mService, "testBlocker"),
+ null);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 71b568cc06c5..ae5369204428 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -37,7 +37,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index ca6fd08092df..aaf9799de777 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -30,7 +30,7 @@ import android.content.Intent;
import android.icu.util.Calendar;
import android.icu.util.GregorianCalendar;
import android.icu.util.TimeZone;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
index 239d413c12d2..f1e9191ddb4f 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
@@ -18,7 +18,7 @@ package com.android.server.timedetector;
import static org.junit.Assert.assertEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 12ba219d0365..1dd7e64690c7 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -365,8 +365,9 @@ public class AppStandbyControllerTests {
public void testSetAppStandbyBucket() throws Exception {
// For a known package, standby bucket should be set properly
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
+ mInjector.mElapsedRealtime = HOUR_MS;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
- REASON_MAIN_TIMEOUT, HOUR_MS);
+ REASON_MAIN_TIMEOUT);
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
// For an unknown package, standby bucket should not be set, hence NEVER is returned
@@ -374,7 +375,7 @@ public class AppStandbyControllerTests {
mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID);
isPackageInstalled = false; // Mock package is not installed
mController.setAppStandbyBucket(PACKAGE_UNKNOWN, USER_ID, STANDBY_BUCKET_ACTIVE,
- REASON_MAIN_TIMEOUT, HOUR_MS);
+ REASON_MAIN_TIMEOUT);
isPackageInstalled = true; // Reset mocked variable for other tests
assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN));
}
@@ -468,12 +469,13 @@ public class AppStandbyControllerTests {
@Test
public void testPredictionTimedout() throws Exception {
// Set it to timeout or usage, so that prediction can override it
+ mInjector.mElapsedRealtime = HOUR_MS;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
- REASON_MAIN_TIMEOUT, HOUR_MS);
+ REASON_MAIN_TIMEOUT);
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
- REASON_MAIN_PREDICTED, HOUR_MS);
+ REASON_MAIN_PREDICTED);
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
// Fast forward 12 hours
@@ -497,29 +499,31 @@ public class AppStandbyControllerTests {
@Test
public void testOverrides() throws Exception {
// Can force to NEVER
+ mInjector.mElapsedRealtime = HOUR_MS;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
- REASON_MAIN_FORCED, 1 * HOUR_MS);
+ REASON_MAIN_FORCED);
assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
// Prediction can't override FORCED reason
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
- REASON_MAIN_FORCED, 1 * HOUR_MS);
+ REASON_MAIN_FORCED);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
- REASON_MAIN_PREDICTED, 1 * HOUR_MS);
+ REASON_MAIN_PREDICTED);
assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1));
// Prediction can't override NEVER
+ mInjector.mElapsedRealtime = 2 * HOUR_MS;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
- REASON_MAIN_DEFAULT, 2 * HOUR_MS);
+ REASON_MAIN_DEFAULT);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
- REASON_MAIN_PREDICTED, 2 * HOUR_MS);
+ REASON_MAIN_PREDICTED);
assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
// Prediction can't set to NEVER
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
- REASON_MAIN_USAGE, 2 * HOUR_MS);
+ REASON_MAIN_USAGE);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
- REASON_MAIN_PREDICTED, 2 * HOUR_MS);
+ REASON_MAIN_PREDICTED);
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
}
@@ -530,7 +534,7 @@ public class AppStandbyControllerTests {
mInjector.mElapsedRealtime = 2000;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
- REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
+ REASON_MAIN_PREDICTED);
assertBucket(STANDBY_BUCKET_ACTIVE);
// bucketing works after timeout
@@ -554,15 +558,17 @@ public class AppStandbyControllerTests {
assertBucket(STANDBY_BUCKET_ACTIVE);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
- REASON_MAIN_PREDICTED, 1000);
+ REASON_MAIN_PREDICTED);
assertBucket(STANDBY_BUCKET_ACTIVE);
+ mInjector.mElapsedRealtime = 2000 + mController.mStrongUsageTimeoutMillis;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
- REASON_MAIN_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis);
+ REASON_MAIN_PREDICTED);
assertBucket(STANDBY_BUCKET_WORKING_SET);
+ mInjector.mElapsedRealtime = 2000 + mController.mNotificationSeenTimeoutMillis;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
- REASON_MAIN_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis);
+ REASON_MAIN_PREDICTED);
assertBucket(STANDBY_BUCKET_FREQUENT);
}
@@ -582,18 +588,18 @@ public class AppStandbyControllerTests {
// Still in ACTIVE after first USER_INTERACTION times out
mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis + 1000;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
- REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
+ REASON_MAIN_PREDICTED);
assertBucket(STANDBY_BUCKET_ACTIVE);
// Both timed out, so NOTIFICATION_SEEN timeout should be effective
mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis * 2 + 2000;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
- REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
+ REASON_MAIN_PREDICTED);
assertBucket(STANDBY_BUCKET_WORKING_SET);
mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
- REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
+ REASON_MAIN_PREDICTED);
assertBucket(STANDBY_BUCKET_RARE);
}
@@ -625,7 +631,7 @@ public class AppStandbyControllerTests {
mInjector.mElapsedRealtime = 1 * RARE_THRESHOLD + 100;
// Make sure app is in NEVER bucket
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
- REASON_MAIN_FORCED, mInjector.mElapsedRealtime);
+ REASON_MAIN_FORCED);
mController.checkIdleStates(USER_ID);
assertBucket(STANDBY_BUCKET_NEVER);
@@ -670,7 +676,7 @@ public class AppStandbyControllerTests {
// Predict to ACTIVE
mInjector.mElapsedRealtime += 1000;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
- REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
+ REASON_MAIN_PREDICTED);
assertBucket(STANDBY_BUCKET_ACTIVE);
// CheckIdleStates should not change the prediction
@@ -687,7 +693,7 @@ public class AppStandbyControllerTests {
// Predict to FREQUENT
mInjector.mElapsedRealtime = RARE_THRESHOLD;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
- REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
+ REASON_MAIN_PREDICTED);
assertBucket(STANDBY_BUCKET_FREQUENT);
// Add a short timeout event
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 73b2f6b2dc37..a3e94599cad3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -521,11 +521,12 @@ public class ActivityRecordTests extends ActivityTestsBase {
}
@Test
- public void testShouldPauseWhenMakeClientVisible() {
+ public void testShouldStartWhenMakeClientActive() {
ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
topActivity.setOccludesParent(false);
mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
- mActivity.makeClientVisible();
+ mActivity.setVisibility(true);
+ mActivity.makeActiveIfNeeded(null /* activeActivity */);
assertEquals(STARTED, mActivity.getState());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
index 574517a00f6f..71390dbbe4a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
@@ -40,7 +40,7 @@ import org.mockito.MockitoAnnotations;
* Tests for the {@link ActivityStack} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:AnimatingActivityRegistryTest
+ * atest WmTests:AnimatingActivityRegistryTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 1311889d5605..f6213bd94ddd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -42,7 +42,7 @@ import org.junit.runner.RunWith;
/**
* Build/Install/Run:
- * atest FrameworksServicesTests:AppTransitionControllerTest
+ * atest WmTests:AppTransitionControllerTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index 0ad0f95f64c1..1dda535cfb95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -60,7 +60,7 @@ import org.junit.runner.RunWith;
* appropriately.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:BoundsAnimationControllerTests
+ * atest WmTests:BoundsAnimationControllerTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 0aa6961d20b3..e8f7849ef96a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -40,7 +40,7 @@ import org.junit.runner.RunWith;
/**
* Build/Install/Run:
- * atest FrameworksServicesTests:DimmerTests
+ * atest WmTests:DimmerTests
*/
@Presubmit
@RunWith(WindowTestRunner.class)
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 73dd2df27e95..f2ba97c269d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -57,6 +57,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -86,6 +88,7 @@ import android.view.IWindowManager;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.ViewRootImpl;
+import android.view.WindowManager;
import android.view.test.InsetsModeSession;
import androidx.test.filters.SmallTest;
@@ -561,8 +564,7 @@ public class DisplayContentTests extends WindowTestsBase {
final DisplayContent dc = createNewDisplay();
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
}
@@ -829,8 +831,7 @@ public class DisplayContentTests extends WindowTestsBase {
win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
dc.updateSystemGestureExclusion();
@@ -866,8 +867,7 @@ public class DisplayContentTests extends WindowTestsBase {
win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
win2.setSystemGestureExclusion(Collections.singletonList(new Rect(20, 30, 40, 50)));
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
win2.setHasSurface(true);
@@ -898,8 +898,7 @@ public class DisplayContentTests extends WindowTestsBase {
win2.getAttrs().height = 10;
win2.setSystemGestureExclusion(Collections.emptyList());
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
win2.setHasSurface(true);
@@ -922,8 +921,7 @@ public class DisplayContentTests extends WindowTestsBase {
| SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
win.mActivityRecord.mTargetSdk = P;
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
@@ -935,6 +933,22 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testRequestResizeForEmptyFrames() {
+ final WindowState win = mChildAppWindowAbove;
+ makeWindowVisible(win, win.getParentWindow());
+ win.setRequestedSize(mDisplayContent.mBaseDisplayWidth, 0 /* height */);
+ win.mAttrs.width = win.mAttrs.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ win.mAttrs.gravity = Gravity.CENTER;
+ performLayout(mDisplayContent);
+
+ // The frame is empty because the requested height is zero.
+ assertTrue(win.getFrameLw().isEmpty());
+ // The window should be scheduled to resize then the client may report a new non-empty size.
+ win.updateResizingWindowIfNeeded();
+ assertThat(mWm.mResizingWindows).contains(win);
+ }
+
+ @Test
public void testOrientationChangeLogging() {
MetricsLogger mockLogger = mock(MetricsLogger.class);
Configuration oldConfig = new Configuration();
@@ -1011,6 +1025,11 @@ public class DisplayContentTests extends WindowTestsBase {
mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateInputWindows */);
}
+ private void performLayout(DisplayContent dc) {
+ dc.setLayoutNeeded();
+ dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ }
+
/**
* Create DisplayContent that does not update display base/initial values from device to keep
* the values set by test.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 112479b3b9a0..1a575962b961 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -61,7 +61,7 @@ import org.mockito.MockitoAnnotations;
/**
* Build/Install/Run:
- * atest FrameworksServicesTests:RemoteAnimationControllerTest
+ * atest WmTests:RemoteAnimationControllerTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index e0112809b22b..bac2bcae30de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -60,7 +60,7 @@ import java.util.concurrent.CountDownLatch;
* Test class for {@link SurfaceAnimationRunner}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:SurfaceAnimationRunnerTest
+ * atest WmTests:SurfaceAnimationRunnerTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java
index 0274b7d788ff..e71247173930 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java
@@ -38,7 +38,7 @@ import org.mockito.MockitoAnnotations;
* Test class for {@link TaskSnapshotCache}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:TaskSnapshotCacheTest
+ * atest WmTests:TaskSnapshotCacheTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 8fe0cdbbd872..2e485dd1bec3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -53,7 +53,7 @@ import org.mockito.Mockito;
* Test class for {@link TaskSnapshotController}.
*
* Build/Install/Run:
- * * atest FrameworksServicesTests:TaskSnapshotControllerTest
+ * * atest WmTests:TaskSnapshotControllerTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index b5a5790a3a8c..eb8eb98fd484 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -47,7 +47,7 @@ import java.util.function.Predicate;
* Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader}
*
* Build/Install/Run:
- * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
+ * atest WmTests:TaskSnapshotPersisterLoaderTest
*/
@MediumTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 2d418ffffcf6..ed87f3a0c604 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -53,7 +53,7 @@ import org.junit.runner.RunWith;
* Test class for {@link TaskSnapshotSurface}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:TaskSnapshotSurfaceTest
+ * atest WmTests:TaskSnapshotSurfaceTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
index 8936aadd5f92..3c0dd1e897f5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
@@ -39,7 +39,7 @@ import java.util.function.Consumer;
* Tests for {@link WindowContainer#forAllWindows} and various implementations.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowContainerTraversalTests
+ * atest WmTests:WindowContainerTraversalTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index e081ca374808..7e248f854dcf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -92,7 +92,7 @@ import java.util.List;
* Tests for the {@link WindowState} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowStateTests
+ * atest WmTests:WindowStateTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index ea8831571639..31a7f2437536 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -44,6 +44,7 @@ import android.view.Display;
import android.view.DisplayInfo;
import android.view.IWindow;
import android.view.SurfaceControl.Transaction;
+import android.view.View;
import android.view.WindowManager;
import com.android.server.AttributeCache;
@@ -312,6 +313,16 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
}
+ static void makeWindowVisible(WindowState... windows) {
+ for (WindowState win : windows) {
+ win.mViewVisibility = View.VISIBLE;
+ win.mRelayoutCalled = true;
+ win.mHasSurface = true;
+ win.mHidden = false;
+ win.showLw(false /* doAnimation */, false /* requestAnim */);
+ }
+ }
+
/** Creates a {@link ActivityStack} and adds it to the specified {@link DisplayContent}. */
ActivityStack createTaskStackOnDisplay(DisplayContent dc) {
return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
new file mode 100644
index 000000000000..9cda08458640
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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 com.android.server.wm.utils;
+
+import static android.graphics.Bitmap.Config.ARGB_8888;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.view.Surface;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class RotationAnimationUtilsTest {
+
+ private static final int BITMAP_HEIGHT = 100;
+ private static final int BITMAP_WIDTH = 100;
+ private static final int POINT_WIDTH = 1000;
+ private static final int POINT_HEIGHT = 2000;
+
+ private ColorSpace mColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+ private Matrix mMatrix;
+
+ @Before
+ public void setup() {
+ mMatrix = new Matrix();
+ }
+
+ @Test
+ public void blackLuma() {
+ Bitmap swBitmap = createBitmap(0);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(0, borderLuma, 0);
+ }
+
+ @Test
+ public void whiteLuma() {
+ Bitmap swBitmap = createBitmap(1);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(1, borderLuma, 0);
+ }
+
+ @Test
+ public void whiteImageBlackBorderLuma() {
+ Bitmap swBitmap = createBitmap(1);
+ setBorderLuma(swBitmap, 0);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(0, borderLuma, 0);
+ }
+
+ @Test
+ public void blackImageWhiteBorderLuma() {
+ Bitmap swBitmap = createBitmap(0);
+ setBorderLuma(swBitmap, 1);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(1, borderLuma, 0);
+ }
+
+ @Test
+ public void rotate_0_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_0,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(POINT_WIDTH, newPoints.x, 0);
+ assertEquals(POINT_HEIGHT, newPoints.y, 0);
+ }
+
+ @Test
+ public void rotate_90_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_90,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(0, newPoints.x, 0);
+ assertEquals(POINT_WIDTH, newPoints.y, 0);
+ }
+
+ @Test
+ public void rotate_180_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_180,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(0, newPoints.x, 0);
+ assertEquals(0, newPoints.y, 0);
+ }
+
+ @Test
+ public void rotate_270_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_270,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(POINT_HEIGHT, newPoints.x, 0);
+ assertEquals(0, newPoints.y, 0);
+ }
+
+ private PointF checkMappedPoints(int x, int y) {
+ final float[] fs = new float[] {x, y};
+ mMatrix.mapPoints(fs);
+ return new PointF(fs[0], fs[1]);
+ }
+
+ private Bitmap createBitmap(float luma) {
+ Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, ARGB_8888);
+ for (int i = 0; i < BITMAP_WIDTH; i++) {
+ for (int j = 0; j < BITMAP_HEIGHT; j++) {
+ bitmap.setPixel(i, j, Color.argb(1, luma, luma, luma));
+ }
+ }
+ return bitmap;
+ }
+
+ private GraphicBuffer swBitmapToGraphicsBuffer(Bitmap swBitmap) {
+ Bitmap hwBitmap = swBitmap.copy(Bitmap.Config.HARDWARE, false);
+ return hwBitmap.createGraphicBufferHandle();
+ }
+
+ private void setBorderLuma(Bitmap swBitmap, float luma) {
+ int i;
+ int width = swBitmap.getWidth();
+ int height = swBitmap.getHeight();
+ for (i = 0; i < width; i++) {
+ swBitmap.setPixel(i, 0, Color.argb(1, luma, luma, luma));
+ swBitmap.setPixel(i, height - 1, Color.argb(1, luma, luma, luma));
+ }
+ for (i = 0; i < height; i++) {
+ swBitmap.setPixel(0, i, Color.argb(1, luma, luma, luma));
+ swBitmap.setPixel(width - 1, i, Color.argb(1, luma, luma, luma));
+ }
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index c900f386b438..8397aa485595 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1568,44 +1568,16 @@ public class UsageStatsService extends SystemService implements
}
@Override
- public void setAppStandbyBucket(String packageName,
- int bucket, int userId) {
+ public void setAppStandbyBucket(String packageName, int bucket, int userId) {
getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE,
"No permission to change app standby state");
- if (bucket < UsageStatsManager.STANDBY_BUCKET_ACTIVE
- || bucket > UsageStatsManager.STANDBY_BUCKET_NEVER) {
- throw new IllegalArgumentException("Cannot set the standby bucket to " + bucket);
- }
final int callingUid = Binder.getCallingUid();
- try {
- userId = ActivityManager.getService().handleIncomingUser(
- Binder.getCallingPid(), callingUid, userId, false, true,
- "setAppStandbyBucket", null);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID;
- final boolean systemCaller = UserHandle.isCore(callingUid);
- final int reason = systemCaller
- ? UsageStatsManager.REASON_MAIN_FORCED
- : UsageStatsManager.REASON_MAIN_PREDICTED;
+ final int callingPid = Binder.getCallingPid();
final long token = Binder.clearCallingIdentity();
try {
- final int packageUid = mPackageManagerInternal.getPackageUid(packageName,
- PackageManager.MATCH_ANY_USER | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE, userId);
- // Caller cannot set their own standby state
- if (packageUid == callingUid) {
- throw new IllegalArgumentException("Cannot set your own standby bucket");
- }
- if (packageUid < 0) {
- throw new IllegalArgumentException(
- "Cannot set standby bucket for non existent package (" + packageName
- + ")");
- }
- mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason,
- SystemClock.elapsedRealtime(), shellCaller);
+ mAppStandby.setAppStandbyBucket(packageName, bucket, userId,
+ callingUid, callingPid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1643,37 +1615,11 @@ public class UsageStatsService extends SystemService implements
"No permission to change app standby state");
final int callingUid = Binder.getCallingUid();
- try {
- userId = ActivityManager.getService().handleIncomingUser(
- Binder.getCallingPid(), callingUid, userId, false, true,
- "setAppStandbyBucket", null);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID;
- final int reason = shellCaller
- ? UsageStatsManager.REASON_MAIN_FORCED
- : UsageStatsManager.REASON_MAIN_PREDICTED;
+ final int callingPid = Binder.getCallingPid();
final long token = Binder.clearCallingIdentity();
try {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- List<AppStandbyInfo> bucketList = appBuckets.getList();
- for (AppStandbyInfo bucketInfo : bucketList) {
- final String packageName = bucketInfo.mPackageName;
- final int bucket = bucketInfo.mStandbyBucket;
- if (bucket < UsageStatsManager.STANDBY_BUCKET_ACTIVE
- || bucket > UsageStatsManager.STANDBY_BUCKET_NEVER) {
- throw new IllegalArgumentException(
- "Cannot set the standby bucket to " + bucket);
- }
- // Caller cannot set their own standby state
- if (mPackageManagerInternal.getPackageUid(packageName,
- PackageManager.MATCH_ANY_USER, userId) == callingUid) {
- throw new IllegalArgumentException("Cannot set your own standby bucket");
- }
- mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason,
- elapsedRealtime, shellCaller);
- }
+ mAppStandby.setAppStandbyBuckets(appBuckets.getList(), userId,
+ callingUid, callingPid);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 198b4c31249a..bde2cfd52c0f 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -611,63 +611,89 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
int setParameter(UUID modelId, @ModelParams int modelParam, int value) {
synchronized (mLock) {
- MetricsLogger.count(mContext, "sth_set_parameter", 1);
- if (modelId == null || mModule == null) {
- return SoundTrigger.STATUS_ERROR;
- }
- ModelData modelData = mModelDataMap.get(modelId);
- if (modelData == null) {
- Slog.w(TAG, "SetParameter: Invalid model id:" + modelId);
- return SoundTrigger.STATUS_BAD_VALUE;
- }
- if (!modelData.isModelLoaded()) {
- Slog.i(TAG, "SetParameter: Given model is not loaded:" + modelId);
- return SoundTrigger.STATUS_BAD_VALUE;
- }
+ return setParameterLocked(mModelDataMap.get(modelId), modelParam, value);
+ }
+ }
- return mModule.setParameter(modelData.getHandle(), modelParam, value);
+ int setKeyphraseParameter(int keyphraseId, @ModelParams int modelParam, int value) {
+ synchronized (mLock) {
+ return setParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam, value);
}
}
- int getParameter(@NonNull UUID modelId, @ModelParams int modelParam)
- throws UnsupportedOperationException, IllegalArgumentException {
+ private int setParameterLocked(@Nullable ModelData modelData, @ModelParams int modelParam,
+ int value) {
+ MetricsLogger.count(mContext, "sth_set_parameter", 1);
+ if (mModule == null) {
+ return SoundTrigger.STATUS_NO_INIT;
+ }
+ if (modelData == null || !modelData.isModelLoaded()) {
+ Slog.i(TAG, "SetParameter: Given model is not loaded:" + modelData);
+ return SoundTrigger.STATUS_BAD_VALUE;
+ }
+
+ return mModule.setParameter(modelData.getHandle(), modelParam, value);
+ }
+
+ int getParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
synchronized (mLock) {
- MetricsLogger.count(mContext, "sth_get_parameter", 1);
- if (mModule == null) {
- throw new UnsupportedOperationException("SoundTriggerModule not initialized");
- }
+ return getParameterLocked(mModelDataMap.get(modelId), modelParam);
+ }
+ }
- ModelData modelData = mModelDataMap.get(modelId);
- if (modelData == null) {
- throw new IllegalArgumentException("Invalid model id:" + modelId);
- }
- if (!modelData.isModelLoaded()) {
- throw new UnsupportedOperationException("Given model is not loaded:" + modelId);
- }
+ int getKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
+ synchronized (mLock) {
+ return getParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam);
+ }
+ }
- return mModule.getParameter(modelData.getHandle(), modelParam);
+ private int getParameterLocked(@Nullable ModelData modelData, @ModelParams int modelParam) {
+ MetricsLogger.count(mContext, "sth_get_parameter", 1);
+ if (mModule == null) {
+ throw new UnsupportedOperationException("SoundTriggerModule not initialized");
}
+
+ if (modelData == null) {
+ throw new IllegalArgumentException("Invalid model id");
+ }
+ if (!modelData.isModelLoaded()) {
+ throw new UnsupportedOperationException("Given model is not loaded:" + modelData);
+ }
+
+ return mModule.getParameter(modelData.getHandle(), modelParam);
}
@Nullable
ModelParamRange queryParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
synchronized (mLock) {
- MetricsLogger.count(mContext, "sth_query_parameter", 1);
- if (mModule == null) {
- return null;
- }
- ModelData modelData = mModelDataMap.get(modelId);
- if (modelData == null) {
- Slog.w(TAG, "queryParameter: Invalid model id:" + modelId);
- return null;
- }
- if (!modelData.isModelLoaded()) {
- Slog.i(TAG, "queryParameter: Given model is not loaded:" + modelId);
- return null;
- }
+ return queryParameterLocked(mModelDataMap.get(modelId), modelParam);
+ }
+ }
- return mModule.queryParameter(modelData.getHandle(), modelParam);
+ @Nullable
+ ModelParamRange queryKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
+ synchronized (mLock) {
+ return queryParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam);
+ }
+ }
+
+ @Nullable
+ private ModelParamRange queryParameterLocked(@Nullable ModelData modelData,
+ @ModelParams int modelParam) {
+ MetricsLogger.count(mContext, "sth_query_parameter", 1);
+ if (mModule == null) {
+ return null;
+ }
+ if (modelData == null) {
+ Slog.w(TAG, "queryParameter: Invalid model id");
+ return null;
}
+ if (!modelData.isModelLoaded()) {
+ Slog.i(TAG, "queryParameter: Given model is not loaded:" + modelData);
+ return null;
+ }
+
+ return mModule.queryParameter(modelData.getHandle(), modelParam);
}
//---- SoundTrigger.StatusListener methods
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
index d05e044499ab..54dffdc4c13a 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
@@ -16,17 +16,17 @@
package com.android.server.soundtrigger;
+import android.annotation.Nullable;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
-import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
-import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
-import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
-import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
-import android.hardware.soundtrigger.SoundTriggerModule;
+
+import com.android.server.voiceinteraction.VoiceInteractionManagerService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -71,6 +71,58 @@ public abstract class SoundTriggerInternal {
public abstract ModuleProperties getModuleProperties();
/**
+ * Set a model specific {@link ModelParams} with the given value. This
+ * parameter will keep its value for the duration the model is loaded regardless of starting and
+ * stopping recognition. Once the model is unloaded, the value will be lost.
+ * {@link SoundTriggerInternal#queryParameter} should be checked first before calling this
+ * method.
+ *
+ * @param keyphraseId The identifier of the keyphrase for which
+ * to modify model parameters
+ * @param modelParam {@link ModelParams}
+ * @param value Value to set
+ * @return - {@link SoundTrigger#STATUS_OK} in case of success
+ * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
+ * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
+ * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
+ * if API is not supported by HAL
+ */
+ public abstract int setParameter(int keyphraseId, @ModelParams int modelParam, int value);
+
+ /**
+ * Get a model specific {@link ModelParams}. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See ModelParams for parameter default values.
+ * {@link SoundTriggerInternal#queryParameter} should be checked first before calling this
+ * method.
+ *
+ * @param keyphraseId The identifier of the keyphrase for which
+ * to modify model parameters
+ * @param modelParam {@link ModelParams}
+ * @return value of parameter
+ * @throws UnsupportedOperationException if hal or model do not support this API.
+ * queryParameter should be checked first.
+ * @throws IllegalArgumentException if invalid model handle or parameter is passed.
+ * queryParameter should be checked first.
+ */
+ public abstract int getParameter(int keyphraseId, @ModelParams int modelParam);
+
+ /**
+ * Determine if parameter control is supported for the given model handle.
+ * This method should be checked prior to calling {@link SoundTriggerInternal#setParameter}
+ * or {@link SoundTriggerInternal#getParameter}.
+ *
+ * @param keyphraseId The identifier of the keyphrase for which
+ * to modify model parameters
+ * @param modelParam {@link ModelParams}
+ * @return supported range of parameter, null if not supported
+ */
+ @Nullable
+ public abstract ModelParamRange queryParameter(int keyphraseId,
+ @ModelParams int modelParam);
+
+ /**
* Unloads (and stops if running) the given keyphraseId
*/
public abstract int unloadKeyphraseModel(int keyphaseId);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 68b16f39e149..e37755bddcaa 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -1446,26 +1446,45 @@ public class SoundTriggerService extends SystemService {
@Override
public int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig) {
- if (!isInitialized()) return STATUS_ERROR;
+ if (!isInitialized()) throw new UnsupportedOperationException();
return mSoundTriggerHelper.startKeyphraseRecognition(keyphraseId, soundModel, listener,
recognitionConfig);
}
@Override
public synchronized int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
- if (!isInitialized()) return STATUS_ERROR;
+ if (!isInitialized()) throw new UnsupportedOperationException();
return mSoundTriggerHelper.stopKeyphraseRecognition(keyphraseId, listener);
}
@Override
public ModuleProperties getModuleProperties() {
- if (!isInitialized()) return null;
+ if (!isInitialized()) throw new UnsupportedOperationException();
return mSoundTriggerHelper.getModuleProperties();
}
@Override
+ public int setParameter(int keyphraseId, @ModelParams int modelParam, int value) {
+ if (!isInitialized()) throw new UnsupportedOperationException();
+ return mSoundTriggerHelper.setKeyphraseParameter(keyphraseId, modelParam, value);
+ }
+
+ @Override
+ public int getParameter(int keyphraseId, @ModelParams int modelParam) {
+ if (!isInitialized()) throw new UnsupportedOperationException();
+ return mSoundTriggerHelper.getKeyphraseParameter(keyphraseId, modelParam);
+ }
+
+ @Override
+ @Nullable
+ public ModelParamRange queryParameter(int keyphraseId, @ModelParams int modelParam) {
+ if (!isInitialized()) throw new UnsupportedOperationException();
+ return mSoundTriggerHelper.queryKeyphraseParameter(keyphraseId, modelParam);
+ }
+
+ @Override
public int unloadKeyphraseModel(int keyphraseId) {
- if (!isInitialized()) return STATUS_ERROR;
+ if (!isInitialized()) throw new UnsupportedOperationException();
return mSoundTriggerHelper.unloadKeyphraseSoundModel(keyphraseId);
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index e9db31ba3e25..06c807421d1a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -41,7 +41,9 @@ import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.os.Binder;
@@ -1084,6 +1086,55 @@ public class VoiceInteractionManagerService extends SystemService {
}
}
+ @Override
+ public int setParameter(IVoiceInteractionService service, int keyphraseId,
+ @ModelParams int modelParam, int value) {
+ // Allow the call if this is the current voice interaction service.
+ synchronized (this) {
+ enforceIsCurrentVoiceInteractionService(service);
+ }
+
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mSoundTriggerInternal.setParameter(keyphraseId, modelParam, value);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
+ @Override
+ public int getParameter(IVoiceInteractionService service, int keyphraseId,
+ @ModelParams int modelParam) {
+ // Allow the call if this is the current voice interaction service.
+ synchronized (this) {
+ enforceIsCurrentVoiceInteractionService(service);
+ }
+
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mSoundTriggerInternal.getParameter(keyphraseId, modelParam);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
+ @Override
+ @Nullable
+ public ModelParamRange queryParameter(IVoiceInteractionService service,
+ int keyphraseId, @ModelParams int modelParam) {
+ // Allow the call if this is the current voice interaction service.
+ synchronized (this) {
+ enforceIsCurrentVoiceInteractionService(service);
+ }
+
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mSoundTriggerInternal.queryParameter(keyphraseId, modelParam);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
private synchronized void unloadAllKeyphraseModels() {
for (int i = 0; i < mLoadedKeyphraseIds.size(); i++) {
final long caller = Binder.clearCallingIdentity();
diff --git a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
index b75510b576f6..488ee78f6230 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
@@ -83,7 +83,7 @@ import com.android.server.wm.ActivityMetricsLaunchObserver;
* could transition to INTENT_STARTED.
*
* <p> If any bad transition happened, the state becomse UNKNOWN. The UNKNOWN state
- * could be * accumulated, because during the UNKNOWN state more IntentStarted may
+ * could be accumulated, because during the UNKNOWN state more IntentStarted may
* be triggered. To recover from UNKNOWN to INIT, all the accumualted IntentStarted
* should termniate.
*
@@ -100,7 +100,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
@Override
public void onIntentStarted(@NonNull Intent intent, long timestampNs) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "IntentStarted during UNKNOWN." + intent);
+ Log.wtf(TAG, "IntentStarted during UNKNOWN." + intent);
incAccIntentStartedEvents();
return;
}
@@ -110,32 +110,32 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
state != State.ACTIVITY_CANCELLED &&
state != State.ACTIVITY_FINISHED &&
state != State.REPORT_FULLY_DRAWN) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.INTENT_STARTED));
incAccIntentStartedEvents();
incAccIntentStartedEvents();
return;
}
- Log.i(TAG, String.format("Tansition from %s to %s", state, State.INTENT_STARTED));
+ Log.i(TAG, String.format("Transition from %s to %s", state, State.INTENT_STARTED));
state = State.INTENT_STARTED;
}
@Override
public void onIntentFailed() {
if (state == State.UNKNOWN) {
- Log.e(TAG, "IntentFailed during UNKNOWN.");
+ Log.wtf(TAG, "IntentFailed during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
if (state != State.INTENT_STARTED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.INTENT_FAILED));
incAccIntentStartedEvents();
return;
}
- Log.i(TAG, String.format("Tansition from %s to %s", state, State.INTENT_FAILED));
+ Log.i(TAG, String.format("Transition from %s to %s", state, State.INTENT_FAILED));
state = State.INTENT_FAILED;
}
@@ -143,11 +143,11 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
@Temperature int temperature) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onActivityLaunched during UNKNOWN.");
+ Log.wtf(TAG, "onActivityLaunched during UNKNOWN.");
return;
}
if (state != State.INTENT_STARTED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.ACTIVITY_LAUNCHED));
incAccIntentStartedEvents();
return;
@@ -160,12 +160,12 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
@Override
public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onActivityLaunchCancelled during UNKNOWN.");
+ Log.wtf(TAG, "onActivityLaunchCancelled during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
if (state != State.ACTIVITY_LAUNCHED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.ACTIVITY_CANCELLED));
incAccIntentStartedEvents();
return;
@@ -179,13 +179,13 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity,
long timestampNs) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onActivityLaunchFinished during UNKNOWN.");
+ Log.wtf(TAG, "onActivityLaunchFinished during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
if (state != State.ACTIVITY_LAUNCHED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.ACTIVITY_FINISHED));
incAccIntentStartedEvents();
return;
@@ -199,7 +199,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
long timestampNs) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onReportFullyDrawn during UNKNOWN.");
+ Log.wtf(TAG, "onReportFullyDrawn during UNKNOWN.");
return;
}
if (state == State.INIT) {
@@ -207,7 +207,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
}
if (state != State.ACTIVITY_FINISHED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.REPORT_FULLY_DRAWN));
return;
}
@@ -230,7 +230,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
private void incAccIntentStartedEvents() {
if (accIntentStartedEvents < 0) {
throw new AssertionError(
- String.format("The number of unknows cannot be negative"));
+ String.format("The number of unknowns cannot be negative"));
}
if (accIntentStartedEvents == 0) {
state = State.UNKNOWN;
@@ -243,7 +243,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
private void decAccIntentStartedEvents() {
if (accIntentStartedEvents <= 0) {
throw new AssertionError(
- String.format("The number of unknows cannot be negative"));
+ String.format("The number of unknowns cannot be negative"));
}
if(accIntentStartedEvents == 1) {
state = State.INIT;
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index 8b8c86be7b0a..ea641f866b98 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -19,7 +19,7 @@ package android.telecom;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 86ad795b9ea2..a8852a849604 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -20,12 +20,11 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import com.android.internal.telecom.IVideoProvider;
diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java
index a5d25e2ce4bb..fb6f99405759 100644
--- a/telecomm/java/android/telecom/CallerInfo.java
+++ b/telecomm/java/android/telecom/CallerInfo.java
@@ -17,7 +17,7 @@
package android.telecom;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -41,8 +41,8 @@ import com.android.i18n.phonenumbers.NumberParseException;
import com.android.i18n.phonenumbers.PhoneNumberUtil;
import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
import com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder;
-
import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Locale;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 8808339b1664..f205ec64f49b 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -21,9 +21,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
import android.app.Notification;
import android.bluetooth.BluetoothDevice;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 7d4ee7686512..4f6a9d6450f8 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -16,7 +16,7 @@
package android.telecom;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index a234bb0af8fa..be4e2f4c65e1 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -16,22 +16,21 @@
package android.telecom;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.telecom.Call.Details.CallDirection;
+import com.android.internal.telecom.IVideoProvider;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import com.android.internal.telecom.IVideoProvider;
-
/**
* Information about a call that is used between InCallService and Telecom.
* @hide
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 61a639a1a235..a427ed612b31 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -17,8 +17,8 @@
package android.telecom;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
import android.bluetooth.BluetoothDevice;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Bundle;
import android.util.ArrayMap;
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index eb568e04ebf3..e1bcb5fbdf00 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -18,7 +18,7 @@ package android.telecom;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.os.Build;
import android.os.Parcel;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index af3c55abf00c..c4c1e21e7c41 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -26,7 +26,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -49,6 +49,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -882,7 +883,8 @@ public class TelecomManager {
*/
public TelecomManager(Context context, ITelecomService telecomServiceImpl) {
Context appContext = context.getApplicationContext();
- if (appContext != null) {
+ if (appContext != null && Objects.equals(context.getFeatureId(),
+ appContext.getFeatureId())) {
mContext = appContext;
} else {
mContext = context;
@@ -916,7 +918,7 @@ public class TelecomManager {
try {
if (isServiceConnected()) {
return getTelecomService().getDefaultOutgoingPhoneAccount(uriScheme,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), mContext.getFeatureId());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getDefaultOutgoingPhoneAccount", e);
@@ -1113,7 +1115,8 @@ public class TelecomManager {
public List<PhoneAccountHandle> getSelfManagedPhoneAccounts() {
try {
if (isServiceConnected()) {
- return getTelecomService().getSelfManagedPhoneAccounts(mContext.getOpPackageName());
+ return getTelecomService().getSelfManagedPhoneAccounts(mContext.getOpPackageName(),
+ mContext.getFeatureId());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getSelfManagedPhoneAccounts()", e);
@@ -1138,8 +1141,8 @@ public class TelecomManager {
boolean includeDisabledAccounts) {
try {
if (isServiceConnected()) {
- return getTelecomService().getCallCapablePhoneAccounts(
- includeDisabledAccounts, mContext.getOpPackageName());
+ return getTelecomService().getCallCapablePhoneAccounts(includeDisabledAccounts,
+ mContext.getOpPackageName(), mContext.getFeatureId());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts(" +
@@ -1442,7 +1445,7 @@ public class TelecomManager {
try {
if (isServiceConnected()) {
return getTelecomService().isVoiceMailNumber(accountHandle, number,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), mContext.getFeatureId());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling ITelecomService#isVoiceMailNumber.", e);
@@ -1464,7 +1467,7 @@ public class TelecomManager {
try {
if (isServiceConnected()) {
return getTelecomService().getVoiceMailNumber(accountHandle,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), mContext.getFeatureId());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling ITelecomService#hasVoiceMailNumber.", e);
@@ -1485,7 +1488,7 @@ public class TelecomManager {
try {
if (isServiceConnected()) {
return getTelecomService().getLine1Number(accountHandle,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), mContext.getFeatureId());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling ITelecomService#getLine1Number.", e);
@@ -1506,7 +1509,8 @@ public class TelecomManager {
public boolean isInCall() {
try {
if (isServiceConnected()) {
- return getTelecomService().isInCall(mContext.getOpPackageName());
+ return getTelecomService().isInCall(mContext.getOpPackageName(),
+ mContext.getFeatureId());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling isInCall().", e);
@@ -1531,7 +1535,8 @@ public class TelecomManager {
public boolean isInManagedCall() {
try {
if (isServiceConnected()) {
- return getTelecomService().isInManagedCall(mContext.getOpPackageName());
+ return getTelecomService().isInManagedCall(mContext.getOpPackageName(),
+ mContext.getFeatureId());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling isInManagedCall().", e);
@@ -1711,7 +1716,8 @@ public class TelecomManager {
public boolean isTtySupported() {
try {
if (isServiceConnected()) {
- return getTelecomService().isTtySupported(mContext.getOpPackageName());
+ return getTelecomService().isTtySupported(mContext.getOpPackageName(),
+ mContext.getFeatureId());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException attempting to get TTY supported state.", e);
@@ -1735,7 +1741,8 @@ public class TelecomManager {
public @TtyMode int getCurrentTtyMode() {
try {
if (isServiceConnected()) {
- return getTelecomService().getCurrentTtyMode(mContext.getOpPackageName());
+ return getTelecomService().getCurrentTtyMode(mContext.getOpPackageName(),
+ mContext.getFeatureId());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException attempting to get the current TTY mode.", e);
@@ -1925,7 +1932,8 @@ public class TelecomManager {
ITelecomService service = getTelecomService();
if (service != null) {
try {
- service.showInCallScreen(showDialpad, mContext.getOpPackageName());
+ service.showInCallScreen(showDialpad, mContext.getOpPackageName(),
+ mContext.getFeatureId());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#showCallScreen", e);
}
@@ -1988,7 +1996,7 @@ public class TelecomManager {
}
try {
service.placeCall(address, extras == null ? new Bundle() : extras,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), mContext.getFeatureId());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#placeCall", e);
}
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index 4a1aa0a8ffa4..109e7f829f2e 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -16,7 +16,7 @@
package android.telecom;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index 64e6ca3416e3..4197f3cfc6c3 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -19,7 +19,6 @@ package android.telecom;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
-import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 204c37e9aa38..c54da6b4d527 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -35,12 +35,13 @@ interface ITelecomService {
*
* @param showDialpad if true, make the dialpad visible initially.
*/
- void showInCallScreen(boolean showDialpad, String callingPackage);
+ void showInCallScreen(boolean showDialpad, String callingPackage, String callingFeatureId);
/**
* @see TelecomServiceImpl#getDefaultOutgoingPhoneAccount
*/
- PhoneAccountHandle getDefaultOutgoingPhoneAccount(in String uriScheme, String callingPackage);
+ PhoneAccountHandle getDefaultOutgoingPhoneAccount(in String uriScheme, String callingPackage,
+ String callingFeatureId);
/**
* @see TelecomServiceImpl#getUserSelectedOutgoingPhoneAccount
@@ -56,12 +57,13 @@ interface ITelecomService {
* @see TelecomServiceImpl#getCallCapablePhoneAccounts
*/
List<PhoneAccountHandle> getCallCapablePhoneAccounts(
- boolean includeDisabledAccounts, String callingPackage);
+ boolean includeDisabledAccounts, String callingPackage, String callingFeatureId);
/**
* @see TelecomServiceImpl#getSelfManagedPhoneAccounts
*/
- List<PhoneAccountHandle> getSelfManagedPhoneAccounts(String callingPackage);
+ List<PhoneAccountHandle> getSelfManagedPhoneAccounts(String callingPackage,
+ String callingFeatureId);
/**
* @see TelecomManager#getPhoneAccountsSupportingScheme
@@ -123,17 +125,19 @@ interface ITelecomService {
* @see TelecomServiceImpl#isVoiceMailNumber
*/
boolean isVoiceMailNumber(in PhoneAccountHandle accountHandle, String number,
- String callingPackage);
+ String callingPackage, String callingFeatureId);
/**
* @see TelecomServiceImpl#getVoiceMailNumber
*/
- String getVoiceMailNumber(in PhoneAccountHandle accountHandle, String callingPackage);
+ String getVoiceMailNumber(in PhoneAccountHandle accountHandle, String callingPackage,
+ String callingFeatureId);
/**
* @see TelecomServiceImpl#getLine1Number
*/
- String getLine1Number(in PhoneAccountHandle accountHandle, String callingPackage);
+ String getLine1Number(in PhoneAccountHandle accountHandle, String callingPackage,
+ String callingFeatureId);
/**
* @see TelecomServiceImpl#getDefaultPhoneApp
@@ -172,12 +176,12 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#isInCall
*/
- boolean isInCall(String callingPackage);
+ boolean isInCall(String callingPackage, String callingFeatureId);
/**
* @see TelecomServiceImpl#isInManagedCall
*/
- boolean isInManagedCall(String callingPackage);
+ boolean isInManagedCall(String callingPackage, String callingFeatureId);
/**
* @see TelecomServiceImpl#isRinging
@@ -229,12 +233,12 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#isTtySupported
*/
- boolean isTtySupported(String callingPackage);
+ boolean isTtySupported(String callingPackage, String callingFeatureId);
/**
* @see TelecomServiceImpl#getCurrentTtyMode
*/
- int getCurrentTtyMode(String callingPackage);
+ int getCurrentTtyMode(String callingPackage, String callingFeatureId);
/**
* @see TelecomServiceImpl#addNewIncomingCall
@@ -249,7 +253,7 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#placeCall
*/
- void placeCall(in Uri handle, in Bundle extras, String callingPackage);
+ void placeCall(in Uri handle, in Bundle extras, String callingPackage, String callingFeatureId);
/**
* @see TelecomServiceImpl#enablePhoneAccount
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index f39981fdf25d..aaafee29e24a 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
index eb02ea6f5e40..368f8f1dab2e 100644
--- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
@@ -25,7 +25,7 @@ import android.content.res.Resources;
import android.os.RemoteException;
import android.permission.IPermissionManager;
import android.provider.Settings;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
diff --git a/telephony/common/com/android/internal/telephony/GsmAlphabet.java b/telephony/common/com/android/internal/telephony/GsmAlphabet.java
index 5fb4e90b9666..a36ff9341275 100644
--- a/telephony/common/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/common/com/android/internal/telephony/GsmAlphabet.java
@@ -16,10 +16,10 @@
package com.android.internal.telephony;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
import android.os.Build;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.text.TextUtils;
import android.util.SparseIntArray;
diff --git a/telephony/common/com/android/internal/telephony/HbpcdUtils.java b/telephony/common/com/android/internal/telephony/HbpcdUtils.java
index 2f3194214be6..45a563c09394 100644
--- a/telephony/common/com/android/internal/telephony/HbpcdUtils.java
+++ b/telephony/common/com/android/internal/telephony/HbpcdUtils.java
@@ -19,7 +19,7 @@ package com.android.internal.telephony;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import com.android.internal.telephony.HbpcdLookup.ArbitraryMccSidMatch;
import com.android.internal.telephony.HbpcdLookup.MccIdd;
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index b30258906368..afb9b6f52bdb 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -40,7 +40,7 @@ import android.os.UserHandle;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
import android.telephony.PackageChangeReceiver;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.TelephonyManager;
import android.util.Log;
diff --git a/telephony/common/com/android/internal/telephony/SmsConstants.java b/telephony/common/com/android/internal/telephony/SmsConstants.java
index 19f52b0ef429..3aa8bbf607d1 100644
--- a/telephony/common/com/android/internal/telephony/SmsConstants.java
+++ b/telephony/common/com/android/internal/telephony/SmsConstants.java
@@ -15,7 +15,7 @@
*/
package com.android.internal.telephony;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* SMS Constants and must be the same as the corresponding
diff --git a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
index 06c08f56aa1f..06c37288a1a6 100644
--- a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
+++ b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
@@ -24,7 +24,7 @@ import android.os.PersistableBundle;
import android.os.SystemProperties;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 80a55b2a1147..4109ca6bd7d0 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -28,7 +28,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
diff --git a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 2abcc76fdccc..2abcc76fdccc 100644
--- a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
diff --git a/telephony/java/android/service/carrier/CarrierIdentifier.java b/telephony/java/android/service/carrier/CarrierIdentifier.java
index af5bf7475f95..7957c258b54f 100644
--- a/telephony/java/android/service/carrier/CarrierIdentifier.java
+++ b/telephony/java/android/service/carrier/CarrierIdentifier.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.TelephonyManager;
import com.android.internal.telephony.uicc.IccUtils;
diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java
index 6c357ccdd03d..8450a9018634 100644
--- a/telephony/java/android/service/euicc/EuiccProfileInfo.java
+++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java
@@ -19,7 +19,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.carrier.CarrierIdentifier;
diff --git a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
index c7a985160730..2382f657c9ee 100644
--- a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
+++ b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
@@ -17,7 +17,7 @@ package android.service.euicc;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.euicc.DownloadableSubscription;
diff --git a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
index abd4065c754a..d0fb51180c1d 100644
--- a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
+++ b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
@@ -17,7 +17,7 @@ package android.service.euicc;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.euicc.DownloadableSubscription;
diff --git a/telephony/java/android/telephony/AnomalyReporter.java b/telephony/java/android/telephony/AnomalyReporter.java
index 9753d8be4065..097041f672ac 100644
--- a/telephony/java/android/telephony/AnomalyReporter.java
+++ b/telephony/java/android/telephony/AnomalyReporter.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.content.Context;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fdf88497db02..6a622378dac7 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -24,12 +26,11 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.os.PersistableBundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.service.carrier.CarrierService;
import android.telecom.TelecomManager;
import android.telephony.ims.ImsReasonInfo;
@@ -3124,7 +3125,6 @@ public class CarrierConfigManager {
* EAP-AKA: "0"
* EAP-SIM: "1"
* EAP-AKA_PRIME: "6"
- * @hide
*/
public static final String ENABLE_EAP_METHOD_PREFIX_BOOL = "enable_eap_method_prefix_bool";
@@ -3399,12 +3399,17 @@ public class CarrierConfigManager {
/** Prefix of all Ims.KEY_* constants. */
public static final String KEY_PREFIX = "ims.";
- //TODO: Add configs related to IMS.
+ /**
+ * Delay in milliseconds to turn off wifi when IMS is registered over wifi.
+ */
+ public static final String KEY_WIFI_OFF_DEFERRING_TIME_INT =
+ KEY_PREFIX + "wifi_off_deferring_time_int";
private Ims() {}
private static PersistableBundle getDefaults() {
PersistableBundle defaults = new PersistableBundle();
+ defaults.putInt(KEY_WIFI_OFF_DEFERRING_TIME_INT, 0);
return defaults;
}
}
@@ -4205,8 +4210,11 @@ public class CarrierConfigManager {
/** @hide */
@Nullable
private ICarrierConfigLoader getICarrierConfigLoader() {
- return ICarrierConfigLoader.Stub
- .asInterface(ServiceManager.getService(Context.CARRIER_CONFIG_SERVICE));
+ return ICarrierConfigLoader.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getCarrierConfigServiceRegisterer()
+ .get());
}
/**
diff --git a/telephony/java/android/telephony/CbGeoUtils.java b/telephony/java/android/telephony/CbGeoUtils.java
index 84be4e8b9ba4..719ba8d98773 100644
--- a/telephony/java/android/telephony/CbGeoUtils.java
+++ b/telephony/java/android/telephony/CbGeoUtils.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.text.TextUtils;
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index ce32dce834db..8e703fee3126 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -191,6 +193,7 @@ public abstract class CellIdentity implements Parcelable {
*
* @hide
*/
+ @SystemApi
public abstract @NonNull CellIdentity sanitizeLocationInfo();
@Override
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 2ecdfce92825..49f425acead6 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -18,7 +18,7 @@ package android.telephony;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 15c91752badf..bc4655069dba 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -18,7 +18,7 @@ package android.telephony;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
import android.telephony.gsm.GsmCellLocation;
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index 2b1387c313ae..acb21f450243 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index 4f7c7a93d19b..79a9d44f36a2 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 6d19261c8932..fed3ebf4af03 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index f1305f5ca768..58ff8c9558d9 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index ee5fec838d2d..33f6a555414c 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -18,7 +18,7 @@ package android.telephony;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import java.util.Objects;
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index 64776e377fa4..11931996009c 100644
--- a/telephony/java/android/telephony/CellLocation.java
+++ b/telephony/java/android/telephony/CellLocation.java
@@ -19,7 +19,6 @@ package android.telephony;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
@@ -38,7 +37,11 @@ public abstract class CellLocation {
*/
public static void requestLocationUpdate() {
try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.getService("phone"));
+ ITelephony phone = ITelephony.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (phone != null) {
phone.updateServiceLocation();
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 199843905854..cab3b0cd3c47 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -20,7 +20,7 @@ import android.annotation.IntRange;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import java.util.Objects;
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index a9f3487a0880..28052aa93486 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.IntRange;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index a6ba9c279ae3..2ef2a52977ff 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.IntRange;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index f31fafe36508..4d67bcf536cf 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.os.Parcel;
@@ -155,7 +157,17 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
* @param ss signal strength from modem.
*/
public CellSignalStrengthNr(android.hardware.radio.V1_4.NrSignalStrength ss) {
- this(ss.csiRsrp, ss.csiRsrq, ss.csiSinr, ss.ssRsrp, ss.ssRsrq, ss.ssSinr);
+ this(flip(ss.csiRsrp), flip(ss.csiRsrq), ss.csiSinr, flip(ss.ssRsrp), flip(ss.ssRsrq),
+ ss.ssSinr);
+ }
+
+ /**
+ * Flip sign cell strength value when taking in the value from hal
+ * @param val cell strength value
+ * @return flipped value
+ */
+ private static int flip(int val) {
+ return val != CellInfo.UNAVAILABLE ? -val : val;
}
/**
diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
index f4a3dbb37988..3bd9d5810136 100644
--- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.os.Parcel;
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index 34b13858f104..535e9520074d 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.IntRange;
import android.annotation.StringDef;
import android.compat.annotation.UnsupportedAppUsage;
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
index 202da6817cb5..a6dedf761636 100644
--- a/telephony/java/android/telephony/NetworkScan.java
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -16,10 +16,10 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.IntDef;
-import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
import com.android.internal.telephony.ITelephony;
@@ -148,6 +148,9 @@ public class NetworkScan {
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
}
}
diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java
index 8c5e10788b89..844289ce75d4 100644
--- a/telephony/java/android/telephony/NetworkService.java
+++ b/telephony/java/android/telephony/NetworkService.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
diff --git a/telephony/java/android/telephony/NetworkServiceCallback.java b/telephony/java/android/telephony/NetworkServiceCallback.java
index 89b96654451e..214ab41ae4f2 100644
--- a/telephony/java/android/telephony/NetworkServiceCallback.java
+++ b/telephony/java/android/telephony/NetworkServiceCallback.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SystemApi;
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 6e86a4211834..2f9e6ac0f9ff 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 8139330cfc59..2c62d0667e19 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -545,7 +547,7 @@ public class ServiceState implements Parcelable {
* @see #STATE_EMERGENCY_ONLY
* @see #STATE_POWER_OFF
*
- * @return current data registration state {@link RegState}
+ * @return current data registration state
*
* @hide
*/
@@ -562,7 +564,7 @@ public class ServiceState implements Parcelable {
* @see #STATE_EMERGENCY_ONLY
* @see #STATE_POWER_OFF
*
- * @return current data registration state {@link RegState}
+ * @return current data registration state
*
* @hide
*/
@@ -2044,4 +2046,27 @@ public class ServiceState implements Parcelable {
public boolean isIwlanPreferred() {
return mIsIwlanPreferred;
}
+ /**
+ * @return {@code true}Returns True whenever the modem is searching for service.
+ * To check both CS and PS domain
+ */
+
+ public boolean isSearching() {
+ NetworkRegistrationInfo psRegState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ if (psRegState != null && psRegState.getRegistrationState()
+ == NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING) {
+ return true;
+ }
+
+ NetworkRegistrationInfo csRegState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ if (csRegState != null && csRegState.getRegistrationState()
+ == NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 3350a3371504..1f7d55f2758a 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index fbe355e5c78b..db33be313941 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -35,7 +35,6 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -745,7 +744,11 @@ public final class SmsManager {
"Invalid pdu format. format must be either 3gpp or 3gpp2");
}
try {
- ISms iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ ISms iSms = ISms.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSmsServiceRegisterer()
+ .get());
if (iSms != null) {
iSms.injectSmsPduForSubscriber(
getSubscriptionId(), pdu, format, receivedIntent);
@@ -1535,7 +1538,10 @@ public final class SmsManager {
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (binder == null) {
throw new RuntimeException("Could not find Telephony Service.");
}
@@ -1573,7 +1579,11 @@ public final class SmsManager {
}
private static ISms getISmsService() {
- return ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ return ISms.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSmsServiceRegisterer()
+ .get());
}
/**
@@ -2007,7 +2017,11 @@ public final class SmsManager {
public boolean isSMSPromptEnabled() {
ISms iSms = null;
try {
- iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ iSms = ISms.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSmsServiceRegisterer()
+ .get());
return iSms.isSMSPromptEnabled();
} catch (RemoteException ex) {
return false;
@@ -2434,14 +2448,18 @@ public final class SmsManager {
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is successfully sent, or failed
* @throws IllegalArgumentException if contentUri is empty
+ * @deprecated use {@link MmsManager#sendMultimediaMessage} instead.
*/
public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
Bundle configOverrides, PendingIntent sentIntent) {
if (contentUri == null) {
throw new IllegalArgumentException("Uri contentUri null");
}
- MmsManager.getInstance().sendMultimediaMessage(getSubscriptionId(), contentUri,
- locationUrl, configOverrides, sentIntent);
+ MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE);
+ if (m != null) {
+ m.sendMultimediaMessage(getSubscriptionId(), contentUri, locationUrl, configOverrides,
+ sentIntent);
+ }
}
/**
@@ -2465,6 +2483,7 @@ public final class SmsManager {
* @param downloadedIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is downloaded, or the download is failed
* @throws IllegalArgumentException if locationUrl or contentUri is empty
+ * @deprecated use {@link MmsManager#downloadMultimediaMessage} instead.
*/
public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
Bundle configOverrides, PendingIntent downloadedIntent) {
@@ -2474,8 +2493,11 @@ public final class SmsManager {
if (contentUri == null) {
throw new IllegalArgumentException("Uri contentUri null");
}
- MmsManager.getInstance().downloadMultimediaMessage(getSubscriptionId(), locationUrl,
- contentUri, configOverrides, downloadedIntent);
+ MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE);
+ if (m != null) {
+ m.downloadMultimediaMessage(getSubscriptionId(), locationUrl, contentUri,
+ configOverrides, downloadedIntent);
+ }
}
// MMS send/download failure result codes
@@ -2517,9 +2539,9 @@ public final class SmsManager {
* </p>
*
* @return the bundle key/values pairs that contains MMS configuration values
+ * or an empty bundle if they cannot be found.
*/
- @Nullable
- public Bundle getCarrierConfigValues() {
+ @NonNull public Bundle getCarrierConfigValues() {
try {
ISms iSms = getISmsService();
if (iSms != null) {
@@ -2528,7 +2550,7 @@ public final class SmsManager {
} catch (RemoteException ex) {
// ignore it
}
- return null;
+ return new Bundle();
}
/**
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index c0bc29d26c6c..c217b8b83c26 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
import android.annotation.Nullable;
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 2c0a1c94dc8d..c24eeb74f6cd 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 22eed6e026af..4510fede4e8e 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
@@ -53,7 +55,6 @@ import android.os.Looper;
import android.os.ParcelUuid;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.provider.Telephony.SimInfo;
import android.telephony.euicc.EuiccManager;
import android.telephony.ims.ImsMmTelManager;
@@ -265,7 +266,7 @@ public class SubscriptionManager {
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+ public static final String UNIQUE_KEY_SUBSCRIPTION_ID = SimInfo.UNIQUE_KEY_SUBSCRIPTION_ID;
/**
* TelephonyProvider column name for a unique identifier for the subscription within the
@@ -274,18 +275,18 @@ public class SubscriptionManager {
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String ICC_ID = "icc_id";
+ public static final String ICC_ID = SimInfo.ICC_ID;
/**
* TelephonyProvider column name for user SIM_SlOT_INDEX
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String SIM_SLOT_INDEX = "sim_id";
+ public static final String SIM_SLOT_INDEX = SimInfo.SIM_SLOT_INDEX;
/** SIM is not inserted */
/** @hide */
- public static final int SIM_NOT_INSERTED = -1;
+ public static final int SIM_NOT_INSERTED = SimInfo.SIM_NOT_INSERTED;
/**
* The slot-index for Bluetooth Remote-SIM subscriptions
@@ -300,23 +301,7 @@ public class SubscriptionManager {
* Default value is 0.
*/
/** @hide */
- public static final String SUBSCRIPTION_TYPE = "subscription_type";
-
- /**
- * TelephonyProvider column name white_listed_apn_data.
- * It's a bitmask of APN types that will be allowed on this subscription even if it's metered
- * and mobile data is turned off by the user.
- * <P>Type: INTEGER (int)</P> For example, if TYPE_MMS is is true, Telephony will allow MMS
- * data connection to setup even if MMS is metered and mobile_data is turned off on that
- * subscription.
- *
- * Default value is 0.
- *
- * @deprecated Replaced by {@link #DATA_ENABLED_OVERRIDE_RULES}
- * @hide
- */
- @Deprecated
- public static final String WHITE_LISTED_APN_DATA = "white_listed_apn_data";
+ public static final String SUBSCRIPTION_TYPE = SimInfo.SUBSCRIPTION_TYPE;
/**
* TelephonyProvider column name data_enabled_override_rules.
@@ -329,7 +314,15 @@ public class SubscriptionManager {
*
* @hide
*/
- public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+ public static final String DATA_ENABLED_OVERRIDE_RULES = SimInfo.DATA_ENABLED_OVERRIDE_RULES;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
+ value = {
+ SUBSCRIPTION_TYPE_LOCAL_SIM,
+ SUBSCRIPTION_TYPE_REMOTE_SIM})
+ public @interface SubscriptionType {}
/**
* This constant is to designate a subscription as a Local-SIM Subscription.
@@ -337,7 +330,7 @@ public class SubscriptionManager {
* device.
* </p>
*/
- public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+ public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = SimInfo.SUBSCRIPTION_TYPE_LOCAL_SIM;
/**
* This constant is to designate a subscription as a Remote-SIM Subscription.
@@ -363,29 +356,21 @@ public class SubscriptionManager {
* was never seen before.
* </p>
*/
- public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
- value = {
- SUBSCRIPTION_TYPE_LOCAL_SIM,
- SUBSCRIPTION_TYPE_REMOTE_SIM})
- public @interface SubscriptionType {}
+ public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = SimInfo.SUBSCRIPTION_TYPE_REMOTE_SIM;
/**
* TelephonyProvider column name for user displayed name.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String DISPLAY_NAME = "display_name";
+ public static final String DISPLAY_NAME = SimInfo.DISPLAY_NAME;
/**
* TelephonyProvider column name for the service provider name for the SIM.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String CARRIER_NAME = "carrier_name";
+ public static final String CARRIER_NAME = SimInfo.CARRIER_NAME;
/**
* Default name resource
@@ -399,44 +384,44 @@ public class SubscriptionManager {
*
* @hide
*/
- public static final String NAME_SOURCE = "name_source";
+ public static final String NAME_SOURCE = SimInfo.NAME_SOURCE;
/**
* The name_source is the default, which is from the carrier id.
* @hide
*/
- public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
+ public static final int NAME_SOURCE_DEFAULT = SimInfo.NAME_SOURCE_DEFAULT;
/**
* The name_source is from SIM EF_SPN.
* @hide
*/
- public static final int NAME_SOURCE_SIM_SPN = 1;
+ public static final int NAME_SOURCE_SIM_SPN = SimInfo.NAME_SOURCE_SIM_SPN;
/**
* The name_source is from user input
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public static final int NAME_SOURCE_USER_INPUT = 2;
+ public static final int NAME_SOURCE_USER_INPUT = SimInfo.NAME_SOURCE_USER_INPUT;
/**
* The name_source is carrier (carrier app, carrier config, etc.)
* @hide
*/
- public static final int NAME_SOURCE_CARRIER = 3;
+ public static final int NAME_SOURCE_CARRIER = SimInfo.NAME_SOURCE_CARRIER;
/**
* The name_source is from SIM EF_PNN.
* @hide
*/
- public static final int NAME_SOURCE_SIM_PNN = 4;
+ public static final int NAME_SOURCE_SIM_PNN = SimInfo.NAME_SOURCE_SIM_PNN;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"NAME_SOURCE_"},
value = {
- NAME_SOURCE_DEFAULT_SOURCE,
+ NAME_SOURCE_DEFAULT,
NAME_SOURCE_SIM_SPN,
NAME_SOURCE_USER_INPUT,
NAME_SOURCE_CARRIER,
@@ -449,67 +434,30 @@ public class SubscriptionManager {
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String COLOR = "color";
-
- /** @hide */
- public static final int COLOR_1 = 0;
-
- /** @hide */
- public static final int COLOR_2 = 1;
-
- /** @hide */
- public static final int COLOR_3 = 2;
-
- /** @hide */
- public static final int COLOR_4 = 3;
-
- /** @hide */
- public static final int COLOR_DEFAULT = COLOR_1;
+ public static final String COLOR = SimInfo.COLOR;
/**
* TelephonyProvider column name for the phone number of a SIM.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String NUMBER = "number";
+ public static final String NUMBER = SimInfo.NUMBER;
/**
- * TelephonyProvider column name for the number display format of a SIM.
+ * TelephonyProvider column name for whether data roaming is enabled.
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
-
- /** @hide */
- public static final int DISPLAY_NUMBER_NONE = 0;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_FIRST = 1;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_LAST = 2;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
-
- /**
- * TelephonyProvider column name for permission for data roaming of a SIM.
- * <P>Type: INTEGER (int)</P>
- */
- /** @hide */
- public static final String DATA_ROAMING = "data_roaming";
+ public static final String DATA_ROAMING = SimInfo.DATA_ROAMING;
/** Indicates that data roaming is enabled for a subscription */
- public static final int DATA_ROAMING_ENABLE = 1;
+ public static final int DATA_ROAMING_ENABLE = SimInfo.DATA_ROAMING_ENABLE;
/** Indicates that data roaming is disabled for a subscription */
- public static final int DATA_ROAMING_DISABLE = 0;
-
- /** @hide */
- public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+ public static final int DATA_ROAMING_DISABLE = SimInfo.DATA_ROAMING_DISABLE;
/** @hide */
- public static final int SIM_PROVISIONED = 0;
+ public static final int DATA_ROAMING_DEFAULT = SimInfo.DATA_ROAMING_DEFAULT;
/**
* TelephonyProvider column name for subscription carrier id.
@@ -517,61 +465,61 @@ public class SubscriptionManager {
* <p>Type: INTEGER (int) </p>
* @hide
*/
- public static final String CARRIER_ID = "carrier_id";
+ public static final String CARRIER_ID = SimInfo.CARRIER_ID;
/**
* @hide A comma-separated list of EHPLMNs associated with the subscription
* <P>Type: TEXT (String)</P>
*/
- public static final String EHPLMNS = "ehplmns";
+ public static final String EHPLMNS = SimInfo.EHPLMNS;
/**
* @hide A comma-separated list of HPLMNs associated with the subscription
* <P>Type: TEXT (String)</P>
*/
- public static final String HPLMNS = "hplmns";
+ public static final String HPLMNS = SimInfo.HPLMNS;
/**
* TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String MCC_STRING = "mcc_string";
+ public static final String MCC_STRING = SimInfo.MCC_STRING;
/**
* TelephonyProvider column name for the MNC associated with a SIM, stored as a string.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String MNC_STRING = "mnc_string";
+ public static final String MNC_STRING = SimInfo.MNC_STRING;
/**
* TelephonyProvider column name for the MCC associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String MCC = "mcc";
+ public static final String MCC = SimInfo.MCC;
/**
* TelephonyProvider column name for the MNC associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String MNC = "mnc";
+ public static final String MNC = SimInfo.MNC;
/**
* TelephonyProvider column name for the iso country code associated with a SIM.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String ISO_COUNTRY_CODE = "iso_country_code";
+ public static final String ISO_COUNTRY_CODE = SimInfo.ISO_COUNTRY_CODE;
/**
* TelephonyProvider column name for the sim provisioning status associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
+ public static final String SIM_PROVISIONING_STATUS = SimInfo.SIM_PROVISIONING_STATUS;
/**
* TelephonyProvider column name for whether a subscription is embedded (that is, present on an
@@ -579,7 +527,7 @@ public class SubscriptionManager {
* <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
* @hide
*/
- public static final String IS_EMBEDDED = "is_embedded";
+ public static final String IS_EMBEDDED = SimInfo.IS_EMBEDDED;
/**
* TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of the
@@ -587,7 +535,7 @@ public class SubscriptionManager {
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String CARD_ID = "card_id";
+ public static final String CARD_ID = SimInfo.CARD_ID;
/**
* TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
@@ -595,7 +543,7 @@ public class SubscriptionManager {
* <p>TYPE: BLOB
* @hide
*/
- public static final String ACCESS_RULES = "access_rules";
+ public static final String ACCESS_RULES = SimInfo.ACCESS_RULES;
/**
* TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
@@ -605,7 +553,7 @@ public class SubscriptionManager {
* @hide
*/
public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
- "access_rules_from_carrier_configs";
+ SimInfo.ACCESS_RULES_FROM_CARRIER_CONFIGS;
/**
* TelephonyProvider column name identifying whether an embedded subscription is on a removable
@@ -615,79 +563,79 @@ public class SubscriptionManager {
* <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
* @hide
*/
- public static final String IS_REMOVABLE = "is_removable";
+ public static final String IS_REMOVABLE = SimInfo.IS_REMOVABLE;
/**
* TelephonyProvider column name for extreme threat in CB settings
* @hide
*/
- public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+ public static final String CB_EXTREME_THREAT_ALERT = SimInfo.CB_EXTREME_THREAT_ALERT;
/**
* TelephonyProvider column name for severe threat in CB settings
*@hide
*/
- public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+ public static final String CB_SEVERE_THREAT_ALERT = SimInfo.CB_SEVERE_THREAT_ALERT;
/**
* TelephonyProvider column name for amber alert in CB settings
*@hide
*/
- public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+ public static final String CB_AMBER_ALERT = SimInfo.CB_AMBER_ALERT;
/**
* TelephonyProvider column name for emergency alert in CB settings
*@hide
*/
- public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+ public static final String CB_EMERGENCY_ALERT = SimInfo.CB_EMERGENCY_ALERT;
/**
* TelephonyProvider column name for alert sound duration in CB settings
*@hide
*/
- public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+ public static final String CB_ALERT_SOUND_DURATION = SimInfo.CB_ALERT_SOUND_DURATION;
/**
* TelephonyProvider column name for alert reminder interval in CB settings
*@hide
*/
- public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+ public static final String CB_ALERT_REMINDER_INTERVAL = SimInfo.CB_ALERT_REMINDER_INTERVAL;
/**
* TelephonyProvider column name for enabling vibrate in CB settings
*@hide
*/
- public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+ public static final String CB_ALERT_VIBRATE = SimInfo.CB_ALERT_VIBRATE;
/**
* TelephonyProvider column name for enabling alert speech in CB settings
*@hide
*/
- public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+ public static final String CB_ALERT_SPEECH = SimInfo.CB_ALERT_SPEECH;
/**
* TelephonyProvider column name for ETWS test alert in CB settings
*@hide
*/
- public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+ public static final String CB_ETWS_TEST_ALERT = SimInfo.CB_ETWS_TEST_ALERT;
/**
* TelephonyProvider column name for enable channel50 alert in CB settings
*@hide
*/
- public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+ public static final String CB_CHANNEL_50_ALERT = SimInfo.CB_CHANNEL_50_ALERT;
/**
* TelephonyProvider column name for CMAS test alert in CB settings
*@hide
*/
- public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
+ public static final String CB_CMAS_TEST_ALERT = SimInfo.CB_CMAS_TEST_ALERT;
/**
* TelephonyProvider column name for Opt out dialog in CB settings
*@hide
*/
- public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+ public static final String CB_OPT_OUT_DIALOG = SimInfo.CB_OPT_OUT_DIALOG;
/**
* TelephonyProvider column name for enable Volte.
@@ -696,37 +644,37 @@ public class SubscriptionManager {
* {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
*@hide
*/
- public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+ public static final String ENHANCED_4G_MODE_ENABLED = SimInfo.ENHANCED_4G_MODE_ENABLED;
/**
* TelephonyProvider column name for enable VT (Video Telephony over IMS)
*@hide
*/
- public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+ public static final String VT_IMS_ENABLED = SimInfo.VT_IMS_ENABLED;
/**
* TelephonyProvider column name for enable Wifi calling
*@hide
*/
- public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+ public static final String WFC_IMS_ENABLED = SimInfo.WFC_IMS_ENABLED;
/**
* TelephonyProvider column name for Wifi calling mode
*@hide
*/
- public static final String WFC_IMS_MODE = "wfc_ims_mode";
+ public static final String WFC_IMS_MODE = SimInfo.WFC_IMS_MODE;
/**
* TelephonyProvider column name for Wifi calling mode in roaming
*@hide
*/
- public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+ public static final String WFC_IMS_ROAMING_MODE = SimInfo.WFC_IMS_ROAMING_MODE;
/**
* TelephonyProvider column name for enable Wifi calling in roaming
*@hide
*/
- public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+ public static final String WFC_IMS_ROAMING_ENABLED = SimInfo.WFC_IMS_ROAMING_ENABLED;
/**
* TelephonyProvider column name for whether a subscription is opportunistic, that is,
@@ -735,7 +683,7 @@ public class SubscriptionManager {
* <p>Type: INTEGER (int), 1 for opportunistic or 0 for non-opportunistic.
* @hide
*/
- public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+ public static final String IS_OPPORTUNISTIC = SimInfo.IS_OPPORTUNISTIC;
/**
* TelephonyProvider column name for group ID. Subscriptions with same group ID
@@ -744,7 +692,7 @@ public class SubscriptionManager {
*
* @hide
*/
- public static final String GROUP_UUID = "group_uuid";
+ public static final String GROUP_UUID = SimInfo.GROUP_UUID;
/**
* TelephonyProvider column name for group owner. It's the package name who created
@@ -752,14 +700,7 @@ public class SubscriptionManager {
*
* @hide
*/
- public static final String GROUP_OWNER = "group_owner";
-
- /**
- * TelephonyProvider column name for whether a subscription is metered or not, that is, whether
- * the network it connects to charges for subscription or not. For example, paid CBRS or unpaid.
- * @hide
- */
- public static final String IS_METERED = "is_metered";
+ public static final String GROUP_OWNER = SimInfo.GROUP_OWNER;
/**
* TelephonyProvider column name for the profile class of a subscription
@@ -767,7 +708,7 @@ public class SubscriptionManager {
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String PROFILE_CLASS = "profile_class";
+ public static final String PROFILE_CLASS = SimInfo.PROFILE_CLASS;
/**
* Profile class of the subscription
@@ -775,11 +716,11 @@ public class SubscriptionManager {
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "PROFILE_CLASS_" }, value = {
- PROFILE_CLASS_TESTING,
- PROFILE_CLASS_PROVISIONING,
- PROFILE_CLASS_OPERATIONAL,
- PROFILE_CLASS_UNSET,
- PROFILE_CLASS_DEFAULT
+ SimInfo.PROFILE_CLASS_TESTING,
+ SimInfo.PROFILE_CLASS_PROVISIONING,
+ SimInfo.PROFILE_CLASS_OPERATIONAL,
+ SimInfo.PROFILE_CLASS_UNSET,
+ SimInfo.PROFILE_CLASS_DEFAULT
})
public @interface ProfileClass {}
@@ -791,7 +732,7 @@ public class SubscriptionManager {
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_TESTING = 0;
+ public static final int PROFILE_CLASS_TESTING = SimInfo.PROFILE_CLASS_TESTING;
/**
* A provisioning profile is pre-loaded onto the eUICC and
@@ -800,7 +741,7 @@ public class SubscriptionManager {
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_PROVISIONING = 1;
+ public static final int PROFILE_CLASS_PROVISIONING = SimInfo.PROFILE_CLASS_PROVISIONING;
/**
* An operational profile can be pre-loaded or downloaded
@@ -809,7 +750,7 @@ public class SubscriptionManager {
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_OPERATIONAL = 2;
+ public static final int PROFILE_CLASS_OPERATIONAL = SimInfo.PROFILE_CLASS_OPERATIONAL;
/**
* The profile class is unset. This occurs when profile class
@@ -818,14 +759,14 @@ public class SubscriptionManager {
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_UNSET = -1;
+ public static final int PROFILE_CLASS_UNSET = SimInfo.PROFILE_CLASS_UNSET;
/**
* Default profile class
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+ public static final int PROFILE_CLASS_DEFAULT = SimInfo.PROFILE_CLASS_DEFAULT;
/**
* IMSI (International Mobile Subscriber Identity).
@@ -833,13 +774,13 @@ public class SubscriptionManager {
* @hide
*/
//TODO: add @SystemApi
- public static final String IMSI = "imsi";
+ public static final String IMSI = SimInfo.IMSI;
/**
* Whether uicc applications is set to be enabled or disabled. By default it's enabled.
* @hide
*/
- public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+ public static final String UICC_APPLICATIONS_ENABLED = SimInfo.UICC_APPLICATIONS_ENABLED;
/**
* Broadcast Action: The user has changed one of the default subs related to
@@ -1023,8 +964,11 @@ public class SubscriptionManager {
private final INetworkPolicyManager getNetworkPolicy() {
if (mNetworkPolicy == null) {
- mNetworkPolicy = INetworkPolicyManager.Stub
- .asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+ mNetworkPolicy = INetworkPolicyManager.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getNetworkPolicyServiceRegisterer()
+ .get());
}
return mNetworkPolicy;
}
@@ -1041,6 +985,23 @@ public class SubscriptionManager {
*/
public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
if (listener == null) return;
+ addOnSubscriptionsChangedListener(listener.mExecutor, listener);
+ }
+
+ /**
+ * Register for changes to the list of active {@link SubscriptionInfo} records or to the
+ * individual records themselves. When a change occurs the onSubscriptionsChanged method of
+ * the listener will be invoked immediately if there has been a notification. The
+ * onSubscriptionChanged method will also be triggered once initially when calling this
+ * function.
+ *
+ * @param listener an instance of {@link OnSubscriptionsChangedListener} with
+ * onSubscriptionsChanged overridden.
+ * @param executor the executor that will execute callbacks.
+ */
+ public void addOnSubscriptionsChangedListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnSubscriptionsChangedListener listener) {
String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
if (DBG) {
logd("register OnSubscriptionsChangedListener pkgName=" + pkgName
@@ -1052,7 +1013,7 @@ public class SubscriptionManager {
mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
if (telephonyRegistryManager != null) {
telephonyRegistryManager.addOnSubscriptionsChangedListener(listener,
- listener.mExecutor);
+ executor);
}
}
@@ -1185,7 +1146,11 @@ public class SubscriptionManager {
SubscriptionInfo subInfo = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1219,7 +1184,11 @@ public class SubscriptionManager {
SubscriptionInfo result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1253,7 +1222,11 @@ public class SubscriptionManager {
SubscriptionInfo result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex,
mContext.getOpPackageName(), mContext.getFeatureId());
@@ -1277,7 +1250,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAllSubInfoList(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1358,7 +1335,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> activeList = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1409,7 +1390,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1448,7 +1433,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAccessibleSubscriptionInfoList(mContext.getOpPackageName());
}
@@ -1477,7 +1466,11 @@ public class SubscriptionManager {
public void requestEmbeddedSubscriptionInfoListRefresh() {
int cardId = TelephonyManager.from(mContext).getCardIdForDefaultEuicc();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId);
}
@@ -1506,7 +1499,11 @@ public class SubscriptionManager {
@SystemApi
public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId);
}
@@ -1527,7 +1524,11 @@ public class SubscriptionManager {
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAllSubInfoCount(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1556,7 +1557,11 @@ public class SubscriptionManager {
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubInfoCount(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1577,7 +1582,11 @@ public class SubscriptionManager {
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubInfoCountMax();
}
@@ -1634,7 +1643,11 @@ public class SubscriptionManager {
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub == null) {
Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- ISub service is null");
return;
@@ -1668,7 +1681,11 @@ public class SubscriptionManager {
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub == null) {
Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null");
return;
@@ -1771,7 +1788,11 @@ public class SubscriptionManager {
int result = INVALID_SIM_SLOT_INDEX;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getSlotIndex(subscriptionId);
}
@@ -1805,7 +1826,11 @@ public class SubscriptionManager {
int[] subId = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getSubId(slotIndex);
}
@@ -1829,7 +1854,11 @@ public class SubscriptionManager {
int result = INVALID_PHONE_INDEX;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getPhoneId(subId);
}
@@ -1863,7 +1892,11 @@ public class SubscriptionManager {
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultSubId();
}
@@ -1886,7 +1919,11 @@ public class SubscriptionManager {
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultVoiceSubId();
}
@@ -1916,7 +1953,11 @@ public class SubscriptionManager {
public void setDefaultVoiceSubscriptionId(int subscriptionId) {
if (VDBG) logd("setDefaultVoiceSubId sub id = " + subscriptionId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setDefaultVoiceSubId(subscriptionId);
}
@@ -1964,7 +2005,11 @@ public class SubscriptionManager {
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultSmsSubId();
}
@@ -1990,7 +2035,11 @@ public class SubscriptionManager {
public void setDefaultSmsSubId(int subscriptionId) {
if (VDBG) logd("setDefaultSmsSubId sub id = " + subscriptionId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setDefaultSmsSubId(subscriptionId);
}
@@ -2028,7 +2077,11 @@ public class SubscriptionManager {
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultDataSubId();
}
@@ -2054,7 +2107,11 @@ public class SubscriptionManager {
public void setDefaultDataSubId(int subscriptionId) {
if (VDBG) logd("setDataSubscription sub id = " + subscriptionId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setDefaultDataSubId(subscriptionId);
}
@@ -2085,7 +2142,11 @@ public class SubscriptionManager {
/** @hide */
public void clearSubscriptionInfo() {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.clearSubInfo();
}
@@ -2221,7 +2282,11 @@ public class SubscriptionManager {
*/
public @NonNull int[] getActiveSubscriptionIdList(boolean visibleOnly) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
int[] subId = iSub.getActiveSubIdList(visibleOnly);
if (subId != null) return subId;
@@ -2272,7 +2337,11 @@ public class SubscriptionManager {
int simState = TelephonyManager.SIM_STATE_UNKNOWN;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
simState = iSub.getSimStateForSlotIndex(slotIndex);
}
@@ -2291,7 +2360,11 @@ public class SubscriptionManager {
*/
public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setSubscriptionProperty(subId, propKey, propValue);
}
@@ -2311,7 +2384,11 @@ public class SubscriptionManager {
Context context) {
String resultValue = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
resultValue = iSub.getSubscriptionProperty(subId, propKey,
context.getOpPackageName(), context.getFeatureId());
@@ -2453,7 +2530,11 @@ public class SubscriptionManager {
@UnsupportedAppUsage
public boolean isActiveSubId(int subId) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.isActiveSubId(subId, mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -2756,7 +2837,11 @@ public class SubscriptionManager {
@TelephonyManager.SetOpportunisticSubscriptionResult Consumer<Integer> callback) {
if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub == null) return;
ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@@ -2799,7 +2884,11 @@ public class SubscriptionManager {
public int getPreferredDataSubscriptionId() {
int preferredSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
preferredSubId = iSub.getPreferredDataSubscriptionId();
}
@@ -2830,7 +2919,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> subInfoList = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subInfoList = iSub.getOpportunisticSubscriptions(contextPkg, contextFeature);
}
@@ -2931,7 +3024,11 @@ public class SubscriptionManager {
ParcelUuid groupUuid = null;
int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
groupUuid = iSub.createSubscriptionGroup(subIdArray, pkgForDebug);
} else {
@@ -2981,7 +3078,11 @@ public class SubscriptionManager {
int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.addSubscriptionsIntoGroup(subIdArray, groupUuid, pkgForDebug);
} else {
@@ -3033,7 +3134,11 @@ public class SubscriptionManager {
int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, pkgForDebug);
} else {
@@ -3078,7 +3183,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg, contextFeature);
} else {
@@ -3191,7 +3300,11 @@ public class SubscriptionManager {
logd("setSubscriptionActivated subId= " + subscriptionId + " enable " + enable);
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.setSubscriptionEnabled(enable, subscriptionId);
}
@@ -3221,7 +3334,11 @@ public class SubscriptionManager {
logd("setUiccApplicationsEnabled subId= " + subscriptionId + " enable " + enabled);
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setUiccApplicationsEnabled(enabled, subscriptionId);
}
@@ -3251,7 +3368,11 @@ public class SubscriptionManager {
logd("canDisablePhysicalSubscription");
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.canDisablePhysicalSubscription();
}
@@ -3272,7 +3393,11 @@ public class SubscriptionManager {
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isSubscriptionEnabled(int subscriptionId) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.isSubscriptionEnabled(subscriptionId);
}
@@ -3295,7 +3420,11 @@ public class SubscriptionManager {
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getEnabledSubscriptionId(slotIndex);
}
@@ -3321,7 +3450,11 @@ public class SubscriptionManager {
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = helper.callMethod(iSub);
}
@@ -3344,7 +3477,11 @@ public class SubscriptionManager {
*/
public static int getActiveDataSubscriptionId() {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.getActiveDataSubscriptionId();
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index df8c26da7af9..843c0656efc3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -60,7 +60,6 @@ import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.WorkSource;
import android.provider.Settings.SettingNotFoundException;
@@ -107,6 +106,7 @@ import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.SmsApplication;
+import com.android.telephony.Rlog;
import dalvik.system.VMRuntime;
@@ -785,30 +785,6 @@ public class TelephonyManager {
public static final String EXTRA_PRECISE_DISCONNECT_CAUSE = "precise_disconnect_cause";
/**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an String containing the data APN type.
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getStringExtra(String name)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_APN_TYPE = PhoneConstants.DATA_APN_TYPE_KEY;
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an String containing the data APN.
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getStringExtra(String name)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_APN = PhoneConstants.DATA_APN_KEY;
-
- /**
* Broadcast intent action for letting the default dialer to know to show voicemail
* notification.
*
@@ -5107,7 +5083,11 @@ public class TelephonyManager {
@UnsupportedAppUsage
private IPhoneSubInfo getSubscriberInfo() {
// get it each time because that process crashes a lot
- return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
+ return IPhoneSubInfo.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getPhoneSubServiceRegisterer()
+ .get());
}
/**
@@ -5320,11 +5300,19 @@ public class TelephonyManager {
}
private ITelephonyRegistry getTelephonyRegistry() {
- return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
+ return ITelephonyRegistry.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyRegistryServiceRegisterer()
+ .get());
}
private IOns getIOns() {
- return IOns.Stub.asInterface(ServiceManager.getService("ions"));
+ return IOns.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getOpportunisticNetworkServiceRegisterer()
+ .get());
}
//
@@ -5880,7 +5868,10 @@ public class TelephonyManager {
* @param AID Application id. See ETSI 102.221 and 101.220.
* @param p2 P2 parameter (described in ISO 7816-4).
* @return an IccOpenLogicalChannelResponse object.
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID, int p2) {
return iccOpenLogicalChannel(getSubId(), AID, p2);
}
@@ -5911,7 +5902,10 @@ public class TelephonyManager {
* @param p2 P2 parameter (described in ISO 7816-4).
* @return an IccOpenLogicalChannelResponse object.
* @hide
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID, int p2) {
try {
ITelephony telephony = getITelephony();
@@ -5939,7 +5933,10 @@ public class TelephonyManager {
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
* @hide
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) {
@@ -5966,7 +5963,10 @@ public class TelephonyManager {
* @param channel is the channel id to be closed as returned by a successful
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public boolean iccCloseLogicalChannel(int channel) {
return iccCloseLogicalChannel(getSubId(), channel);
}
@@ -5985,7 +5985,10 @@ public class TelephonyManager {
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
* @hide
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public boolean iccCloseLogicalChannel(int subId, int channel) {
try {
ITelephony telephony = getITelephony();
@@ -6021,7 +6024,10 @@ public class TelephonyManager {
* @return The APDU response from the ICC card with the status appended at the end, or null if
* there is an issue connecting to the Telephony service.
* @hide
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
@Nullable
@@ -6059,7 +6065,10 @@ public class TelephonyManager {
* @param data Data to be sent with the APDU.
* @return The APDU response from the ICC card with the status appended at
* the end.
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public String iccTransmitApduLogicalChannel(int channel, int cla,
int instruction, int p1, int p2, int p3, String data) {
return iccTransmitApduLogicalChannel(getSubId(), channel, cla,
@@ -6088,7 +6097,10 @@ public class TelephonyManager {
* @return The APDU response from the ICC card with the status appended at
* the end.
* @hide
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public String iccTransmitApduLogicalChannel(int subId, int channel, int cla,
int instruction, int p1, int p2, int p3, String data) {
try {
@@ -6124,7 +6136,10 @@ public class TelephonyManager {
* @return The APDU response from the ICC card with the status appended at
* the end.
* @hide
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
@NonNull
@@ -6160,7 +6175,10 @@ public class TelephonyManager {
* @param data Data to be sent with the APDU.
* @return The APDU response from the ICC card with the status appended at
* the end.
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public String iccTransmitApduBasicChannel(int cla,
int instruction, int p1, int p2, int p3, String data) {
return iccTransmitApduBasicChannel(getSubId(), cla,
@@ -6187,7 +6205,10 @@ public class TelephonyManager {
* @return The APDU response from the ICC card with the status appended at
* the end.
* @hide
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public String iccTransmitApduBasicChannel(int subId, int cla,
int instruction, int p1, int p2, int p3, String data) {
try {
@@ -6215,7 +6236,10 @@ public class TelephonyManager {
* @param p3 P3 value of the APDU command.
* @param filePath
* @return The APDU response.
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
String filePath) {
return iccExchangeSimIO(getSubId(), fileID, command, p1, p2, p3, filePath);
@@ -6237,7 +6261,10 @@ public class TelephonyManager {
* @param filePath
* @return The APDU response.
* @hide
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2,
int p3, String filePath) {
try {
@@ -6263,7 +6290,10 @@ public class TelephonyManager {
* @return The APDU response from the ICC card in hexadecimal format
* with the last 4 bytes being the status word. If the command fails,
* returns an empty string.
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public String sendEnvelopeWithStatus(String content) {
return sendEnvelopeWithStatus(getSubId(), content);
}
@@ -6283,7 +6313,10 @@ public class TelephonyManager {
* with the last 4 bytes being the status word. If the command fails,
* returns an empty string.
* @hide
+ * @deprecated Use {@link android.se.omapi.SEService} APIs instead.
*/
+ // TODO(b/147153909): Update Javadoc to link to specific SEService API once integrated.
+ @Deprecated
public String sendEnvelopeWithStatus(int subId, String content) {
try {
ITelephony telephony = getITelephony();
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 96b6db75b370..a1d40e85fb10 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -16,10 +16,11 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.Nullable;
-import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -29,7 +30,6 @@ import android.os.Message;
import android.os.Messenger;
import android.os.Parcelable;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.util.SparseArray;
import com.android.internal.telephony.ITelephony;
@@ -234,6 +234,9 @@ public final class TelephonyScanManager {
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
}
}
diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java
index 93ccba1dd996..81a09c645070 100644
--- a/telephony/java/android/telephony/UiccAccessRule.java
+++ b/telephony/java/android/telephony/UiccAccessRule.java
@@ -15,6 +15,8 @@
*/
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
diff --git a/telephony/java/android/telephony/VoLteServiceState.java b/telephony/java/android/telephony/VoLteServiceState.java
index 414b9995fd58..121401277ce9 100644
--- a/telephony/java/android/telephony/VoLteServiceState.java
+++ b/telephony/java/android/telephony/VoLteServiceState.java
@@ -16,6 +16,8 @@
package android.telephony;
+import com.android.telephony.Rlog;
+
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Bundle;
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index dbfb6a2a0f2e..fab1bf2215af 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -28,7 +28,7 @@ import android.provider.Telephony;
import android.provider.Telephony.Carriers;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.NetworkType;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 372bdf1c0f81..bff12b624ae8 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -31,7 +31,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.AccessNetworkConstants;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index 11dc78a611ff..d33d3f9a5eee 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -22,7 +22,7 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.LinkProperties;
import android.os.RemoteException;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.data.DataService.DataServiceProvider;
import java.lang.annotation.Retention;
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index e793979a61c9..8220b16500de 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -28,7 +28,7 @@ import android.os.Message;
import android.os.RemoteException;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.Annotation.ApnType;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 16662652847d..cd3fc953f9d2 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -25,7 +25,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 994c49cd2315..e16fffa69f8a 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -21,8 +21,8 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.service.euicc.EuiccProfileInfo;
+import android.telephony.TelephonyFrameworkInitializer;
import android.util.Log;
import com.android.internal.telephony.euicc.IAuthenticateServerCallback;
@@ -148,7 +148,10 @@ public class EuiccCardManager {
private IEuiccCardController getIEuiccCardController() {
return IEuiccCardController.Stub.asInterface(
- ServiceManager.getService("euicc_card_controller"));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getEuiccCardControllerServiceRegisterer()
+ .get());
}
/**
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index cb66a9650f2f..d5a48df149f1 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -30,7 +30,7 @@ import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccCardManager.ResetOption;
@@ -968,6 +968,10 @@ public class EuiccManager {
}
private static IEuiccController getIEuiccController() {
- return IEuiccController.Stub.asInterface(ServiceManager.getService("econtroller"));
+ return IEuiccController.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getEuiccControllerService()
+ .get());
}
}
diff --git a/telephony/java/android/telephony/ims/ImsConferenceState.java b/telephony/java/android/telephony/ims/ImsConferenceState.java
index 8d2049b97138..abfee61930ed 100644
--- a/telephony/java/android/telephony/ims/ImsConferenceState.java
+++ b/telephony/java/android/telephony/ims/ImsConferenceState.java
@@ -24,7 +24,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.telecom.Call;
import android.telecom.Connection;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.util.Log;
import java.util.HashMap;
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index dcb9c9d5ec27..136a83e2eec9 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -24,7 +24,7 @@ import android.annotation.TestApi;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 057d22cd7eae..91514e9ebe28 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -25,14 +25,13 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MmTelFeature;
@@ -1018,7 +1017,10 @@ public class ImsMmTelManager implements RegistrationManager {
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (binder == null) {
throw new RuntimeException("Could not find Telephony Service.");
}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index d3fb37f005cd..c96271432ea2 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -26,8 +26,8 @@ import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.AccessNetworkConstants;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.feature.ImsFeature;
@@ -35,6 +35,8 @@ import android.telephony.ims.feature.RcsFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
+import com.android.internal.telephony.IIntegerConsumer;
+
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -158,9 +160,20 @@ public class ImsRcsManager implements RegistrationManager {
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
+
+ IImsRcsController imsRcsController = getIImsRcsController();
+ if (imsRcsController == null) {
+ Log.e(TAG, "Register registration callback: IImsRcsController is null");
+ throw new ImsException("Cannot find remote IMS service",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
c.setExecutor(executor);
- throw new UnsupportedOperationException("registerImsRegistrationCallback is not"
- + "supported.");
+ try {
+ imsRcsController.registerImsRegistrationCallback(mSubId, c.getBinder());
+ } catch (RemoteException | IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**{@inheritDoc}*/
@@ -171,8 +184,18 @@ public class ImsRcsManager implements RegistrationManager {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
- throw new UnsupportedOperationException("unregisterImsRegistrationCallback is not"
- + "supported.");
+
+ IImsRcsController imsRcsController = getIImsRcsController();
+ if (imsRcsController == null) {
+ Log.e(TAG, "Unregister registration callback: IImsRcsController is null");
+ throw new IllegalStateException("Cannot find remote IMS service");
+ }
+
+ try {
+ imsRcsController.unregisterImsRegistrationCallback(mSubId, c.getBinder());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
}
/**{@inheritDoc}*/
@@ -186,8 +209,23 @@ public class ImsRcsManager implements RegistrationManager {
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
- throw new UnsupportedOperationException("getRegistrationState is not"
- + "supported.");
+
+ IImsRcsController imsRcsController = getIImsRcsController();
+ if (imsRcsController == null) {
+ Log.e(TAG, "Get registration state error: IImsRcsController is null");
+ throw new IllegalStateException("Cannot find remote IMS service");
+ }
+
+ try {
+ imsRcsController.getImsRcsRegistrationState(mSubId, new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> stateCallback.accept(result));
+ }
+ });
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
}
/**{@inheritDoc}*/
@@ -202,10 +240,25 @@ public class ImsRcsManager implements RegistrationManager {
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
- throw new UnsupportedOperationException("getRegistrationTransportType is not"
- + "supported.");
- }
+ IImsRcsController imsRcsController = getIImsRcsController();
+ if (imsRcsController == null) {
+ Log.e(TAG, "Get registration transport type error: IImsRcsController is null");
+ throw new IllegalStateException("Cannot find remote IMS service");
+ }
+
+ try {
+ imsRcsController.getImsRcsRegistrationTransportType(mSubId,
+ new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> transportTypeCallback.accept(result));
+ }
+ });
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
/**
* Registers an {@link AvailabilityCallback} with the system, which will provide RCS
@@ -362,7 +415,10 @@ public class ImsRcsManager implements RegistrationManager {
}
private IImsRcsController getIImsRcsController() {
- IBinder binder = ServiceManager.getService(Context.TELEPHONY_IMS_SERVICE);
+ IBinder binder = TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyImsServiceRegisterer()
+ .get();
return IImsRcsController.Stub.asInterface(binder);
}
}
diff --git a/telephony/java/android/telephony/ims/ImsSsData.java b/telephony/java/android/telephony/ims/ImsSsData.java
index 6b728599c7d3..2d2e63812fad 100644
--- a/telephony/java/android/telephony/ims/ImsSsData.java
+++ b/telephony/java/android/telephony/ims/ImsSsData.java
@@ -22,7 +22,7 @@ import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index e4d63355625d..f0521802a167 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -25,14 +25,13 @@ import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
-import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsConfigCallback;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsConfigImplBase;
@@ -415,7 +414,11 @@ public class ProvisioningManager {
}
private static boolean isImsAvailableOnDevice() {
- IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ IPackageManager pm = IPackageManager.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getPackageManagerServiceRegisterer()
+ .get());
if (pm == null) {
// For some reason package manger is not available.. This will fail internally anyways,
// so do not throw error and allow.
@@ -432,7 +435,10 @@ public class ProvisioningManager {
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (binder == null) {
throw new RuntimeException("Could not find Telephony Service.");
}
diff --git a/telephony/java/android/telephony/ims/RcsControllerCall.java b/telephony/java/android/telephony/ims/RcsControllerCall.java
index ce03c3c799bb..1e93437a5a94 100644
--- a/telephony/java/android/telephony/ims/RcsControllerCall.java
+++ b/telephony/java/android/telephony/ims/RcsControllerCall.java
@@ -18,7 +18,7 @@ package android.telephony.ims;
import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IRcsMessage;
/**
@@ -35,8 +35,11 @@ class RcsControllerCall {
}
<R> R call(RcsServiceCall<R> serviceCall) throws RcsMessageStoreException {
- IRcsMessage iRcsMessage = IRcsMessage.Stub.asInterface(ServiceManager.getService(
- Context.TELEPHONY_RCS_MESSAGE_SERVICE));
+ IRcsMessage iRcsMessage = IRcsMessage.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyRcsMessageServiceRegisterer()
+ .get());
if (iRcsMessage == null) {
throw new RcsMessageStoreException("Could not connect to RCS storage service");
}
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 75e3f0a6393d..2e3f59a13670 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -21,12 +21,11 @@ import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
-import android.content.Context;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
import android.util.Log;
@@ -365,7 +364,10 @@ public class RcsUceAdapter {
}
private IImsRcsController getIImsRcsController() {
- IBinder binder = ServiceManager.getService(Context.TELEPHONY_IMS_SERVICE);
+ IBinder binder = TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyImsServiceRegisterer()
+ .get();
return IImsRcsController.Stub.asInterface(binder);
}
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index e81bac0f6764..6f6aa44371fa 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -19,6 +19,9 @@ package android.telephony.ims.aidl;
import android.net.Uri;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
+
+import com.android.internal.telephony.IIntegerConsumer;
/**
* Interface used to interact with the Telephony IMS.
@@ -26,6 +29,13 @@ import android.telephony.ims.aidl.IRcsUceControllerCallback;
* {@hide}
*/
interface IImsRcsController {
+ // IMS RCS registration commands
+ void registerImsRegistrationCallback(int subId, IImsRegistrationCallback c);
+ void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c);
+ void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer);
+ void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer);
+
+ // IMS RCS capability commands
void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback c);
void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback c);
boolean isCapable(int subId, int capability, int radioTech);
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index cfc803ca3639..9116a3bf3bde 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -19,7 +19,7 @@ package com.android.ims;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.aidl.IImsConfig;
diff --git a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
index 1d6ec2d82eb7..8e86ff788a08 100644
--- a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
+++ b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
@@ -19,7 +19,7 @@ package com.android.internal.telephony;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.util.SparseIntArray;
import com.android.internal.telephony.cdma.sms.UserData;
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index e75c5933f1df..832502cae37d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -20,7 +20,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
import android.sysprop.TelephonyProperties;
import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.SmsCbLocation;
import android.telephony.SmsCbMessage;
import android.telephony.cdma.CdmaSmsCbProgramData;
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 b5af6467a0ad..cbf0f5c297e1 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -18,7 +18,7 @@ package com.android.internal.telephony.cdma.sms;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.SmsCbCmasInfo;
import android.telephony.cdma.CdmaSmsCbProgramData;
import android.telephony.cdma.CdmaSmsCbProgramResults;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 0681dc11066e..417aafd765ea 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -28,7 +28,7 @@ import static com.android.internal.telephony.SmsConstants.MessageClass;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.text.TextUtils;
import com.android.internal.telephony.EncodeException;
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index eed9a86cf448..0dc740194034 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -21,7 +21,7 @@ import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.Color;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.GsmAlphabet;
diff --git a/telephony/java/com/android/telephony/Rlog.java b/telephony/java/com/android/telephony/Rlog.java
new file mode 100644
index 000000000000..9d6c930de8f5
--- /dev/null
+++ b/telephony/java/com/android/telephony/Rlog.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.telephony;
+
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+
+import com.android.internal.telephony.util.TelephonyUtils;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * A copy of {@link android.telephony.Rlog} to be used within the telephony mainline module.
+ *
+ * @hide
+ */
+public final class Rlog {
+
+ private static final boolean USER_BUILD = TelephonyUtils.IS_USER;
+
+ private Rlog() {
+ }
+
+ private static int log(int priority, String tag, String msg) {
+ return Log.logToRadioBuffer(priority, tag, msg);
+ }
+
+ public static int v(String tag, String msg) {
+ return log(Log.VERBOSE, tag, msg);
+ }
+
+ public static int v(String tag, String msg, Throwable tr) {
+ return log(Log.VERBOSE, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int d(String tag, String msg) {
+ return log(Log.DEBUG, tag, msg);
+ }
+
+ public static int d(String tag, String msg, Throwable tr) {
+ return log(Log.DEBUG, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int i(String tag, String msg) {
+ return log(Log.INFO, tag, msg);
+ }
+
+ public static int i(String tag, String msg, Throwable tr) {
+ return log(Log.INFO, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int w(String tag, String msg) {
+ return log(Log.WARN, tag, msg);
+ }
+
+ public static int w(String tag, String msg, Throwable tr) {
+ return log(Log.WARN, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int w(String tag, Throwable tr) {
+ return log(Log.WARN, tag, Log.getStackTraceString(tr));
+ }
+
+ public static int e(String tag, String msg) {
+ return log(Log.ERROR, tag, msg);
+ }
+
+ public static int e(String tag, String msg, Throwable tr) {
+ return log(Log.ERROR, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int println(int priority, String tag, String msg) {
+ return log(priority, tag, msg);
+ }
+
+ public static boolean isLoggable(String tag, int level) {
+ return Log.isLoggable(tag, level);
+ }
+
+ /**
+ * Redact personally identifiable information for production users.
+ * @param tag used to identify the source of a log message
+ * @param pii the personally identifiable information we want to apply secure hash on.
+ * @return If tag is loggable in verbose mode or pii is null, return the original input.
+ * otherwise return a secure Hash of input pii
+ */
+ public static String pii(String tag, Object pii) {
+ String val = String.valueOf(pii);
+ if (pii == null || TextUtils.isEmpty(val) || isLoggable(tag, Log.VERBOSE)) {
+ return val;
+ }
+ return "[" + secureHash(val.getBytes()) + "]";
+ }
+
+ /**
+ * Redact personally identifiable information for production users.
+ * @param enablePiiLogging set when caller explicitly want to enable sensitive logging.
+ * @param pii the personally identifiable information we want to apply secure hash on.
+ * @return If enablePiiLogging is set to true or pii is null, return the original input.
+ * otherwise return a secure Hash of input pii
+ */
+ public static String pii(boolean enablePiiLogging, Object pii) {
+ String val = String.valueOf(pii);
+ if (pii == null || TextUtils.isEmpty(val) || enablePiiLogging) {
+ return val;
+ }
+ return "[" + secureHash(val.getBytes()) + "]";
+ }
+
+ /**
+ * Returns a secure hash (using the SHA1 algorithm) of the provided input.
+ *
+ * @return "****" if the build type is user, otherwise the hash
+ * @param input the bytes for which the secure hash should be computed.
+ */
+ private static String secureHash(byte[] input) {
+ // Refrain from logging user personal information in user build.
+ if (USER_BUILD) {
+ return "****";
+ }
+
+ MessageDigest messageDigest;
+
+ try {
+ messageDigest = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ return "####";
+ }
+
+ byte[] result = messageDigest.digest(input);
+ return Base64.encodeToString(
+ result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
+ }
+}
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
index 653282d0d365..1361df30e9d7 100644
--- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
@@ -320,8 +320,9 @@ public class MemoryUsageTest extends InstrumentationTestCase {
UserHandle.USER_CURRENT);
}
- mAtm.startActivityAndWait(null, null, mLaunchIntent, mimeType,
- null, null, 0, mLaunchIntent.getFlags(), null, null,
+ mAtm.startActivityAndWait(null,
+ getInstrumentation().getContext().getBasePackageName(), mLaunchIntent,
+ mimeType, null, null, 0, mLaunchIntent.getFlags(), null, null,
UserHandle.USER_CURRENT_OR_SELF);
} catch (RemoteException e) {
Log.w(TAG, "Error launching app", e);
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index b4cafe41662e..656628eb39d5 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -896,39 +896,78 @@ public class PackageWatchdogTest {
assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A);
}
- /** Test that observers execute correctly for different failure reasons */
+ /** Test that observers execute correctly for failures reasons that go through thresholding. */
@Test
- public void testFailureReasons() {
+ public void testNonImmediateFailureReasons() {
PackageWatchdog watchdog = createWatchdog();
TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
- TestObserver observer3 = new TestObserver(OBSERVER_NAME_3);
- TestObserver observer4 = new TestObserver(OBSERVER_NAME_4);
watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
watchdog.startObservingHealth(observer2, Arrays.asList(APP_B), SHORT_DURATION);
- watchdog.startObservingHealth(observer3, Arrays.asList(APP_C), SHORT_DURATION);
- watchdog.startObservingHealth(observer4, Arrays.asList(APP_D), SHORT_DURATION);
raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
- VERSION_CODE)), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
- raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_B,
- VERSION_CODE)), PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
- raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_C,
VERSION_CODE)), PackageWatchdog.FAILURE_REASON_APP_CRASH);
- raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_D,
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_B,
VERSION_CODE)), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
assertThat(observer1.getLastFailureReason()).isEqualTo(
- PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
- assertThat(observer2.getLastFailureReason()).isEqualTo(
- PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
- assertThat(observer3.getLastFailureReason()).isEqualTo(
PackageWatchdog.FAILURE_REASON_APP_CRASH);
- assertThat(observer4.getLastFailureReason()).isEqualTo(
+ assertThat(observer2.getLastFailureReason()).isEqualTo(
PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
}
+ /** Test that observers execute correctly for failures reasons that skip thresholding. */
+ @Test
+ public void testImmediateFailures() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_B,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
+
+ assertThat(observer1.mMitigatedPackages).containsExactly(APP_A, APP_B);
+ }
+
+ /**
+ * Test that a persistent observer will mitigate failures if it wishes to observe a package.
+ */
+ @Test
+ public void testPersistentObserverWatchesPackage() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver persistentObserver = new TestObserver(OBSERVER_NAME_1);
+ persistentObserver.setPersistent(true);
+ persistentObserver.setMayObservePackages(true);
+
+ watchdog.startObservingHealth(persistentObserver, Arrays.asList(APP_B), SHORT_DURATION);
+
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+ assertThat(persistentObserver.mHealthCheckFailedPackages).containsExactly(APP_A);
+ }
+
+ /**
+ * Test that a persistent observer will not mitigate failures if it does not wish to observe
+ * a given package.
+ */
+ @Test
+ public void testPersistentObserverDoesNotWatchPackage() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver persistentObserver = new TestObserver(OBSERVER_NAME_1);
+ persistentObserver.setPersistent(true);
+ persistentObserver.setMayObservePackages(false);
+
+ watchdog.startObservingHealth(persistentObserver, Arrays.asList(APP_B), SHORT_DURATION);
+
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+ assertThat(persistentObserver.mHealthCheckFailedPackages).isEmpty();
+ }
+
private void adoptShellPermissions(String... permissions) {
InstrumentationRegistry
.getInstrumentation()
@@ -964,7 +1003,12 @@ public class PackageWatchdogTest {
/** Trigger package failures above the threshold. */
private void raiseFatalFailureAndDispatch(PackageWatchdog watchdog,
List<VersionedPackage> packages, int failureReason) {
- for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
+ long triggerFailureCount = watchdog.getTriggerFailureCount();
+ if (failureReason == PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK
+ || failureReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
+ triggerFailureCount = 1;
+ }
+ for (int i = 0; i < triggerFailureCount; i++) {
watchdog.onPackageFailure(packages, failureReason);
}
mTestLooper.dispatchAll();
@@ -1000,6 +1044,8 @@ public class PackageWatchdogTest {
private final String mName;
private int mImpact;
private int mLastFailureReason;
+ private boolean mIsPersistent = false;
+ private boolean mMayObservePackages = false;
final List<String> mHealthCheckFailedPackages = new ArrayList<>();
final List<String> mMitigatedPackages = new ArrayList<>();
@@ -1028,9 +1074,25 @@ public class PackageWatchdogTest {
return mName;
}
+ public boolean isPersistent() {
+ return mIsPersistent;
+ }
+
+ public boolean mayObservePackage(String packageName) {
+ return mMayObservePackages;
+ }
+
public int getLastFailureReason() {
return mLastFailureReason;
}
+
+ public void setPersistent(boolean persistent) {
+ mIsPersistent = persistent;
+ }
+
+ public void setMayObservePackages(boolean mayObservePackages) {
+ mMayObservePackages = mayObservePackages;
+ }
}
private static class TestController extends ExplicitHealthCheckController {
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 40169b8cdcd3..9e490f765eab 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -324,6 +324,7 @@ public class StagedRollbackTest {
@Test
public void testNetworkPassedDoesNotRollback_Phase1() throws Exception {
+ // Remove available rollbacks and uninstall NetworkStack on /data/
RollbackManager rm = RollbackUtils.getRollbackManager();
String networkStack = getNetworkStackPackageName();
@@ -332,6 +333,15 @@ public class StagedRollbackTest {
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
networkStack)).isNull();
+
+ // Reduce health check deadline, here unlike the network failed case, we use
+ // a longer deadline because joining a network can take a much longer time for
+ // reasons external to the device than 'not joining'
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS,
+ Integer.toString(300000), false);
+ // Simulate re-installation of new NetworkStack with rollbacks enabled
+ installNetworkStackPackage();
}
@Test
@@ -343,6 +353,9 @@ public class StagedRollbackTest {
@Test
public void testNetworkPassedDoesNotRollback_Phase3() throws Exception {
+ // Sleep for > health check deadline. We expect no rollback should happen during sleeping.
+ // If the device reboots for rollback, this device test will fail as well as the host test.
+ Thread.sleep(TimeUnit.SECONDS.toMillis(310));
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
getNetworkStackPackageName())).isNull();
@@ -380,11 +393,6 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackWhitelistedApp_cleanUp() throws Exception {
- RollbackUtils.getRollbackManager().expireRollbackForPackage(getModuleMetadataPackageName());
- }
-
- @Test
public void testRollbackDataPolicy_Phase1() throws Exception {
Uninstall.packages(TestApp.A, TestApp.B);
Install.multi(TestApp.A1, TestApp.B1).commit();
@@ -422,6 +430,16 @@ public class StagedRollbackTest {
assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
}
+ @Test
+ public void testCleanUp() throws Exception {
+ // testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
+ // committed on a device which doesn't support checkpoint. Let's clean up all rollbacks
+ // so there is only one rollback to commit when testing native crashes.
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ }
+
private static void runShellCommand(String cmd) {
ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
.executeShellCommand(cmd);
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 4644d8aee306..91577c202df9 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -22,8 +22,8 @@ import static org.testng.Assert.assertThrows;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,6 +53,11 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
getDevice().reboot();
}
+ @After
+ public void tearDown() throws Exception {
+ runPhase("testCleanUp");
+ }
+
/**
* Tests watchdog triggered staged rollbacks involving only apks.
*/
@@ -128,21 +133,8 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
* Tests passed network health check does not trigger watchdog staged rollbacks.
*/
@Test
- @Ignore("b/143514090")
public void testNetworkPassedDoesNotRollback() throws Exception {
- // Remove available rollbacks and uninstall NetworkStack on /data/
runPhase("testNetworkPassedDoesNotRollback_Phase1");
- // Reduce health check deadline, here unlike the network failed case, we use
- // a longer deadline because joining a network can take a much longer time for
- // reasons external to the device than 'not joining'
- getDevice().executeShellCommand("device_config put rollback "
- + "watchdog_request_timeout_millis 300000");
- // Simulate re-installation of new NetworkStack with rollbacks enabled
- getDevice().executeShellCommand("pm install -r --staged --enable-rollback "
- + getNetworkStackPath());
-
- // Sleep to allow writes to disk before reboot
- Thread.sleep(5000);
// Reboot device to activate staged package
getDevice().reboot();
@@ -157,8 +149,6 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
// on mobile data
getDevice().waitForDeviceAvailable();
- // Sleep for > health check deadline
- Thread.sleep(310000);
// Verify rollback was not executed after health check deadline
runPhase("testNetworkPassedDoesNotRollback_Phase3");
}
@@ -180,16 +170,9 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
*/
@Test
public void testRollbackWhitelistedApp() throws Exception {
- try {
- runPhase("testRollbackWhitelistedApp_Phase1");
- getDevice().reboot();
- runPhase("testRollbackWhitelistedApp_Phase2");
- } finally {
- // testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
- // committed on a device which doesn't support checkpoint. Let's clean up the rollback
- // so there is only one rollback to commit when testing native crashes.
- runPhase("testRollbackWhitelistedApp_cleanUp");
- }
+ runPhase("testRollbackWhitelistedApp_Phase1");
+ getDevice().reboot();
+ runPhase("testRollbackWhitelistedApp_Phase2");
}
@Test
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index c16a0f446651..33d77d288e15 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -64,15 +64,15 @@ public class NetworkStatsTest {
@Test
public void testFindIndex() throws Exception {
final NetworkStats stats = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12);
assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES,
@@ -94,21 +94,21 @@ public class NetworkStatsTest {
@Test
public void testFindIndexHinted() {
final NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 1024L, 8L, 0L, 0L, 10)
- .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11)
- .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12)
- .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ .addEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12);
// verify that we correctly find across regardless of hinting
@@ -143,27 +143,27 @@ public class NetworkStatsTest {
assertEquals(0, stats.size());
assertEquals(4, stats.internalSize());
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5);
assertEquals(4, stats.size());
assertEquals(4, stats.internalSize());
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11);
assertEquals(9, stats.size());
@@ -193,8 +193,8 @@ public class NetworkStatsTest {
public void testCombineExisting() throws Exception {
final NetworkStats stats = new NetworkStats(TEST_START, 10);
- stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10);
- stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2);
+ stats.addEntry(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10);
+ stats.addEntry(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2);
stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L,
-128L, -1L, -1);
@@ -215,12 +215,12 @@ public class NetworkStatsTest {
@Test
public void testSubtractIdenticalData() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
final NetworkStats after = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
final NetworkStats result = after.subtract(before);
@@ -234,12 +234,12 @@ public class NetworkStatsTest {
@Test
public void testSubtractIdenticalRows() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
final NetworkStats after = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20);
final NetworkStats result = after.subtract(before);
@@ -253,13 +253,13 @@ public class NetworkStatsTest {
@Test
public void testSubtractNewRows() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
final NetworkStats after = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12)
+ .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20);
final NetworkStats result = after.subtract(before);
@@ -275,11 +275,11 @@ public class NetworkStatsTest {
@Test
public void testSubtractMissingRows() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0)
- .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0);
+ .addEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0)
+ .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0);
final NetworkStats after = new NetworkStats(TEST_START, 1)
- .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0);
+ .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0);
final NetworkStats result = after.subtract(before);
@@ -293,40 +293,40 @@ public class NetworkStatsTest {
@Test
public void testTotalBytes() throws Exception {
final NetworkStats iface = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L);
+ .addEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L);
assertEquals(384L, iface.getTotalBytes());
final NetworkStats uidSet = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
assertEquals(96L, uidSet.getTotalBytes());
final NetworkStats uidTag = new NetworkStats(TEST_START, 6)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L);
assertEquals(64L, uidTag.getTotalBytes());
final NetworkStats uidMetered = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
assertEquals(96L, uidMetered.getTotalBytes());
final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
assertEquals(96L, uidRoaming.getTotalBytes());
}
@@ -343,11 +343,11 @@ public class NetworkStatsTest {
@Test
public void testGroupedByIfaceAll() throws Exception {
final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
- .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_NO, 128L, 8L, 0L, 2L, 20L)
- .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES,
+ .addEntry(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L);
final NetworkStats grouped = uidStats.groupedByIface();
@@ -361,19 +361,19 @@ public class NetworkStatsTest {
@Test
public void testGroupedByIface() throws Exception {
final NetworkStats uidStats = new NetworkStats(TEST_START, 7)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L);
final NetworkStats grouped = uidStats.groupedByIface();
@@ -390,19 +390,19 @@ public class NetworkStatsTest {
@Test
public void testAddAllValues() {
final NetworkStats first = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
+ .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
final NetworkStats second = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
+ .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
first.combineAllValues(second);
@@ -421,19 +421,19 @@ public class NetworkStatsTest {
@Test
public void testGetTotal() {
final NetworkStats stats = new NetworkStats(TEST_START, 7)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 512L,32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L);
assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L);
@@ -459,7 +459,7 @@ public class NetworkStatsTest {
assertEquals(0, after.size());
// Test 1 item stats.
- before.addValues(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L);
+ before.addEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L);
after = before.clone();
after.removeUids(new int[0]);
assertEquals(1, after.size());
@@ -469,12 +469,12 @@ public class NetworkStatsTest {
assertEquals(0, after.size());
// Append remaining test items.
- before.addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L);
+ before.addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L);
assertEquals(7, before.size());
// Test remove with empty uid list.
@@ -505,12 +505,12 @@ public class NetworkStatsTest {
@Test
public void testClone() throws Exception {
final NetworkStats original = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
// make clone and mutate original
final NetworkStats clone = original.clone();
- original.addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L);
+ original.addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L);
assertEquals(3, original.size());
assertEquals(2, clone.size());
@@ -523,8 +523,8 @@ public class NetworkStatsTest {
public void testAddWhenEmpty() throws Exception {
final NetworkStats red = new NetworkStats(TEST_START, -1);
final NetworkStats blue = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
// We're mostly checking that we don't crash
red.combineAllValues(blue);
@@ -537,39 +537,39 @@ public class NetworkStatsTest {
final String underlyingIface = "wlan0";
final int testTag1 = 8888;
NetworkStats delta = new NetworkStats(TEST_START, 17)
- .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L)
- .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L)
- .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L)
- // VPN package also uses some traffic through unprotected network.
- .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L)
- .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- // Tag entries
- .addValues(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L)
- .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L)
- // Irrelevant entries
- .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L)
- // Underlying Iface entries
- .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L)
- .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */,
- 299L /* smaller than sum(tun0) */, 0L)
- .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
-
- delta.migrateTun(tunUid, tunIface, new String[] {underlyingIface});
+ .addEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L)
+ .addEntry(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
+ .addEntry(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L)
+ .addEntry(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L)
+ // VPN package also uses some traffic through unprotected network.
+ .addEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L)
+ .addEntry(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
+ // Tag entries
+ .addEntry(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L)
+ .addEntry(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L)
+ // Irrelevant entries
+ .addEntry(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L)
+ // Underlying Iface entries
+ .addEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L)
+ .addEntry(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
+ .addEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */,
+ 299L /* smaller than sum(tun0) */, 0L)
+ .addEntry(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
+
+ delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface});
assertEquals(20, delta.size());
// tunIface and TEST_IFACE entries are not changed.
@@ -634,21 +634,21 @@ public class NetworkStatsTest {
final String tunIface = "tun0";
final String underlyingIface = "wlan0";
NetworkStats delta = new NetworkStats(TEST_START, 9)
- // 2 different apps sent/receive data via tun0.
- .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L)
- .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L)
- // VPN package resends data through the tunnel (with exaggerated overhead)
- .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L)
- // 1 app already has some traffic on the underlying interface, the other doesn't yet
- .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L)
- // Traffic through the underlying interface via the vpn app.
- // This test should redistribute this data correctly.
- .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L);
+ // 2 different apps sent/receive data via tun0.
+ .addEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L)
+ .addEntry(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L)
+ // VPN package resends data through the tunnel (with exaggerated overhead)
+ .addEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L)
+ // 1 app already has some traffic on the underlying interface, the other doesn't yet
+ .addEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L)
+ // Traffic through the underlying interface via the vpn app.
+ // This test should redistribute this data correctly.
+ .addEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L);
delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface});
assertEquals(9, delta.size());
@@ -697,9 +697,9 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3);
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3);
stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL);
assertEquals(3, stats.size());
@@ -724,9 +724,9 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3);
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3);
stats.filter(testUid, INTERFACES_ALL, TAG_ALL);
assertEquals(2, stats.size());
@@ -755,10 +755,10 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 4)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3)
- .addValues(entry4);
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3)
+ .addEntry(entry4);
stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL);
assertEquals(3, stats.size());
@@ -778,8 +778,8 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(entry1)
- .addValues(entry2);
+ .addEntry(entry1)
+ .addEntry(entry2);
stats.filter(UID_ALL, new String[] { }, TAG_ALL);
assertEquals(0, stats.size());
@@ -802,9 +802,9 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3);
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3);
stats.filter(UID_ALL, INTERFACES_ALL, testTag);
assertEquals(2, stats.size());
@@ -831,10 +831,10 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 4)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3)
- .addValues(entry4);
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3)
+ .addEntry(entry4);
stats.filterDebugEntries();
@@ -891,14 +891,14 @@ public class NetworkStatsTest {
0 /* operations */);
final NetworkStats statsXt = new NetworkStats(TEST_START, 3)
- .addValues(appEntry)
- .addValues(xtRootUidEntry)
- .addValues(otherEntry);
+ .addEntry(appEntry)
+ .addEntry(xtRootUidEntry)
+ .addEntry(otherEntry);
final NetworkStats statsEbpf = new NetworkStats(TEST_START, 3)
- .addValues(appEntry)
- .addValues(ebpfRootUidEntry)
- .addValues(otherEntry);
+ .addEntry(appEntry)
+ .addEntry(ebpfRootUidEntry)
+ .addEntry(otherEntry);
statsXt.apply464xlatAdjustments(stackedIface, false);
statsEbpf.apply464xlatAdjustments(stackedIface, true);
@@ -945,8 +945,8 @@ public class NetworkStatsTest {
0 /* operations */);
NetworkStats stats = new NetworkStats(TEST_START, 2)
- .addValues(firstEntry)
- .addValues(secondEntry);
+ .addEntry(firstEntry)
+ .addEntry(secondEntry);
// Empty map: no adjustment
stats.apply464xlatAdjustments(new ArrayMap<>(), false);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
index c0f9dc14869f..f0e5774a5dea 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -326,14 +326,14 @@ public class NetworkStatsObserversTest {
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
@@ -359,14 +359,14 @@ public class NetworkStatsObserversTest {
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
@@ -391,14 +391,14 @@ public class NetworkStatsObserversTest {
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
@@ -424,14 +424,14 @@ public class NetworkStatsObserversTest {
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
+ .addEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
+ .addEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 4d42a612030d..6de068e48a38 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -298,11 +298,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1024L, 8L, 2048L, 16L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
mService.setUidForeground(UID_RED, false);
mService.incrementOperationCount(UID_RED, 0xFAAD, 4);
mService.setUidForeground(UID_RED, true);
@@ -407,9 +407,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 10);
forcePollAndWaitForIdle();
@@ -429,9 +429,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
forcePollAndWaitForIdle();
@@ -443,10 +443,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2176L, 17L, 1536L, 12L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L));
mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10);
forcePollAndWaitForIdle();
@@ -480,10 +480,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
- .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
+ .addEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
mService.incrementOperationCount(UID_RED, 0xFAAD, 10);
forcePollAndWaitForIdle();
@@ -501,10 +501,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
- .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
+ .addEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
final Intent intent = new Intent(ACTION_UID_REMOVED);
intent.putExtra(EXTRA_UID, UID_BLUE);
mServiceContext.sendBroadcast(intent);
@@ -536,8 +536,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 5);
forcePollAndWaitForIdle();
@@ -552,8 +552,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
forcePollAndWaitForIdle();
@@ -564,10 +564,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
+ .addEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L));
mService.incrementOperationCount(UID_RED, 0xFAAD, 5);
forcePollAndWaitForIdle();
@@ -591,9 +591,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
forcePollAndWaitForIdle();
@@ -608,9 +608,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L));
forcePollAndWaitForIdle();
// first verify entire history present
@@ -654,9 +654,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3));
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3));
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL);
@@ -704,11 +704,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
.thenReturn(augmentedIfaceFilter);
when(mStatsFactory.readNetworkStatsDetail(eq(UID_ALL), any(), eq(TAG_ALL)))
.thenReturn(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(uidStats));
+ .addEntry(uidStats));
when(mNetManager.getNetworkStatsTethering(STATS_PER_UID))
.thenReturn(new NetworkStats(getElapsedRealtime(), 2)
- .addValues(tetheredStats1)
- .addValues(tetheredStats2));
+ .addEntry(tetheredStats1)
+ .addEntry(tetheredStats2));
NetworkStats stats = mService.getDetailedUidStats(ifaceFilter);
@@ -745,8 +745,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
forcePollAndWaitForIdle();
@@ -760,10 +760,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L));
mService.setUidForeground(UID_RED, true);
mService.incrementOperationCount(UID_RED, 0xFAAD, 1);
@@ -804,9 +804,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// and DEFAULT_NETWORK_YES, because these three properties aren't tracked at that layer.
// We layer them on top by inspecting the iface properties.
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
@@ -843,9 +843,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it
// on top by inspecting the iface properties.
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO,
DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L));
forcePollAndWaitForIdle();
@@ -885,10 +885,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// Traffic for UID_RED.
final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
// All tethering traffic, both hardware and software.
final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L,
+ .addEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L,
0L);
expectNetworkStatsSummary(ifaceStats, tetherStatsHardware);
diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp
index f71be7b0b7d3..a6625ab9c17f 100644
--- a/tests/utils/testutils/Android.bp
+++ b/tests/utils/testutils/Android.bp
@@ -22,6 +22,7 @@ java_library {
static_libs: [
"junit",
"hamcrest-library",
+ "androidx.test.runner",
],
libs: [
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java b/tests/utils/testutils/java/com/android/server/accessibility/test/MessageCapturingHandler.java
index e2b517f875db..bce2ab5c5a7f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java
+++ b/tests/utils/testutils/java/com/android/server/accessibility/test/MessageCapturingHandler.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.accessibility;
+package com.android.server.accessibility.test;
import android.os.Handler;
import android.os.Looper;
@@ -31,7 +31,7 @@ import java.util.List;
* at their target.
*/
public class MessageCapturingHandler extends Handler {
- List<Pair<Message, Long>> timedMessages = new ArrayList<>();
+ public List<Pair<Message, Long>> timedMessages = new ArrayList<>();
Handler.Callback mCallback;
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index 7f0872c02613..7fa47f696b50 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -85,8 +85,9 @@ static int write_java_methods(
string indent("");
if (supportQ) {
// TODO(b/146235828): Use just SDK_INT check once it is incremented from Q.
- fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q ||\n");
- fprintf(out, " Build.VERSION.CODENAME.equals(\"R\")) {\n");
+ fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n");
+ fprintf(out, " || (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q\n");
+ fprintf(out, " && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n");
indent = " ";
}
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 634f6746d815..180368cbd9f7 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -67,10 +67,15 @@ java_library {
optimize: {
enabled: false
},
+ hostdex: true, // for hiddenapi check
visibility: [
"//frameworks/base", // TODO(b/140299412) remove once all dependencies are fixed
"//frameworks/opt/net/wifi/service:__subpackages__",
] + test_access_hidden_api_whitelist,
+ apex_available: [
+ "com.android.wifi",
+ "test_com.android.wifi",
+ ],
plugins: ["java_api_finder"],
}
@@ -106,8 +111,10 @@ java_defaults {
name: "framework-wifi-test-defaults",
sdk_version: "core_platform", // tests can use @CorePlatformApi's
libs: [
+ // order matters: classes in framework-wifi are resolved before framework, meaning
+ // @hide APIs in framework-wifi are resolved before @SystemApi stubs in framework
"framework-wifi",
- "framework-minus-apex",
+ "framework",
// if sdk_version="" this gets automatically included, but here we need to add manually.
"framework-res",
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1678d5a4776b..f490766559de 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -90,6 +90,8 @@ interface IWifiManager
void allowAutojoin(int netId, boolean choice);
+ void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin);
+
boolean startScan(String packageName, String featureId);
List<ScanResult> getScanResults(String callingPackage, String callingFeatureId);
@@ -248,4 +250,6 @@ interface IWifiManager
void unregisterSuggestionConnectionStatusListener(int listenerIdentifier, String packageName);
int calculateSignalLevel(int rssi);
+
+ List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(in List<ScanResult> scanResults);
}
diff --git a/wifi/java/android/net/wifi/SoftApCapability.java b/wifi/java/android/net/wifi/SoftApCapability.java
index c4474e2bc9cc..2bbe7d2aa4ec 100644
--- a/wifi/java/android/net/wifi/SoftApCapability.java
+++ b/wifi/java/android/net/wifi/SoftApCapability.java
@@ -61,11 +61,20 @@ public final class SoftApCapability implements Parcelable {
*/
public static final int SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 1 << 1;
+
+ /**
+ * Support for WPA3 Simultaneous Authentication of Equals (WPA3-SAE).
+ *
+ * flag when {@link config_wifi_softap_sae_supported)} is true.
+ */
+ public static final int SOFTAP_FEATURE_WPA3_SAE = 1 << 2;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "SOFTAP_FEATURE_" }, value = {
SOFTAP_FEATURE_ACS_OFFLOAD,
SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT,
+ SOFTAP_FEATURE_WPA3_SAE,
})
public @interface HotspotFeatures {}
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 05e245b8eabc..2b7f8af728d7 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -25,6 +25,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
@@ -55,6 +56,11 @@ import java.util.concurrent.Executor;
@SystemApi
public final class SoftApConfiguration implements Parcelable {
+ @VisibleForTesting
+ static final int PSK_MIN_LEN = 8;
+ @VisibleForTesting
+ static final int PSK_MAX_LEN = 63;
+
/**
* 2GHz band.
* @hide
@@ -142,9 +148,10 @@ public final class SoftApConfiguration implements Parcelable {
private final @Nullable MacAddress mBssid;
/**
- * Pre-shared key for WPA2-PSK encryption (non-null enables WPA2-PSK).
+ * Pre-shared key for WPA2-PSK or WPA3-SAE-Transition or WPA3-SAE encryption which depends on
+ * the security type.
*/
- private final @Nullable String mWpa2Passphrase;
+ private final @Nullable String mPassphrase;
/**
* This is a network that does not broadcast its SSID, so an
@@ -175,6 +182,12 @@ public final class SoftApConfiguration implements Parcelable {
private final @SecurityType int mSecurityType;
/**
+ * Delay in milliseconds before shutting down soft AP when
+ * there are no connected devices.
+ */
+ private final int mShutdownTimeoutMillis;
+
+ /**
* Security types we support.
*/
/** @hide */
@@ -186,25 +199,36 @@ public final class SoftApConfiguration implements Parcelable {
public static final int SECURITY_TYPE_WPA2_PSK = 1;
/** @hide */
+ @SystemApi
+ public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2;
+
+ /** @hide */
+ @SystemApi
+ public static final int SECURITY_TYPE_WPA3_SAE = 3;
+
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "SECURITY_TYPE" }, value = {
+ @IntDef(prefix = { "SECURITY_TYPE_" }, value = {
SECURITY_TYPE_OPEN,
SECURITY_TYPE_WPA2_PSK,
+ SECURITY_TYPE_WPA3_SAE_TRANSITION,
+ SECURITY_TYPE_WPA3_SAE,
})
public @interface SecurityType {}
/** Private constructor for Builder and Parcelable implementation. */
private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
- @Nullable String wpa2Passphrase, boolean hiddenSsid, @BandType int band, int channel,
- @SecurityType int securityType, int maxNumberOfClients) {
+ @Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel,
+ @SecurityType int securityType, int maxNumberOfClients, int shutdownTimeoutMillis) {
mSsid = ssid;
mBssid = bssid;
- mWpa2Passphrase = wpa2Passphrase;
+ mPassphrase = passphrase;
mHiddenSsid = hiddenSsid;
mBand = band;
mChannel = channel;
mSecurityType = securityType;
mMaxNumberOfClients = maxNumberOfClients;
+ mShutdownTimeoutMillis = shutdownTimeoutMillis;
}
@Override
@@ -218,18 +242,19 @@ public final class SoftApConfiguration implements Parcelable {
SoftApConfiguration other = (SoftApConfiguration) otherObj;
return Objects.equals(mSsid, other.mSsid)
&& Objects.equals(mBssid, other.mBssid)
- && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase)
+ && Objects.equals(mPassphrase, other.mPassphrase)
&& mHiddenSsid == other.mHiddenSsid
&& mBand == other.mBand
&& mChannel == other.mChannel
&& mSecurityType == other.mSecurityType
- && mMaxNumberOfClients == other.mMaxNumberOfClients;
+ && mMaxNumberOfClients == other.mMaxNumberOfClients
+ && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis;
}
@Override
public int hashCode() {
- return Objects.hash(mSsid, mBssid, mWpa2Passphrase, mHiddenSsid,
- mBand, mChannel, mSecurityType, mMaxNumberOfClients);
+ return Objects.hash(mSsid, mBssid, mPassphrase, mHiddenSsid,
+ mBand, mChannel, mSecurityType, mMaxNumberOfClients, mShutdownTimeoutMillis);
}
@Override
@@ -237,13 +262,14 @@ public final class SoftApConfiguration implements Parcelable {
StringBuilder sbuf = new StringBuilder();
sbuf.append("ssid=").append(mSsid);
if (mBssid != null) sbuf.append(" \n bssid=").append(mBssid.toString());
- sbuf.append(" \n Wpa2Passphrase =").append(
- TextUtils.isEmpty(mWpa2Passphrase) ? "<empty>" : "<non-empty>");
+ sbuf.append(" \n Passphrase =").append(
+ TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>");
sbuf.append(" \n HiddenSsid =").append(mHiddenSsid);
sbuf.append(" \n Band =").append(mBand);
sbuf.append(" \n Channel =").append(mChannel);
sbuf.append(" \n SecurityType=").append(getSecurityType());
sbuf.append(" \n MaxClient=").append(mMaxNumberOfClients);
+ sbuf.append(" \n ShutdownTimeoutMillis=").append(mShutdownTimeoutMillis);
return sbuf.toString();
}
@@ -251,12 +277,13 @@ public final class SoftApConfiguration implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mSsid);
dest.writeParcelable(mBssid, flags);
- dest.writeString(mWpa2Passphrase);
+ dest.writeString(mPassphrase);
dest.writeBoolean(mHiddenSsid);
dest.writeInt(mBand);
dest.writeInt(mChannel);
dest.writeInt(mSecurityType);
dest.writeInt(mMaxNumberOfClients);
+ dest.writeInt(mShutdownTimeoutMillis);
}
@Override
@@ -272,7 +299,7 @@ public final class SoftApConfiguration implements Parcelable {
in.readString(),
in.readParcelable(MacAddress.class.getClassLoader()),
in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt(),
- in.readInt());
+ in.readInt(), in.readInt());
}
@Override
@@ -300,12 +327,12 @@ public final class SoftApConfiguration implements Parcelable {
}
/**
- * Returns String set to be passphrase for the WPA2-PSK AP.
- * {@link Builder#setWpa2Passphrase(String)}.
+ * Returns String set to be passphrase for current AP.
+ * {@link #setPassphrase(String, @SecurityType int)}.
*/
@Nullable
- public String getWpa2Passphrase() {
- return mWpa2Passphrase;
+ public String getPassphrase() {
+ return mPassphrase;
}
/**
@@ -351,6 +378,15 @@ public final class SoftApConfiguration implements Parcelable {
}
/**
+ * Returns the shutdown timeout in milliseconds.
+ * The Soft AP will shutdown when there are no devices associated to it for
+ * the timeout duration. See {@link Builder#setShutdownTimeoutMillis(int)}.
+ */
+ public int getShutdownTimeoutMillis() {
+ return mShutdownTimeoutMillis;
+ }
+
+ /**
* Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a
* Soft AP.
*
@@ -360,23 +396,13 @@ public final class SoftApConfiguration implements Parcelable {
public static final class Builder {
private String mSsid;
private MacAddress mBssid;
- private String mWpa2Passphrase;
+ private String mPassphrase;
private boolean mHiddenSsid;
private int mBand;
private int mChannel;
private int mMaxNumberOfClients;
-
- private int setSecurityType() {
- int securityType = SECURITY_TYPE_OPEN;
- if (!TextUtils.isEmpty(mWpa2Passphrase)) { // WPA2-PSK network.
- securityType = SECURITY_TYPE_WPA2_PSK;
- }
- return securityType;
- }
-
- private void clearAllPassphrase() {
- mWpa2Passphrase = null;
- }
+ private int mSecurityType;
+ private int mShutdownTimeoutMillis;
/**
* Constructs a Builder with default values (see {@link Builder}).
@@ -384,11 +410,13 @@ public final class SoftApConfiguration implements Parcelable {
public Builder() {
mSsid = null;
mBssid = null;
- mWpa2Passphrase = null;
+ mPassphrase = null;
mHiddenSsid = false;
mBand = BAND_2GHZ;
mChannel = 0;
mMaxNumberOfClients = 0;
+ mSecurityType = SECURITY_TYPE_OPEN;
+ mShutdownTimeoutMillis = 0;
}
/**
@@ -399,11 +427,13 @@ public final class SoftApConfiguration implements Parcelable {
mSsid = other.mSsid;
mBssid = other.mBssid;
- mWpa2Passphrase = other.mWpa2Passphrase;
+ mPassphrase = other.mPassphrase;
mHiddenSsid = other.mHiddenSsid;
mBand = other.mBand;
mChannel = other.mChannel;
mMaxNumberOfClients = other.mMaxNumberOfClients;
+ mSecurityType = other.mSecurityType;
+ mShutdownTimeoutMillis = other.mShutdownTimeoutMillis;
}
/**
@@ -413,8 +443,9 @@ public final class SoftApConfiguration implements Parcelable {
*/
@NonNull
public SoftApConfiguration build() {
- return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase,
- mHiddenSsid, mBand, mChannel, setSecurityType(), mMaxNumberOfClients);
+ return new SoftApConfiguration(mSsid, mBssid, mPassphrase,
+ mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients,
+ mShutdownTimeoutMillis);
}
/**
@@ -462,26 +493,43 @@ public final class SoftApConfiguration implements Parcelable {
}
/**
- * Specifies that this AP should use WPA2-PSK with the given ASCII WPA2 passphrase.
- * When set to null, an open network is created.
- * <p>
+ * Specifies that this AP should use specific security type with the given ASCII passphrase.
+ *
+ * @param securityType one of the security types from {@link @SecurityType}.
+ * @param passphrase The passphrase to use for sepcific {@link @SecurityType} configuration
+ * or null with {@link @SecurityType#SECURITY_TYPE_OPEN}.
*
- * @param passphrase The passphrase to use, or null to unset a previously-set WPA2-PSK
- * configuration.
* @return Builder for chaining.
- * @throws IllegalArgumentException when the passphrase is the empty string
+ * @throws IllegalArgumentException when the passphrase length is invalid and
+ * {@code securityType} is not {@link @SecurityType#SECURITY_TYPE_OPEN}
+ * or non-null passphrase and {@code securityType} is
+ * {@link @SecurityType#SECURITY_TYPE_OPEN}.
*/
@NonNull
- public Builder setWpa2Passphrase(@Nullable String passphrase) {
- if (passphrase != null) {
+ public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) {
+ if (securityType == SECURITY_TYPE_OPEN) {
+ if (passphrase != null) {
+ throw new IllegalArgumentException(
+ "passphrase should be null when security type is open");
+ }
+ } else {
+ Preconditions.checkStringNotEmpty(passphrase);
final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
if (!asciiEncoder.canEncode(passphrase)) {
throw new IllegalArgumentException("passphrase not ASCII encodable");
}
- Preconditions.checkStringNotEmpty(passphrase);
+ if (securityType == SECURITY_TYPE_WPA2_PSK
+ || securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION) {
+ if (passphrase.length() < PSK_MIN_LEN || passphrase.length() > PSK_MAX_LEN) {
+ throw new IllegalArgumentException(
+ "Password size must be at least " + PSK_MIN_LEN
+ + " and no more than " + PSK_MAX_LEN
+ + " for WPA2_PSK and WPA3_SAE_TRANSITION Mode");
+ }
+ }
}
- clearAllPassphrase();
- mWpa2Passphrase = passphrase;
+ mSecurityType = securityType;
+ mPassphrase = passphrase;
return this;
}
@@ -589,5 +637,30 @@ public final class SoftApConfiguration implements Parcelable {
mMaxNumberOfClients = maxNumberOfClients;
return this;
}
+
+ /**
+ * Specifies the shutdown timeout in milliseconds.
+ * The Soft AP will shut down when there are no devices connected to it for
+ * the timeout duration.
+ *
+ * Specify a value of 0 to have the framework automatically use default timeout
+ * setting which defined in {@link R.integer.config_wifi_framework_soft_ap_timeout_delay}
+ *
+ * <p>
+ * <li>If not set, defaults to 0</li>
+ * <li>The shut down timout will apply when
+ * {@link Settings.Global.SOFT_AP_TIMEOUT_ENABLED} is true</li>
+ *
+ * @param timeoutMillis milliseconds of the timeout delay.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setShutdownTimeoutMillis(int timeoutMillis) {
+ if (timeoutMillis < 0) {
+ throw new IllegalArgumentException("Invalid timeout value");
+ }
+ mShutdownTimeoutMillis = timeoutMillis;
+ return this;
+ }
}
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a379c75360ac..f4c5b9168cd0 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -253,9 +253,12 @@ public class WifiConfiguration implements Parcelable {
/** LEAP/Network EAP (only used with LEAP) */
public static final int LEAP = 2;
+ /** SAE (Used only for WPA3-Personal) */
+ public static final int SAE = 3;
+
public static final String varName = "auth_alg";
- public static final String[] strings = { "OPEN", "SHARED", "LEAP" };
+ public static final String[] strings = { "OPEN", "SHARED", "LEAP", "SAE" };
}
/**
@@ -468,10 +471,13 @@ public class WifiConfiguration implements Parcelable {
break;
case SECURITY_TYPE_SAE:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
requirePMF = true;
break;
case SECURITY_TYPE_EAP_SUITE_B:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
// Note: allowedSuiteBCiphers bitset will be set by the service once the
@@ -480,6 +486,8 @@ public class WifiConfiguration implements Parcelable {
break;
case SECURITY_TYPE_OWE:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
requirePMF = true;
break;
case SECURITY_TYPE_WAPI_PSK:
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 378c67ba4fcb..1baab12b8ab5 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -545,15 +545,22 @@ public class WifiManager {
public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
/**
- * The look up key for an int that indicates why softAP started failed
- * currently support general and no_channel
- * @see #SAP_START_FAILURE_GENERAL
- * @see #SAP_START_FAILURE_NO_CHANNEL
- * @see #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION
+ * An extra containing the int error code for Soft AP start failure.
+ * Can be obtained from the {@link #WIFI_AP_STATE_CHANGED_ACTION} using
+ * {@link android.content.Intent#getIntExtra}.
+ * This extra will only be attached if {@link #EXTRA_WIFI_AP_STATE} is
+ * attached and is equal to {@link #WIFI_AP_STATE_FAILED}.
+ *
+ * The error code will be one of:
+ * {@link #SAP_START_FAILURE_GENERAL},
+ * {@link #SAP_START_FAILURE_NO_CHANNEL},
+ * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
*
* @hide
*/
- public static final String EXTRA_WIFI_AP_FAILURE_REASON = "wifi_ap_error_code";
+ @SystemApi
+ public static final String EXTRA_WIFI_AP_FAILURE_REASON =
+ "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
/**
* The previous Wi-Fi state.
*
@@ -1359,6 +1366,36 @@ public class WifiManager {
}
/**
+ * Retrieve a list of {@link WifiConfiguration} for available {@link WifiNetworkSuggestion}
+ * matching the given list of {@link ScanResult}.
+ *
+ * An available {@link WifiNetworkSuggestion} must satisfy:
+ * <ul>
+ * <li> Matching one of the {@link ScanResult} from the given list.
+ * <li> and {@link WifiNetworkSuggestion.Builder#setIsUserAllowedToManuallyConnect(boolean)} set
+ * to true.
+ * </ul>
+ *
+ * @param scanResults a list of scanResult.
+ * @return a list of @link WifiConfiguration} for available {@link WifiNetworkSuggestion}
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD
+ })
+ @NonNull
+ public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
+ @NonNull List<ScanResult> scanResults) {
+ try {
+ return mService.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(scanResults);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
* Returns a list of unique Hotspot 2.0 OSU (Online Sign-Up) providers associated with a given
* list of ScanResult.
*
@@ -4103,6 +4140,23 @@ public class WifiManager {
}
/**
+ * Configure auto-join settings for a Passpoint profile.
+ *
+ * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
+ * @param enableAutoJoin true to enable autojoin, false to disable autojoin.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void allowAutojoinPasspoint(@NonNull String fqdn, boolean enableAutoJoin) {
+ try {
+ mService.allowAutojoinPasspoint(fqdn, enableAutoJoin);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Disable an ephemeral network.
*
* @param ssid in the format of WifiConfiguration's SSID.
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 5befb54ce50a..1822e84fdd57 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -17,6 +17,7 @@
package android.net.wifi.hotspot2;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.net.wifi.hotspot2.pps.Credential;
import android.net.wifi.hotspot2.pps.HomeSp;
import android.net.wifi.hotspot2.pps.Policy;
@@ -423,6 +424,41 @@ public final class PasspointConfiguration implements Parcelable {
}
/**
+ * The auto-join configuration specifies whether or not the Passpoint Configuration is
+ * considered for auto-connection. If true then yes, if false then it isn't considered as part
+ * of auto-connection - but can still be manually connected to.
+ */
+ private boolean mIsAutoJoinEnabled = true;
+
+ /**
+ * Configures the auto-association status of this Passpoint configuration. A value of true
+ * indicates that the configuration will be considered for auto-connection, a value of false
+ * indicates that only manual connection will work - the framework will not auto-associate to
+ * this Passpoint network.
+ *
+ * @param autoJoinEnabled true to be considered for framework auto-connection, false otherwise.
+ * @hide
+ */
+ public void setAutoJoinEnabled(boolean autoJoinEnabled) {
+ mIsAutoJoinEnabled = autoJoinEnabled;
+ }
+
+ /**
+ * Indicates whether the Passpoint configuration may be auto-connected to by the framework. A
+ * value of true indicates that auto-connection can happen, a value of false indicates that it
+ * cannot. However, even when auto-connection is not possible manual connection by the user is
+ * possible.
+ *
+ * @return the auto-join configuration: true for auto-connection (or join) enabled, false
+ * otherwise.
+ * @hide
+ */
+ @SystemApi
+ public boolean isAutoJoinEnabled() {
+ return mIsAutoJoinEnabled;
+ }
+
+ /**
* Constructor for creating PasspointConfiguration with default values.
*/
public PasspointConfiguration() {}
@@ -464,6 +500,7 @@ public final class PasspointConfiguration implements Parcelable {
mServiceFriendlyNames = source.mServiceFriendlyNames;
mAaaServerTrustedNames = source.mAaaServerTrustedNames;
mCarrierId = source.mCarrierId;
+ mIsAutoJoinEnabled = source.mIsAutoJoinEnabled;
}
@Override
@@ -493,6 +530,7 @@ public final class PasspointConfiguration implements Parcelable {
(HashMap<String, String>) mServiceFriendlyNames);
dest.writeBundle(bundle);
dest.writeInt(mCarrierId);
+ dest.writeBoolean(mIsAutoJoinEnabled);
}
@Override
@@ -523,6 +561,7 @@ public final class PasspointConfiguration implements Parcelable {
&& mUsageLimitDataLimit == that.mUsageLimitDataLimit
&& mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
&& mCarrierId == that.mCarrierId
+ && mIsAutoJoinEnabled == that.mIsAutoJoinEnabled
&& (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null
: mServiceFriendlyNames.equals(that.mServiceFriendlyNames));
}
@@ -533,7 +572,7 @@ public final class PasspointConfiguration implements Parcelable {
mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis,
mSubscriptionExpirationTimeInMillis, mUsageLimitUsageTimePeriodInMinutes,
mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
- mServiceFriendlyNames, mCarrierId);
+ mServiceFriendlyNames, mCarrierId, mIsAutoJoinEnabled);
}
@Override
@@ -587,6 +626,7 @@ public final class PasspointConfiguration implements Parcelable {
builder.append("ServiceFriendlyNames: ").append(mServiceFriendlyNames);
}
builder.append("CarrierId:" + mCarrierId);
+ builder.append("IsAutoJoinEnabled:" + mIsAutoJoinEnabled);
return builder.toString();
}
@@ -692,6 +732,7 @@ public final class PasspointConfiguration implements Parcelable {
"serviceFriendlyNames");
config.setServiceFriendlyNames(friendlyNamesMap);
config.mCarrierId = in.readInt();
+ config.mIsAutoJoinEnabled = in.readBoolean();
return config;
}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index d58083c92df6..3c13562d6952 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -182,6 +182,11 @@ public class BaseWifiService extends IWifiManager.Stub {
}
@Override
+ public void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean startScan(String packageName, String featureId) {
throw new UnsupportedOperationException();
}
@@ -584,4 +589,10 @@ public class BaseWifiService extends IWifiManager.Stub {
public int calculateSignalLevel(int rssi) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
+ List<ScanResult> scanResults) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 1f601036a718..eeea7e2a6cd8 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -25,8 +25,12 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
+import java.util.Random;
+
@SmallTest
public class SoftApConfigurationTest {
+ private static final String TEST_CHAR_SET_AS_STRING = "abcdefghijklmnopqrstuvwxyz0123456789";
+
private SoftApConfiguration parcelUnparcel(SoftApConfiguration configIn) {
Parcel parcel = Parcel.obtain();
parcel.writeParcelable(configIn, 0);
@@ -37,6 +41,25 @@ public class SoftApConfigurationTest {
return configOut;
}
+ /**
+ * Helper method to generate random string.
+ *
+ * Note: this method has limited use as a random string generator.
+ * The characters used in this method do no not cover all valid inputs.
+ * @param length number of characters to generate for the string
+ * @return String generated string of random characters
+ */
+ private String generateRandomString(int length) {
+ Random random = new Random();
+ StringBuilder stringBuilder = new StringBuilder(length);
+ int index = -1;
+ while (stringBuilder.length() < length) {
+ index = random.nextInt(TEST_CHAR_SET_AS_STRING.length());
+ stringBuilder.append(TEST_CHAR_SET_AS_STRING.charAt(index));
+ }
+ return stringBuilder.toString();
+ }
+
@Test
public void testBasicSettings() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
@@ -45,7 +68,7 @@ public class SoftApConfigurationTest {
.build();
assertThat(original.getSsid()).isEqualTo("ssid");
assertThat(original.getBssid()).isEqualTo(MacAddress.fromString("11:22:33:44:55:66"));
- assertThat(original.getWpa2Passphrase()).isNull();
+ assertThat(original.getPassphrase()).isNull();
assertThat(original.getSecurityType()).isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
assertThat(original.getChannel()).isEqualTo(0);
@@ -66,9 +89,9 @@ public class SoftApConfigurationTest {
@Test
public void testWpa2() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
- .setWpa2Passphrase("secretsecret")
+ .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
.build();
- assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
+ assertThat(original.getPassphrase()).isEqualTo("secretsecret");
assertThat(original.getSecurityType()).isEqualTo(
SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
@@ -90,19 +113,73 @@ public class SoftApConfigurationTest {
@Test
public void testWpa2WithAllFieldCustomized() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
- .setWpa2Passphrase("secretsecret")
- .setBand(SoftApConfiguration.BAND_ANY)
+ .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
.setChannel(149, SoftApConfiguration.BAND_5GHZ)
.setHiddenSsid(true)
.setMaxNumberOfClients(10)
+ .setShutdownTimeoutMillis(500000)
.build();
- assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
+ assertThat(original.getPassphrase()).isEqualTo("secretsecret");
assertThat(original.getSecurityType()).isEqualTo(
SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
assertThat(original.getChannel()).isEqualTo(149);
assertThat(original.isHiddenSsid()).isEqualTo(true);
assertThat(original.getMaxNumberOfClients()).isEqualTo(10);
+ assertThat(original.getShutdownTimeoutMillis()).isEqualTo(500000);
+
+ SoftApConfiguration unparceled = parcelUnparcel(original);
+ assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isEqualTo(original);
+ assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+ SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+ assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isEqualTo(original);
+ assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test
+ public void testWpa3Sae() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ assertThat(original.getPassphrase()).isEqualTo("secretsecret");
+ assertThat(original.getSecurityType()).isEqualTo(
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
+ assertThat(original.getChannel()).isEqualTo(149);
+ assertThat(original.isHiddenSsid()).isEqualTo(true);
+
+
+ SoftApConfiguration unparceled = parcelUnparcel(original);
+ assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isEqualTo(original);
+ assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+ SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+ assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isEqualTo(original);
+ assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test
+ public void testWpa3SaeTransition() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase("secretsecret",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ assertThat(original.getSecurityType()).isEqualTo(
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
+ assertThat(original.getPassphrase()).isEqualTo("secretsecret");
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
+ assertThat(original.getChannel()).isEqualTo(149);
+ assertThat(original.isHiddenSsid()).isEqualTo(true);
+
SoftApConfiguration unparceled = parcelUnparcel(original);
assertThat(unparceled).isNotSameAs(original);
@@ -114,4 +191,51 @@ public class SoftApConfigurationTest {
assertThat(copy).isEqualTo(original);
assertThat(copy.hashCode()).isEqualTo(original.hashCode());
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidShortPasswordLengthForWpa2() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MIN_LEN - 1),
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidLongPasswordLengthForWpa2() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MAX_LEN + 1),
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidShortPasswordLengthForWpa3SaeTransition() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MIN_LEN - 1),
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidLongPasswordLengthForWpa3SaeTransition() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MAX_LEN + 1),
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
+ .setChannel(149, SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(true)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalieShutdownTimeoutMillis() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setShutdownTimeoutMillis(-1)
+ .build();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 909cfefba941..8689a38c6b17 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -16,6 +16,10 @@
package android.net.wifi;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -328,4 +332,57 @@ public class WifiConfigurationTest {
assertNotNull(NetworkSelectionStatus.DISABLE_REASON_INFOS.get(i));
}
}
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for SAE security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForSae() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_SAE);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.requirePMF);
+ }
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for OWE security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForOwe() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_OWE);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.requirePMF);
+ }
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for Suite-B security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForSuiteB() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
+ assertTrue(config.allowedGroupManagementCiphers
+ .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
+ assertTrue(config.requirePMF);
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index f9bd31d57ffc..4b837184dc9a 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1672,10 +1672,22 @@ public class WifiManagerTest {
@Test
public void testAllowAutojoin() throws Exception {
mWifiManager.allowAutojoin(1, true);
- verify(mWifiService).allowAutojoin(eq(1), eq(true));
+ verify(mWifiService).allowAutojoin(1, true);
}
/**
+ * Test behavior of {@link WifiManager#allowAutojoinPasspoint(String, boolean)}
+ * @throws Exception
+ */
+ @Test
+ public void testAllowAutojoinPasspoint() throws Exception {
+ final String fqdn = "FullyQualifiedDomainName";
+ mWifiManager.allowAutojoinPasspoint(fqdn, true);
+ verify(mWifiService).allowAutojoinPasspoint(fqdn, true);
+ }
+
+
+ /**
* Test behavior of {@link WifiManager#disconnect()}
*/
@Test
@@ -2173,4 +2185,18 @@ public class WifiManagerTest {
result = WifiManager.parseDppChannelList(channelList);
assertEquals(result.size(), 0);
}
+
+ /**
+ * Test getWifiConfigsForMatchedNetworkSuggestions for given scanResults.
+ */
+ @Test
+ public void testGetWifiConfigsForMatchedNetworkSuggestions() throws Exception {
+ List<WifiConfiguration> testResults = new ArrayList<>();
+ testResults.add(new WifiConfiguration());
+
+ when(mWifiService.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(any(List.class)))
+ .thenReturn(testResults);
+ assertEquals(testResults, mWifiManager
+ .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(new ArrayList<>()));
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index f501b16d2c79..94054fdde8da 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -171,6 +171,7 @@ public class PasspointConfigurationTest {
assertFalse(config.validate());
assertFalse(config.validateForR2());
+ assertTrue(config.isAutoJoinEnabled());
}
/**