summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/jni/SystemPerfTest.cpp2
-rw-r--r--apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java (renamed from apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java)2
-rw-r--r--api/current.txt244
-rw-r--r--api/system-current.txt252
-rw-r--r--api/test-current.txt244
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java6
-rw-r--r--core/java/android/app/AppOpsManager.java16
-rw-r--r--core/java/android/app/ApplicationPackageManager.java8
-rw-r--r--core/java/android/app/ContextImpl.java7
-rw-r--r--core/java/android/app/FragmentTransition.java15
-rw-r--r--core/java/android/app/Notification.java17
-rw-r--r--core/java/android/app/NotificationChannel.java45
-rw-r--r--core/java/android/app/NotificationManager.java13
-rw-r--r--core/java/android/app/ResourcesManager.java20
-rw-r--r--core/java/android/app/assist/AssistStructure.java31
-rw-r--r--core/java/android/content/ContentResolver.java6
-rw-r--r--core/java/android/content/Context.java13
-rw-r--r--core/java/android/content/pm/BaseParceledListSlice.java201
-rw-r--r--core/java/android/content/pm/InstantAppInfo.java2
-rw-r--r--core/java/android/content/pm/LauncherApps.java4
-rw-r--r--core/java/android/content/pm/PackageInstaller.java32
-rw-r--r--core/java/android/content/pm/PackageManager.java41
-rw-r--r--core/java/android/content/pm/PackageParser.java116
-rw-r--r--core/java/android/content/pm/ParceledListSlice.java171
-rw-r--r--core/java/android/content/pm/ResolveInfo.java8
-rw-r--r--core/java/android/content/pm/ShortcutInfo.java15
-rw-r--r--core/java/android/content/pm/StringParceledListSlice.aidl19
-rw-r--r--core/java/android/content/pm/StringParceledListSlice.java83
-rw-r--r--core/java/android/content/res/AssetManager.java22
-rw-r--r--core/java/android/content/res/CompatResources.java14
-rw-r--r--core/java/android/content/res/CompatibilityInfo.java14
-rw-r--r--core/java/android/net/ConnectivityManager.java9
-rw-r--r--core/java/android/net/IpSecAlgorithm.java181
-rw-r--r--core/java/android/net/IpSecConfig.aidl20
-rw-r--r--core/java/android/net/IpSecConfig.java197
-rw-r--r--core/java/android/net/IpSecManager.java379
-rw-r--r--core/java/android/net/IpSecTransform.java471
-rw-r--r--core/java/android/net/NetworkPolicyManager.java17
-rw-r--r--core/java/android/net/NetworkScoreManager.java12
-rw-r--r--core/java/android/net/NetworkScorerAppData.java17
-rw-r--r--core/java/android/os/BatteryManager.java2
-rw-r--r--core/java/android/os/StrictMode.java2
-rw-r--r--core/java/android/os/UpdateEngine.java77
-rw-r--r--core/java/android/os/UpdateEngineCallback.java13
-rw-r--r--core/java/android/os/storage/VolumeInfo.java2
-rw-r--r--core/java/android/preference/Preference.java24
-rw-r--r--core/java/android/preference/PreferenceDataStore.java32
-rw-r--r--core/java/android/preference/PreferenceManager.java13
-rw-r--r--core/java/android/provider/DocumentsContract.java3
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java2
-rw-r--r--core/java/android/service/quicksettings/TileService.java4
-rw-r--r--core/java/android/view/SurfaceControl.java17
-rw-r--r--core/java/android/view/SurfaceSession.java5
-rw-r--r--core/java/android/view/SurfaceView.java451
-rw-r--r--core/java/android/view/ViewRootImpl.java10
-rw-r--r--core/java/android/view/ViewStructure.java7
-rw-r--r--core/java/android/view/autofill/AutoFillType.java38
-rw-r--r--core/java/android/view/autofill/AutoFillValue.java48
-rw-r--r--core/java/android/widget/CompoundButton.java2
-rw-r--r--core/java/android/widget/DatePicker.java60
-rwxr-xr-xcore/java/android/widget/DatePickerCalendarDelegate.java10
-rw-r--r--core/java/android/widget/DatePickerSpinnerDelegate.java4
-rw-r--r--core/java/android/widget/RadioGroup.java2
-rw-r--r--core/java/android/widget/TextView.java1
-rw-r--r--core/java/android/widget/TimePicker.java64
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java12
-rw-r--r--core/java/android/widget/TimePickerSpinnerDelegate.java3
-rw-r--r--core/java/com/android/internal/app/NightDisplayController.java4
-rw-r--r--core/java/com/android/internal/notification/SystemNotificationChannels.java136
-rw-r--r--core/java/com/android/internal/util/ParcelableString.java52
-rw-r--r--core/java/com/android/internal/view/SurfaceCallbackHelper.java21
-rw-r--r--core/java/com/android/internal/view/menu/CascadingMenuPopup.java29
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp73
-rw-r--r--core/jni/android/graphics/Bitmap.h8
-rw-r--r--core/jni/android_os_HwBinder.cpp2
-rw-r--r--core/jni/android_util_AssetManager.cpp22
-rw-r--r--core/jni/android_view_InputChannel.cpp9
-rw-r--r--core/jni/android_view_RenderNode.cpp8
-rw-r--r--core/jni/android_view_SurfaceControl.cpp28
-rw-r--r--core/jni/android_view_SurfaceSession.cpp11
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp4
-rw-r--r--core/res/AndroidManifest.xml15
-rw-r--r--core/res/res/layout/notification_template_material_messaging.xml4
-rw-r--r--core/res/res/values/attrs.xml360
-rw-r--r--core/res/res/values/attrs_manifest.xml8
-rw-r--r--core/res/res/values/config.xml1
-rw-r--r--core/res/res/values/public.xml7
-rw-r--r--core/res/res/values/strings.xml47
-rw-r--r--core/res/res/values/symbols.xml17
-rw-r--r--core/tests/coretests/AndroidManifest.xml3
-rw-r--r--core/tests/coretests/res/color/color1.xml (renamed from graphics/tests/graphicstests/res/color/color1.xml)0
-rw-r--r--core/tests/coretests/res/color/color_no_default.xml (renamed from graphics/tests/graphicstests/res/color/color_no_default.xml)0
-rw-r--r--core/tests/coretests/res/drawable-nodpi/landscape.png (renamed from graphics/tests/graphicstests/res/drawable-nodpi/landscape.png)bin24981 -> 24981 bytes
-rw-r--r--core/tests/coretests/res/drawable/test128x96.png (renamed from graphics/tests/graphicstests/res/drawable/test128x96.png)bin21474 -> 21474 bytes
-rw-r--r--core/tests/coretests/res/drawable/test16x12.png (renamed from graphics/tests/graphicstests/res/drawable/test16x12.png)bin707 -> 707 bytes
-rw-r--r--core/tests/coretests/res/drawable/test256x192.png (renamed from graphics/tests/graphicstests/res/drawable/test256x192.png)bin78630 -> 78630 bytes
-rw-r--r--core/tests/coretests/res/drawable/test320x240.png (renamed from graphics/tests/graphicstests/res/drawable/test320x240.png)bin39533 -> 39533 bytes
-rw-r--r--core/tests/coretests/res/drawable/test32x24.png (renamed from graphics/tests/graphicstests/res/drawable/test32x24.png)bin1841 -> 1841 bytes
-rw-r--r--core/tests/coretests/res/drawable/test64x48.png (renamed from graphics/tests/graphicstests/res/drawable/test64x48.png)bin6020 -> 6020 bytes
-rw-r--r--core/tests/coretests/res/values/colors.xml3
-rw-r--r--core/tests/coretests/src/android/app/activity/LocalProvider.java32
-rw-r--r--core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java178
-rw-r--r--core/tests/coretests/src/android/content/CrossUserContentService.java45
-rw-r--r--core/tests/coretests/src/android/content/ICrossUserContentService.aidl24
-rw-r--r--core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java42
-rw-r--r--core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java40
-rw-r--r--core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java22
-rw-r--r--core/tests/coretests/src/android/graphics/BitmapFactoryTest.java (renamed from graphics/tests/graphicstests/src/android/graphics/BitmapFactoryTest.java)4
-rw-r--r--core/tests/coretests/src/android/graphics/BitmapTest.java (renamed from graphics/tests/graphicstests/src/android/graphics/BitmapTest.java)39
-rw-r--r--core/tests/coretests/src/android/graphics/ColorStateListTest.java (renamed from graphics/tests/graphicstests/src/android/graphics/ColorStateListTest.java)6
-rw-r--r--core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java (renamed from graphics/tests/graphicstests/src/android/graphics/GraphicsPerformanceTests.java)10
-rw-r--r--core/tests/coretests/src/android/graphics/GraphicsTests.java (renamed from graphics/tests/graphicstests/src/android/graphics/GraphicsTests.java)0
-rw-r--r--core/tests/coretests/src/android/graphics/PaintTest.java209
-rw-r--r--core/tests/coretests/src/android/graphics/PathTest.java (renamed from graphics/tests/graphicstests/src/android/graphics/PathTest.java)1
-rw-r--r--core/tests/coretests/src/android/graphics/ThreadBitmapTest.java (renamed from graphics/tests/graphicstests/src/android/graphics/ThreadBitmapTest.java)4
-rw-r--r--core/tests/coretests/src/android/graphics/VariationParserTest.java (renamed from graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java)4
-rw-r--r--core/tests/coretests/src/android/graphics/drawable/IconTest.java (renamed from graphics/tests/graphicstests/src/android/graphics/drawable/IconTest.java)17
-rw-r--r--core/tests/coretests/src/android/graphics/drawable/StateListDrawableTest.java (renamed from graphics/tests/graphicstests/src/android/graphics/drawable/StateListDrawableTest.java)4
-rw-r--r--core/tests/coretests/src/android/view/MockView.java (renamed from graphics/tests/graphicstests/src/android/view/MockView.java)0
-rw-r--r--graphics/java/android/graphics/drawable/Icon.java32
-rw-r--r--graphics/tests/graphicstests/Android.mk15
-rw-r--r--graphics/tests/graphicstests/AndroidManifest.xml38
-rw-r--r--graphics/tests/graphicstests/res/values/colors.xml24
-rw-r--r--graphics/tests/graphicstests/src/android/graphics/PaintTest.java230
-rw-r--r--keystore/java/android/security/IKeyChainService.aidl6
-rw-r--r--keystore/java/android/security/keystore/KeyProperties.java11
-rw-r--r--libs/hwui/TreeInfo.h2
-rw-r--r--media/java/android/media/tv/TvContract.java1316
-rw-r--r--media/java/android/media/tv/TvInputManager.java34
-rw-r--r--media/java/android/media/tv/TvView.java4
-rw-r--r--native/android/libandroid.map.txt38
-rw-r--r--native/android/sensor.cpp109
-rw-r--r--native/graphics/jni/bitmap.cpp64
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java4
-rw-r--r--packages/SettingsLib/res/layout/drawer_category.xml38
-rw-r--r--packages/SettingsLib/res/layout/drawer_item.xml44
-rw-r--r--packages/SettingsLib/res/layout/drawer_spacer.xml20
-rw-r--r--packages/SettingsLib/res/layout/settings_with_drawer.xml9
-rwxr-xr-xpackages/SettingsLib/res/values/config.xml3
-rw-r--r--packages/SettingsLib/res/values/dimens.xml6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/instantapps/InstantAppDataProvider.java28
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java268
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java147
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java4
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java10
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java (renamed from packages/SystemUI/src/com/android/systemui/ActivityStarter.java)6
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java31
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetail.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTile.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java137
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java127
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java121
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/InflationException.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java278
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java338
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java313
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java99
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java16
-rw-r--r--proto/src/metrics_constants.proto18
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java39
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java16
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java30
-rw-r--r--services/core/java/com/android/server/NetworkScoreService.java18
-rw-r--r--services/core/java/com/android/server/NetworkScorerAppManager.java16
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java4
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java26
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java130
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java45
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java12
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java49
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java51
-rw-r--r--services/core/java/com/android/server/am/PreBootBroadcaster.java7
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java20
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java6
-rw-r--r--services/core/java/com/android/server/am/UidRecord.java8
-rw-r--r--services/core/java/com/android/server/am/UserState.java8
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java8
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkNotificationManager.java9
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java16
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java22
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java3
-rw-r--r--services/core/java/com/android/server/content/ContentService.java27
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java6
-rw-r--r--services/core/java/com/android/server/fingerprint/ClientMonitor.java4
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java23
-rw-r--r--services/core/java/com/android/server/net/LockdownVpnTracker.java25
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java19
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java28
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java17
-rw-r--r--services/core/java/com/android/server/pm/InstantAppRegistry.java1
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java43
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java22
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java96
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java3
-rw-r--r--services/core/java/com/android/server/pm/ParallelPackageParser.java5
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java4
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java9
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java113
-rw-r--r--services/core/java/com/android/server/pm/dex/PackageDexUsage.java33
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java8
-rw-r--r--services/core/java/com/android/server/storage/DeviceStorageMonitorService.java49
-rw-r--r--services/core/java/com/android/server/wm/AlertWindowNotification.java38
-rw-r--r--services/core/java/com/android/server/wm/AppWindowAnimator.java5
-rw-r--r--services/core/java/com/android/server/wm/AppWindowContainerController.java3
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java69
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java8
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java2
-rw-r--r--services/core/java/com/android/server/wm/Session.java3
-rw-r--r--services/core/java/com/android/server/wm/Task.java5
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotCache.java4
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java5
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java12
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java3
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowLayersController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java25
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java94
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java20
-rw-r--r--services/core/jni/com_android_server_lights_LightsService.cpp110
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp20
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java20
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java29
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java17
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java3
-rw-r--r--services/tests/notification/AndroidManifest.xml1
-rw-r--r--services/tests/notification/src/com/android/server/notification/GroupHelperTest.java2
-rw-r--r--services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java21
-rw-r--r--services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java6
-rw-r--r--services/tests/notification/src/com/android/server/notification/RankingHelperTest.java16
-rw-r--r--services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java16
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java37
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java148
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java28
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java118
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java30
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java6
-rw-r--r--services/usb/java/com/android/server/usb/MtpNotificationManager.java14
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java9
-rw-r--r--services/usb/java/com/android/server/usb/UsbPortManager.java2
-rw-r--r--telecomm/java/android/telecom/Call.java10
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java77
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl9
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java39
-rw-r--r--telephony/java/android/telephony/ims/ImsService.java25
-rw-r--r--telephony/java/android/telephony/ims/feature/ImsFeature.java63
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl13
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java2
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java6
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java59
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java285
-rw-r--r--tools/aapt/Command.cpp18
-rw-r--r--tools/layoutlib/bridge/src/android/view/RectShadowPainter.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java2
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.pngbin0 -> 22616 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml97
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java2
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java5
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java11
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java48
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java9
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java339
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java80
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java34
-rw-r--r--wifi/java/android/net/wifi/aware/DiscoverySession.java109
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareManager.java114
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareSession.java97
-rw-r--r--wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java26
-rw-r--r--wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java54
336 files changed, 9211 insertions, 4579 deletions
diff --git a/apct-tests/perftests/core/jni/SystemPerfTest.cpp b/apct-tests/perftests/core/jni/SystemPerfTest.cpp
index eb5540844808..f102e3ec0a71 100644
--- a/apct-tests/perftests/core/jni/SystemPerfTest.cpp
+++ b/apct-tests/perftests/core/jni/SystemPerfTest.cpp
@@ -73,7 +73,7 @@ jint JNI_OnLoad(JavaVM* jvm, void*) {
return JNI_ERR;
}
- if (registerNativeMethods(env, "java/lang/perftests/SystemPerfTest",
+ if (registerNativeMethods(env, "android/perftests/SystemPerfTest",
sMethods, NELEM(sMethods)) == -1) {
return JNI_ERR;
}
diff --git a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java b/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java
index afc9d0cf10e1..95a714486062 100644
--- a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
+++ b/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package java.lang.perftests;
+package android.perftests;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
diff --git a/api/current.txt b/api/current.txt
index ae8c2bdaeca2..cf6c925a6efe 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16,6 +16,7 @@ package android {
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
+ field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -1004,7 +1005,7 @@ package android {
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
- field public static final int primaryContentAlpha = 16843367; // 0x1010267
+ field public static final int primaryContentAlpha = 16844117; // 0x1010555
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1060,7 +1061,9 @@ package android {
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
+ field public static final int requiredFeature = 16844119; // 0x1010557
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
+ field public static final int requiredNotFeature = 16844120; // 0x1010558
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1129,7 +1132,7 @@ package android {
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
- field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
+ field public static final int secondaryContentAlpha = 16844118; // 0x1010556
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -4143,6 +4146,7 @@ package android.app {
field public static final int MODE_ERRORED = 2; // 0x2
field public static final int MODE_IGNORED = 1; // 0x1
field public static final java.lang.String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
+ field public static final java.lang.String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
field public static final java.lang.String OPSTR_BODY_SENSORS = "android:body_sensors";
field public static final java.lang.String OPSTR_CALL_PHONE = "android:call_phone";
field public static final java.lang.String OPSTR_CAMERA = "android:camera";
@@ -5480,6 +5484,7 @@ package android.app {
public final class NotificationChannel implements android.os.Parcelable {
ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
+ ctor public NotificationChannel(java.lang.String, int, int);
ctor protected NotificationChannel(android.os.Parcel);
method public boolean canBypassDnd();
method public boolean canShowBadge();
@@ -5493,6 +5498,7 @@ package android.app {
method public int getLightColor();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
+ method public int getNameResId();
method public android.net.Uri getSound();
method public long[] getVibrationPattern();
method public void setBypassDnd(boolean);
@@ -6563,6 +6569,7 @@ package android.app.assist {
method public java.lang.String getIdEntry();
method public java.lang.String getIdPackage();
method public java.lang.String getIdType();
+ method public int getInputType();
method public int getLeft();
method public int getScrollX();
method public int getScrollY();
@@ -8674,6 +8681,7 @@ package android.content {
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -10166,9 +10174,11 @@ package android.content.pm {
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10211,6 +10221,7 @@ package android.content.pm {
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
@@ -10339,6 +10350,7 @@ package android.content.pm {
method public abstract boolean hasSystemFeature(java.lang.String);
method public abstract boolean hasSystemFeature(java.lang.String, int);
method public abstract boolean isInstantApp();
+ method public abstract boolean isInstantApp(java.lang.String);
method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public abstract boolean isSafeMode();
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -10470,8 +10482,11 @@ package android.content.pm {
field public static final int GET_SIGNATURES = 64; // 0x40
field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
+ field public static final int INSTALL_REASON_DEVICE_RESTORE = 2; // 0x2
+ field public static final int INSTALL_REASON_DEVICE_SETUP = 3; // 0x3
field public static final int INSTALL_REASON_POLICY = 1; // 0x1
field public static final int INSTALL_REASON_UNKNOWN = 0; // 0x0
+ field public static final int INSTALL_REASON_USER = 4; // 0x4
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
field public static final int MATCH_DIRECT_BOOT_AWARE = 524288; // 0x80000
@@ -10600,6 +10615,7 @@ package android.content.pm {
field public android.content.pm.ActivityInfo activityInfo;
field public android.content.IntentFilter filter;
field public int icon;
+ field public boolean instantAppAvailable;
field public boolean isDefault;
field public int labelRes;
field public int match;
@@ -13822,12 +13838,12 @@ package android.graphics.drawable {
}
public final class Icon implements android.os.Parcelable {
+ method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithContentUri(java.lang.String);
method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
- method public static android.graphics.drawable.Icon createWithMaskableBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
method public int describeContents();
@@ -24132,17 +24148,79 @@ package android.media.tv {
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final android.net.Uri buildWatchNextProgramUri(long);
method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
method public static final boolean isChannelUriForTunerInput(android.net.Uri);
method public static final boolean isProgramUri(android.net.Uri);
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+ field public static final java.lang.String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String AUTHORITY = "android.media.tv";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+ field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+ }
+
+ public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+ field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
}
public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
@@ -24248,69 +24326,17 @@ package android.media.tv {
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseProgramColumns {
- field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
- field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
- field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
- field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
- field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
- field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
- field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
- field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
- field public static final java.lang.String COLUMN_AUTHOR = "author";
- field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
- field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
- field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
- field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
- field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
- field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
- field public static final java.lang.String COLUMN_LIVE = "live";
- field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
- field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
- field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
- field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
- field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
- field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
- field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
- field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
- field public static final java.lang.String COLUMN_TYPE = "type";
- field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
- field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
- field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
- field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
- field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
- field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
- field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
- field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
- field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
- field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
- field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
- field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
- field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
- field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
- field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
- field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
- field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
- field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
- field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
- field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
- field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
@@ -24346,6 +24372,7 @@ package android.media.tv {
public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
@@ -24358,6 +24385,19 @@ package android.media.tv {
field public static final android.net.Uri CONTENT_URI;
}
+ public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ ctor public TvContract.WatchNextPrograms();
+ field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+ field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+ }
+
public final class TvInputInfo implements android.os.Parcelable {
method public boolean canRecord();
method public android.content.Intent createSettingsIntent();
@@ -24407,15 +24447,10 @@ package android.media.tv {
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
- field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
- field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
- field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -24987,6 +25022,68 @@ package android.net {
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -30037,12 +30134,12 @@ package android.os {
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
- field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
field public static final int BATTERY_PROPERTY_CURRENT_NOW = 2; // 0x2
field public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5; // 0x5
+ field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
field public static final int BATTERY_STATUS_CHARGING = 2; // 0x2
field public static final int BATTERY_STATUS_DISCHARGING = 3; // 0x3
field public static final int BATTERY_STATUS_FULL = 5; // 0x5
@@ -36323,7 +36420,6 @@ package android.security.keystore {
field public static final int PURPOSE_ENCRYPT = 1; // 0x1
field public static final int PURPOSE_SIGN = 4; // 0x4
field public static final int PURPOSE_VERIFY = 8; // 0x8
- field public static final int PURPOSE_WRAP_KEY = 16; // 0x10
field public static final java.lang.String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS";
}
@@ -36834,6 +36930,7 @@ package android.service.quicksettings {
method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
+ field public static final java.lang.String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
field public static final java.lang.String META_DATA_ACTIVE_TILE = "android.service.quicksettings.ACTIVE_TILE";
}
@@ -38143,6 +38240,7 @@ package android.telecom {
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
+ field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
field public static final int PROPERTY_WIFI = 8; // 0x8
}
@@ -38156,9 +38254,6 @@ package android.telecom {
field public static final int RTT_MODE_VCO = 3; // 0x3
}
- public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
- }
-
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -38699,6 +38794,8 @@ package android.telecom {
}
public class TelecomManager {
+ method public void acceptRingingCall();
+ method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
@@ -38713,6 +38810,7 @@ package android.telecom {
method public boolean handleMmi(java.lang.String);
method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
method public boolean isInCall();
+ method public boolean isInManagedCall();
method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle);
method public boolean isOutgoingCallPermitted(android.telecom.PhoneAccountHandle);
method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
@@ -38749,6 +38847,7 @@ package android.telecom {
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
+ field public static final java.lang.String METADATA_INCLUDE_SELF_MANAGED_CALLS = "android.telecom.INCLUDE_SELF_MANAGED_CALLS";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -39436,6 +39535,7 @@ package android.telephony {
method public java.lang.String getDeviceId();
method public java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
+ method public java.lang.String[] getForbiddenPlmns();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getIccAuthentication(int, int, java.lang.String);
method public java.lang.String getLine1Number();
@@ -40284,6 +40384,7 @@ package android.test.mock {
method public boolean hasSystemFeature(java.lang.String);
method public boolean hasSystemFeature(java.lang.String, int);
method public boolean isInstantApp();
+ method public boolean isInstantApp(java.lang.String);
method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public boolean isSafeMode();
method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -45845,6 +45946,7 @@ package android.view {
method public abstract void setFocused(boolean);
method public abstract void setHint(java.lang.CharSequence);
method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String);
+ method public abstract void setInputType(int);
method public abstract void setLongClickable(boolean);
method public abstract void setSanitized(boolean);
method public abstract void setSelected(boolean);
@@ -47096,10 +47198,12 @@ package android.view.autofill {
public final class AutoFillType implements android.os.Parcelable {
method public int describeContents();
+ method public static android.view.autofill.AutoFillType forDate();
method public static android.view.autofill.AutoFillType forList();
method public static android.view.autofill.AutoFillType forText(int);
method public static android.view.autofill.AutoFillType forToggle();
method public int getSubType();
+ method public boolean isDate();
method public boolean isList();
method public boolean isText();
method public boolean isToggle();
@@ -47109,9 +47213,11 @@ package android.view.autofill {
public final class AutoFillValue implements android.os.Parcelable {
method public int describeContents();
+ method public static android.view.autofill.AutoFillValue forDate(long);
method public static android.view.autofill.AutoFillValue forList(int);
method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence);
method public static android.view.autofill.AutoFillValue forToggle(boolean);
+ method public long getDateValue();
method public int getListValue();
method public java.lang.CharSequence getTextValue();
method public boolean getToggleValue();
diff --git a/api/system-current.txt b/api/system-current.txt
index e00507ee884c..7ef4db8d894b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -25,6 +25,7 @@ package android {
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
+ field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BACKUP = "android.permission.BACKUP";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
@@ -206,7 +207,6 @@ package android {
field public static final java.lang.String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
- field public static final java.lang.String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
@@ -1117,7 +1117,7 @@ package android {
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
- field public static final int primaryContentAlpha = 16843367; // 0x1010267
+ field public static final int primaryContentAlpha = 16844117; // 0x1010555
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1173,7 +1173,9 @@ package android {
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
+ field public static final int requiredFeature = 16844119; // 0x1010557
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
+ field public static final int requiredNotFeature = 16844120; // 0x1010558
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1246,7 +1248,7 @@ package android {
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
- field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
+ field public static final int secondaryContentAlpha = 16844118; // 0x1010556
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -4286,6 +4288,7 @@ package android.app {
field public static final int MODE_IGNORED = 1; // 0x1
field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
field public static final java.lang.String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
+ field public static final java.lang.String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
field public static final java.lang.String OPSTR_BODY_SENSORS = "android:body_sensors";
field public static final java.lang.String OPSTR_CALL_PHONE = "android:call_phone";
field public static final java.lang.String OPSTR_CAMERA = "android:camera";
@@ -5657,6 +5660,7 @@ package android.app {
public final class NotificationChannel implements android.os.Parcelable {
ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
+ ctor public NotificationChannel(java.lang.String, int, int);
ctor protected NotificationChannel(android.os.Parcel);
method public boolean canBypassDnd();
method public boolean canShowBadge();
@@ -5670,6 +5674,7 @@ package android.app {
method public int getLightColor();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
+ method public int getNameResId();
method public android.net.Uri getSound();
method public int getUserLockedFields();
method public long[] getVibrationPattern();
@@ -6803,6 +6808,7 @@ package android.app.assist {
method public java.lang.String getIdEntry();
method public java.lang.String getIdPackage();
method public java.lang.String getIdType();
+ method public int getInputType();
method public int getLeft();
method public int getScrollX();
method public int getScrollY();
@@ -9137,6 +9143,7 @@ package android.content {
field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -10703,9 +10710,11 @@ package android.content.pm {
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10748,6 +10757,7 @@ package android.content.pm {
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
@@ -10889,6 +10899,7 @@ package android.content.pm {
method public abstract boolean hasSystemFeature(java.lang.String);
method public abstract boolean hasSystemFeature(java.lang.String, int);
method public abstract boolean isInstantApp();
+ method public abstract boolean isInstantApp(java.lang.String);
method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public abstract boolean isSafeMode();
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -11073,8 +11084,11 @@ package android.content.pm {
field public static final int INSTALL_PARSE_FAILED_NOT_APK = -100; // 0xffffff9c
field public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; // 0xffffff99
field public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; // 0xffffff9a
+ field public static final int INSTALL_REASON_DEVICE_RESTORE = 2; // 0x2
+ field public static final int INSTALL_REASON_DEVICE_SETUP = 3; // 0x3
field public static final int INSTALL_REASON_POLICY = 1; // 0x1
field public static final int INSTALL_REASON_UNKNOWN = 0; // 0x0
+ field public static final int INSTALL_REASON_USER = 4; // 0x4
field public static final int INSTALL_SUCCEEDED = 1; // 0x1
field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS = 2; // 0x2
field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK = 4; // 0x4
@@ -11222,6 +11236,7 @@ package android.content.pm {
field public android.content.pm.ActivityInfo activityInfo;
field public android.content.IntentFilter filter;
field public int icon;
+ field public boolean instantAppAvailable;
field public boolean isDefault;
field public int labelRes;
field public int match;
@@ -14458,12 +14473,12 @@ package android.graphics.drawable {
}
public final class Icon implements android.os.Parcelable {
+ method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithContentUri(java.lang.String);
method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
- method public static android.graphics.drawable.Icon createWithMaskableBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
method public int describeContents();
@@ -25962,23 +25977,86 @@ package android.media.tv {
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final android.net.Uri buildWatchNextProgramUri(long);
method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
method public static final boolean isChannelUriForTunerInput(android.net.Uri);
method public static final boolean isProgramUri(android.net.Uri);
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+ field public static final java.lang.String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String AUTHORITY = "android.media.tv";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
field public static final java.lang.String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
field public static final java.lang.String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
field public static final java.lang.String EXTRA_EXISTING_COLUMN_NAMES = "android.media.tv.extra.EXISTING_COLUMN_NAMES";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+ field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
field public static final java.lang.String METHOD_ADD_COLUMN = "add_column";
field public static final java.lang.String METHOD_GET_COLUMNS = "get_columns";
}
+ public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+ field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TRANSIENT = "transient";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+ }
+
public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
@@ -26087,70 +26165,17 @@ package android.media.tv {
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseProgramColumns {
- field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
- field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
- field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
- field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
- field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
- field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
- field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
- field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
- field public static final java.lang.String COLUMN_AUTHOR = "author";
- field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
- field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
- field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
- field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
- field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
- field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
- field public static final java.lang.String COLUMN_LIVE = "live";
- field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
- field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
- field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
- field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
- field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
- field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
- field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
- field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
- field public static final java.lang.String COLUMN_TRANSIENT = "transient";
- field public static final java.lang.String COLUMN_TYPE = "type";
- field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
- field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
- field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
- field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
- field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
- field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
- field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
- field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
- field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
- field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
- field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
- field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
- field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
- field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
- field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
- field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
- field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
- field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
- field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
- field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
- field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
@@ -26186,6 +26211,7 @@ package android.media.tv {
public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
@@ -26198,6 +26224,19 @@ package android.media.tv {
field public static final android.net.Uri CONTENT_URI;
}
+ public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ ctor public TvContract.WatchNextPrograms();
+ field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+ field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+ }
+
public static final class TvContract.WatchedPrograms implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
@@ -26327,15 +26366,10 @@ package android.media.tv {
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
- field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
- field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
- field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -27011,6 +27045,73 @@ package android.net {
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public void removeTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform buildTunnelModeTransform(java.net.InetAddress, java.net.InetAddress);
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setNattKeepalive(int);
+ method public android.net.IpSecTransform.Builder setSpi(int, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ method public android.net.IpSecTransform.Builder setUnderlyingNetwork(android.net.Network);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -32634,12 +32735,12 @@ package android.os {
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
- field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
field public static final int BATTERY_PROPERTY_CURRENT_NOW = 2; // 0x2
field public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5; // 0x5
+ field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
field public static final int BATTERY_STATUS_CHARGING = 2; // 0x2
field public static final int BATTERY_STATUS_DISCHARGING = 3; // 0x3
field public static final int BATTERY_STATUS_FULL = 5; // 0x5
@@ -39242,7 +39343,6 @@ package android.security.keystore {
field public static final int PURPOSE_ENCRYPT = 1; // 0x1
field public static final int PURPOSE_SIGN = 4; // 0x4
field public static final int PURPOSE_VERIFY = 8; // 0x8
- field public static final int PURPOSE_WRAP_KEY = 16; // 0x10
field public static final java.lang.String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS";
}
@@ -39827,6 +39927,7 @@ package android.service.quicksettings {
method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
+ field public static final java.lang.String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
field public static final java.lang.String META_DATA_ACTIVE_TILE = "android.service.quicksettings.ACTIVE_TILE";
}
@@ -41189,6 +41290,7 @@ package android.telecom {
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
+ field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
field public static final int PROPERTY_WIFI = 8; // 0x8
}
@@ -41206,9 +41308,6 @@ package android.telecom {
field public static final int RTT_MODE_VCO = 3; // 0x3
}
- public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
- }
-
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -41951,6 +42050,7 @@ package android.telecom {
method public boolean handleMmi(java.lang.String);
method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
method public boolean isInCall();
+ method public boolean isInManagedCall();
method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle);
method public boolean isOutgoingCallPermitted(android.telecom.PhoneAccountHandle);
method public boolean isRinging();
@@ -41994,6 +42094,7 @@ package android.telecom {
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
+ field public static final java.lang.String METADATA_INCLUDE_SELF_MANAGED_CALLS = "android.telecom.INCLUDE_SELF_MANAGED_CALLS";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -42514,7 +42615,9 @@ package android.telephony {
method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
+ method public void sendMultipartTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>);
method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+ method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
@@ -42722,6 +42825,7 @@ package android.telephony {
method public java.lang.String getDeviceId();
method public java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
+ method public java.lang.String[] getForbiddenPlmns();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getIccAuthentication(int, int, java.lang.String);
method public java.lang.String getImei();
@@ -43621,6 +43725,7 @@ package android.test.mock {
method public boolean hasSystemFeature(java.lang.String);
method public boolean hasSystemFeature(java.lang.String, int);
method public boolean isInstantApp();
+ method public boolean isInstantApp(java.lang.String);
method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public boolean isSafeMode();
method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -49189,6 +49294,7 @@ package android.view {
method public abstract void setFocused(boolean);
method public abstract void setHint(java.lang.CharSequence);
method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String);
+ method public abstract void setInputType(int);
method public abstract void setLongClickable(boolean);
method public abstract void setSanitized(boolean);
method public abstract void setSelected(boolean);
@@ -50443,10 +50549,12 @@ package android.view.autofill {
public final class AutoFillType implements android.os.Parcelable {
method public int describeContents();
+ method public static android.view.autofill.AutoFillType forDate();
method public static android.view.autofill.AutoFillType forList();
method public static android.view.autofill.AutoFillType forText(int);
method public static android.view.autofill.AutoFillType forToggle();
method public int getSubType();
+ method public boolean isDate();
method public boolean isList();
method public boolean isText();
method public boolean isToggle();
@@ -50456,9 +50564,11 @@ package android.view.autofill {
public final class AutoFillValue implements android.os.Parcelable {
method public int describeContents();
+ method public static android.view.autofill.AutoFillValue forDate(long);
method public static android.view.autofill.AutoFillValue forList(int);
method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence);
method public static android.view.autofill.AutoFillValue forToggle(boolean);
+ method public long getDateValue();
method public int getListValue();
method public java.lang.CharSequence getTextValue();
method public boolean getToggleValue();
diff --git a/api/test-current.txt b/api/test-current.txt
index 5d497fc7d008..5e4911c39e39 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -16,6 +16,7 @@ package android {
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
+ field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -1004,7 +1005,7 @@ package android {
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
- field public static final int primaryContentAlpha = 16843367; // 0x1010267
+ field public static final int primaryContentAlpha = 16844117; // 0x1010555
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1060,7 +1061,9 @@ package android {
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
+ field public static final int requiredFeature = 16844119; // 0x1010557
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
+ field public static final int requiredNotFeature = 16844120; // 0x1010558
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1129,7 +1132,7 @@ package android {
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
- field public static final int secondaryContentAlpha = 16843688; // 0x10103a8
+ field public static final int secondaryContentAlpha = 16844118; // 0x1010556
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -4153,6 +4156,7 @@ package android.app {
field public static final int MODE_ERRORED = 2; // 0x2
field public static final int MODE_IGNORED = 1; // 0x1
field public static final java.lang.String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
+ field public static final java.lang.String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
field public static final java.lang.String OPSTR_BODY_SENSORS = "android:body_sensors";
field public static final java.lang.String OPSTR_CALL_PHONE = "android:call_phone";
field public static final java.lang.String OPSTR_CAMERA = "android:camera";
@@ -5490,6 +5494,7 @@ package android.app {
public final class NotificationChannel implements android.os.Parcelable {
ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
+ ctor public NotificationChannel(java.lang.String, int, int);
ctor protected NotificationChannel(android.os.Parcel);
method public boolean canBypassDnd();
method public boolean canShowBadge();
@@ -5503,6 +5508,7 @@ package android.app {
method public int getLightColor();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
+ method public int getNameResId();
method public android.net.Uri getSound();
method public long[] getVibrationPattern();
method public void setBypassDnd(boolean);
@@ -6589,6 +6595,7 @@ package android.app.assist {
method public java.lang.String getIdEntry();
method public java.lang.String getIdPackage();
method public java.lang.String getIdType();
+ method public int getInputType();
method public int getLeft();
method public int getScrollX();
method public int getScrollY();
@@ -8702,6 +8709,7 @@ package android.content {
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -10198,9 +10206,11 @@ package android.content.pm {
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10243,6 +10253,7 @@ package android.content.pm {
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
@@ -10373,6 +10384,7 @@ package android.content.pm {
method public abstract boolean hasSystemFeature(java.lang.String);
method public abstract boolean hasSystemFeature(java.lang.String, int);
method public abstract boolean isInstantApp();
+ method public abstract boolean isInstantApp(java.lang.String);
method public abstract boolean isPermissionReviewModeEnabled();
method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public abstract boolean isSafeMode();
@@ -10505,8 +10517,11 @@ package android.content.pm {
field public static final int GET_SIGNATURES = 64; // 0x40
field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
+ field public static final int INSTALL_REASON_DEVICE_RESTORE = 2; // 0x2
+ field public static final int INSTALL_REASON_DEVICE_SETUP = 3; // 0x3
field public static final int INSTALL_REASON_POLICY = 1; // 0x1
field public static final int INSTALL_REASON_UNKNOWN = 0; // 0x0
+ field public static final int INSTALL_REASON_USER = 4; // 0x4
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
field public static final int MATCH_DIRECT_BOOT_AWARE = 524288; // 0x80000
@@ -10636,6 +10651,7 @@ package android.content.pm {
field public android.content.pm.ActivityInfo activityInfo;
field public android.content.IntentFilter filter;
field public int icon;
+ field public boolean instantAppAvailable;
field public boolean isDefault;
field public int labelRes;
field public int match;
@@ -13860,12 +13876,12 @@ package android.graphics.drawable {
}
public final class Icon implements android.os.Parcelable {
+ method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithContentUri(java.lang.String);
method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
- method public static android.graphics.drawable.Icon createWithMaskableBitmap(android.graphics.Bitmap);
method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
method public int describeContents();
@@ -24228,17 +24244,79 @@ package android.media.tv {
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final android.net.Uri buildWatchNextProgramUri(long);
method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
method public static final boolean isChannelUriForTunerInput(android.net.Uri);
method public static final boolean isProgramUri(android.net.Uri);
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+ field public static final java.lang.String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String AUTHORITY = "android.media.tv";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+ field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+ }
+
+ public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+ field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
}
public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
@@ -24344,69 +24422,17 @@ package android.media.tv {
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseProgramColumns {
- field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
- field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
- field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
- field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
- field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
- field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
- field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
- field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
- field public static final java.lang.String COLUMN_AUTHOR = "author";
- field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
- field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
- field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
- field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
- field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
- field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
- field public static final java.lang.String COLUMN_LIVE = "live";
- field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
- field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
- field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
- field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
- field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
- field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
- field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
- field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
- field public static final java.lang.String COLUMN_TYPE = "type";
- field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
- field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
- field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
- field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
- field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
- field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
- field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
- field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
- field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
- field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
- field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
- field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
- field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
- field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
- field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
- field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
- field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
- field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
- field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
- field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
- field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
@@ -24442,6 +24468,7 @@ package android.media.tv {
public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
@@ -24454,6 +24481,19 @@ package android.media.tv {
field public static final android.net.Uri CONTENT_URI;
}
+ public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ ctor public TvContract.WatchNextPrograms();
+ field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+ field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+ }
+
public final class TvInputInfo implements android.os.Parcelable {
method public boolean canRecord();
method public android.content.Intent createSettingsIntent();
@@ -24503,15 +24543,10 @@ package android.media.tv {
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
- field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
- field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
- field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -25083,6 +25118,68 @@ package android.net {
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -30133,12 +30230,12 @@ package android.os {
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
- field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
field public static final int BATTERY_PROPERTY_CURRENT_NOW = 2; // 0x2
field public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5; // 0x5
+ field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
field public static final int BATTERY_STATUS_CHARGING = 2; // 0x2
field public static final int BATTERY_STATUS_DISCHARGING = 3; // 0x3
field public static final int BATTERY_STATUS_FULL = 5; // 0x5
@@ -36462,7 +36559,6 @@ package android.security.keystore {
field public static final int PURPOSE_ENCRYPT = 1; // 0x1
field public static final int PURPOSE_SIGN = 4; // 0x4
field public static final int PURPOSE_VERIFY = 8; // 0x8
- field public static final int PURPOSE_WRAP_KEY = 16; // 0x10
field public static final java.lang.String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS";
}
@@ -37018,6 +37114,7 @@ package android.service.quicksettings {
method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
+ field public static final java.lang.String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
field public static final java.lang.String META_DATA_ACTIVE_TILE = "android.service.quicksettings.ACTIVE_TILE";
}
@@ -38327,6 +38424,7 @@ package android.telecom {
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
+ field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
field public static final int PROPERTY_WIFI = 8; // 0x8
}
@@ -38340,9 +38438,6 @@ package android.telecom {
field public static final int RTT_MODE_VCO = 3; // 0x3
}
- public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
- }
-
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -38883,6 +38978,8 @@ package android.telecom {
}
public class TelecomManager {
+ method public void acceptRingingCall();
+ method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
@@ -38897,6 +38994,7 @@ package android.telecom {
method public boolean handleMmi(java.lang.String);
method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
method public boolean isInCall();
+ method public boolean isInManagedCall();
method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle);
method public boolean isOutgoingCallPermitted(android.telecom.PhoneAccountHandle);
method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
@@ -38933,6 +39031,7 @@ package android.telecom {
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
+ field public static final java.lang.String METADATA_INCLUDE_SELF_MANAGED_CALLS = "android.telecom.INCLUDE_SELF_MANAGED_CALLS";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -39620,6 +39719,7 @@ package android.telephony {
method public java.lang.String getDeviceId();
method public java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
+ method public java.lang.String[] getForbiddenPlmns();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getIccAuthentication(int, int, java.lang.String);
method public java.lang.String getLine1Number();
@@ -40471,6 +40571,7 @@ package android.test.mock {
method public boolean hasSystemFeature(java.lang.String);
method public boolean hasSystemFeature(java.lang.String, int);
method public boolean isInstantApp();
+ method public boolean isInstantApp(java.lang.String);
method public boolean isPermissionReviewModeEnabled();
method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public boolean isSafeMode();
@@ -46207,6 +46308,7 @@ package android.view {
method public abstract void setFocused(boolean);
method public abstract void setHint(java.lang.CharSequence);
method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String);
+ method public abstract void setInputType(int);
method public abstract void setLongClickable(boolean);
method public abstract void setSanitized(boolean);
method public abstract void setSelected(boolean);
@@ -47460,10 +47562,12 @@ package android.view.autofill {
public final class AutoFillType implements android.os.Parcelable {
method public int describeContents();
+ method public static android.view.autofill.AutoFillType forDate();
method public static android.view.autofill.AutoFillType forList();
method public static android.view.autofill.AutoFillType forText(int);
method public static android.view.autofill.AutoFillType forToggle();
method public int getSubType();
+ method public boolean isDate();
method public boolean isList();
method public boolean isText();
method public boolean isToggle();
@@ -47473,9 +47577,11 @@ package android.view.autofill {
public final class AutoFillValue implements android.os.Parcelable {
method public int describeContents();
+ method public static android.view.autofill.AutoFillValue forDate(long);
method public static android.view.autofill.AutoFillValue forList(int);
method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence);
method public static android.view.autofill.AutoFillValue forToggle(boolean);
+ method public long getDateValue();
method public int getListValue();
method public java.lang.CharSequence getTextValue();
method public boolean getToggleValue();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 1aef3639e449..91520f1a7d8e 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -547,6 +547,12 @@ public final class Pm {
throw new IllegalArgumentException("Missing inherit package name");
}
break;
+ case "--pkg":
+ sessionParams.appPackageName = nextOptionData();
+ if (sessionParams.appPackageName == null) {
+ throw new IllegalArgumentException("Missing package name");
+ }
+ break;
case "-S":
final long sizeBytes = Long.parseLong(nextOptionData());
if (sizeBytes <= 0) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 6dd31a852172..0f2ce3c09f00 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -249,8 +249,10 @@ public class AppOpsManager {
public static final int OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE = 67;
/** @hide Instant app start foreground service. */
public static final int OP_INSTANT_APP_START_FOREGROUND = 68;
+ /** @hide Answer incoming phone calls */
+ public static final int OP_ANSWER_PHONE_CALLS = 69;
/** @hide */
- public static final int _NUM_OP = 69;
+ public static final int _NUM_OP = 70;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -356,6 +358,9 @@ public class AppOpsManager {
/** @hide */
public static final String OPSTR_INSTANT_APP_START_FOREGROUND
= "android:instant_app_start_foreground";
+ /** Answer incoming phone calls */
+ public static final String OPSTR_ANSWER_PHONE_CALLS
+ = "android:answer_phone_calls";
private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
// RUNTIME PERMISSIONS
@@ -388,6 +393,7 @@ public class AppOpsManager {
OP_ADD_VOICEMAIL,
OP_USE_SIP,
OP_PROCESS_OUTGOING_CALLS,
+ OP_ANSWER_PHONE_CALLS,
// Microphone
OP_RECORD_AUDIO,
// Camera
@@ -480,6 +486,7 @@ public class AppOpsManager {
OP_REQUEST_INSTALL_PACKAGES,
OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE,
OP_INSTANT_APP_START_FOREGROUND,
+ OP_ANSWER_PHONE_CALLS
};
/**
@@ -556,6 +563,7 @@ public class AppOpsManager {
null, // OP_REQUEST_INSTALL_PACKAGES
null,
OPSTR_INSTANT_APP_START_FOREGROUND,
+ OPSTR_ANSWER_PHONE_CALLS,
};
/**
@@ -632,6 +640,7 @@ public class AppOpsManager {
"REQUEST_INSTALL_PACKAGES",
"OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE",
"INSTANT_APP_START_FOREGROUND",
+ "ANSWER_PHONE_CALLS",
};
/**
@@ -708,6 +717,7 @@ public class AppOpsManager {
Manifest.permission.REQUEST_INSTALL_PACKAGES,
null, // no permission for entering picture-in-picture on hide
Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
+ Manifest.permission.ANSWER_PHONE_CALLS,
};
/**
@@ -785,6 +795,7 @@ public class AppOpsManager {
null, // REQUEST_INSTALL_PACKAGES
null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
null, // INSTANT_APP_START_FOREGROUND
+ null, // ANSWER_PHONE_CALLS
};
/**
@@ -861,6 +872,7 @@ public class AppOpsManager {
false, // REQUEST_INSTALL_PACKAGES
false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
false, // INSTANT_APP_START_FOREGROUND
+ false, // ANSWER_PHONE_CALLS
};
/**
@@ -936,6 +948,7 @@ public class AppOpsManager {
AppOpsManager.MODE_DEFAULT, // OP_REQUEST_INSTALL_PACKAGES
AppOpsManager.MODE_ALLOWED, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE
AppOpsManager.MODE_DEFAULT, // OP_INSTANT_APP_START_FOREGROUND
+ AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS
};
/**
@@ -1015,6 +1028,7 @@ public class AppOpsManager {
false, // OP_REQUEST_INSTALL_PACKAGES
false, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE
false,
+ false, // ANSWER_PHONE_CALLS
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0608acbd6ca0..64e2d49d274b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -805,9 +805,13 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public boolean isInstantApp() {
+ return isInstantApp(mContext.getPackageName());
+ }
+
+ @Override
+ public boolean isInstantApp(String packageName) {
try {
- return mPM.isInstantApp(mContext.getPackageName(),
- mContext.getUserId());
+ return mPM.isInstantApp(packageName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7ee93d0ee790..0ab4b808af95 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2254,11 +2254,10 @@ class ContextImpl extends Context {
}
void setResources(Resources r) {
- if (mPackageInfo.getTargetSdkVersion() < VERSION_CODES.O) {
- mResources = new CompatResources(r, this);
- } else {
- mResources = r;
+ if (r instanceof CompatResources) {
+ ((CompatResources) r).setContext(this);
}
+ mResources = r;
}
void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java
index f62ab8d76c3c..780a9227cecc 100644
--- a/core/java/android/app/FragmentTransition.java
+++ b/core/java/android/app/FragmentTransition.java
@@ -780,8 +780,10 @@ class FragmentTransition {
names = inTransaction.mSharedElementTargetNames;
}
- inSharedElements.retainAll(names);
- if (sharedElementCallback != null) {
+ if (names != null) {
+ inSharedElements.retainAll(names);
+ }
+ if (names != null && sharedElementCallback != null) {
sharedElementCallback.onMapSharedElements(names, inSharedElements);
for (int i = names.size() - 1; i >= 0; i--) {
String name = names.get(i);
@@ -830,8 +832,9 @@ class FragmentTransition {
FragmentContainerTransition fragments,
Transition enterTransition, boolean inIsPop) {
BackStackRecord inTransaction = fragments.lastInTransaction;
- if (enterTransition != null && inTransaction.mSharedElementSourceNames != null &&
- !inTransaction.mSharedElementSourceNames.isEmpty()) {
+ if (enterTransition != null && inSharedElements != null
+ && inTransaction.mSharedElementSourceNames != null
+ && !inTransaction.mSharedElementSourceNames.isEmpty()) {
final String targetName = inIsPop
? inTransaction.mSharedElementSourceNames.get(0)
: inTransaction.mSharedElementTargetNames.get(0);
@@ -1096,7 +1099,9 @@ class FragmentTransition {
if (transition != null) {
viewList = new ArrayList<>();
View root = fragment.getView();
- root.captureTransitioningViews(viewList);
+ if (root != null) {
+ root.captureTransitioningViews(viewList);
+ }
if (sharedElements != null) {
viewList.removeAll(sharedElements);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 64fc44b96ac1..34a45dd626e2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4040,15 +4040,23 @@ public class Notification implements Parcelable
}
/**
- * Construct a RemoteViews for the final notification header only
+ * Construct a RemoteViews for the final notification header only. This will not be
+ * colorized.
*
* @hide
*/
public RemoteViews makeNotificationHeader() {
+ Boolean colorized = (Boolean) mN.extras.get(EXTRA_COLORIZED);
+ mN.extras.putBoolean(EXTRA_COLORIZED, false);
RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(),
R.layout.notification_template_header);
resetNotificationHeader(header);
bindNotificationHeader(header, false /* ambient */);
+ if (colorized != null) {
+ mN.extras.putBoolean(EXTRA_COLORIZED, colorized);
+ } else {
+ mN.extras.remove(EXTRA_COLORIZED);
+ }
return header;
}
@@ -4167,8 +4175,6 @@ public class Notification implements Parcelable
mN.extras.putCharSequence(EXTRA_SUB_TEXT, newSummary);
}
}
- Boolean colorized = (Boolean) mN.extras.get(EXTRA_COLORIZED);
- mN.extras.putBoolean(EXTRA_COLORIZED, false);
RemoteViews header = makeNotificationHeader();
@@ -4177,11 +4183,6 @@ public class Notification implements Parcelable
} else {
mN.extras.remove(EXTRA_SUB_TEXT);
}
- if (colorized != null) {
- mN.extras.putBoolean(EXTRA_COLORIZED, colorized);
- } else {
- mN.extras.remove(EXTRA_COLORIZED);
- }
mN.color = color;
return header;
}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 1a516087a6e5..85e6b85c2beb 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -20,8 +20,10 @@ import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.annotation.SystemApi;
-import android.graphics.Color;
import android.media.AudioAttributes;
import android.net.Uri;
import android.os.Parcel;
@@ -45,6 +47,7 @@ public final class NotificationChannel implements Parcelable {
private static final String TAG_CHANNEL = "channel";
private static final String ATT_NAME = "name";
+ private static final String ATT_NAME_RES_ID = "name_res_id";
private static final String ATT_ID = "id";
private static final String ATT_DELETED = "deleted";
private static final String ATT_PRIORITY = "priority";
@@ -138,6 +141,7 @@ public final class NotificationChannel implements Parcelable {
private final String mId;
private CharSequence mName;
+ private int mNameResId = 0;
private int mImportance = DEFAULT_IMPORTANCE;
private boolean mBypassDnd;
private int mLockscreenVisibility = DEFAULT_VISIBILITY;
@@ -156,7 +160,9 @@ public final class NotificationChannel implements Parcelable {
* Creates a notification channel.
*
* @param id The id of the channel. Must be unique per package.
- * @param name The user visible name of the channel.
+ * @param name The user visible name of the channel. Unchangeable once created; use this
+ * constructor if the channel represents a user-defined category that does not
+ * need to be translated.
* @param importance The importance of the channel. This controls how interruptive notifications
* posted to this channel are. See e.g.
* {@link NotificationManager#IMPORTANCE_DEFAULT}.
@@ -167,6 +173,21 @@ public final class NotificationChannel implements Parcelable {
this.mImportance = importance;
}
+ /**
+ * Creates a notification channel.
+ *
+ * @param id The id of the channel. Must be unique per package.
+ * @param nameResId The resource id of the string containing the channel name.
+ * @param importance The importance of the channel. This controls how interruptive notifications
+ * posted to this channel are. See e.g.
+ * {@link NotificationManager#IMPORTANCE_DEFAULT}.
+ */
+ public NotificationChannel(String id, @StringRes int nameResId, int importance) {
+ this.mId = id;
+ this.mNameResId = nameResId;
+ this.mImportance = importance;
+ }
+
protected NotificationChannel(Parcel in) {
if (in.readByte() != 0) {
mId = in.readString();
@@ -174,6 +195,7 @@ public final class NotificationChannel implements Parcelable {
mId = null;
}
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mNameResId = in.readInt();
mImportance = in.readInt();
mBypassDnd = in.readByte() != 0;
mLockscreenVisibility = in.readInt();
@@ -206,6 +228,7 @@ public final class NotificationChannel implements Parcelable {
dest.writeByte((byte) 0);
}
TextUtils.writeToParcel(mName, dest, flags);
+ dest.writeInt(mNameResId);
dest.writeInt(mImportance);
dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0);
dest.writeInt(mLockscreenVisibility);
@@ -382,11 +405,18 @@ public final class NotificationChannel implements Parcelable {
/**
* Returns the user visible name of this channel.
*/
- public CharSequence getName() {
+ public @Nullable CharSequence getName() {
return mName;
}
/**
+ * Returns the resource id of the user visible name of this channel.
+ */
+ public int getNameResId() {
+ return mNameResId;
+ }
+
+ /**
* Returns the user specified importance {e.g. @link NotificationManager#IMPORTANCE_LOW} for
* notifications posted to this channel.
*/
@@ -516,7 +546,10 @@ public final class NotificationChannel implements Parcelable {
public void writeXml(XmlSerializer out) throws IOException {
out.startTag(null, TAG_CHANNEL);
out.attribute(null, ATT_ID, getId());
- out.attribute(null, ATT_NAME, getName().toString());
+ if (getName() != null) {
+ out.attribute(null, ATT_NAME, getName().toString());
+ }
+ out.attribute(null, ATT_NAME_RES_ID, Integer.toString(getNameResId()));
if (getImportance() != DEFAULT_IMPORTANCE) {
out.attribute(
null, ATT_IMPORTANCE, Integer.toString(getImportance()));
@@ -574,6 +607,7 @@ public final class NotificationChannel implements Parcelable {
JSONObject record = new JSONObject();
record.put(ATT_ID, getId());
record.put(ATT_NAME, getName());
+ record.put(ATT_NAME_RES_ID, getNameResId());
if (getImportance() != DEFAULT_IMPORTANCE) {
record.put(ATT_IMPORTANCE,
NotificationListenerService.Ranking.importanceToString(getImportance()));
@@ -691,6 +725,7 @@ public final class NotificationChannel implements Parcelable {
NotificationChannel that = (NotificationChannel) o;
+ if (getNameResId() != that.getNameResId()) return false;
if (getImportance() != that.getImportance()) return false;
if (mBypassDnd != that.mBypassDnd) return false;
if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false;
@@ -720,6 +755,7 @@ public final class NotificationChannel implements Parcelable {
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + getNameResId();
result = 31 * result + getImportance();
result = 31 * result + (mBypassDnd ? 1 : 0);
result = 31 * result + getLockscreenVisibility();
@@ -741,6 +777,7 @@ public final class NotificationChannel implements Parcelable {
return "NotificationChannel{" +
"mId='" + mId + '\'' +
", mName=" + mName +
+ ", mNameResId=" + mNameResId +
", mImportance=" + mImportance +
", mBypassDnd=" + mBypassDnd +
", mLockscreenVisibility=" + mLockscreenVisibility +
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 5205959361a5..d37e2099c1d7 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -447,6 +447,19 @@ public class NotificationManager
}
/**
+ * @hide
+ */
+ public void createNotificationChannelsForPackage(String pkg,
+ @NonNull List<NotificationChannel> channels) {
+ INotificationManager service = getService();
+ try {
+ service.createNotificationChannels(pkg, new ParceledListSlice(channels));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the notification channel settings for a given channel id.
*/
public NotificationChannel getNotificationChannel(String channelId) {
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 52ec045d5b60..b42df5e2e0fb 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import android.content.res.AssetManager;
+import android.content.res.CompatResources;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -447,7 +448,8 @@ public class ResourcesManager {
* or the class loader is different.
*/
private @NonNull Resources getOrCreateResourcesForActivityLocked(@NonNull IBinder activityToken,
- @NonNull ClassLoader classLoader, @NonNull ResourcesImpl impl) {
+ @NonNull ClassLoader classLoader, @NonNull ResourcesImpl impl,
+ @NonNull CompatibilityInfo compatInfo) {
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
activityToken);
@@ -466,7 +468,8 @@ public class ResourcesManager {
}
}
- Resources resources = new Resources(classLoader);
+ Resources resources = compatInfo.needsCompatResources() ? new CompatResources(classLoader)
+ : new Resources(classLoader);
resources.setImpl(impl);
activityResources.activityResources.add(new WeakReference<>(resources));
if (DEBUG) {
@@ -481,7 +484,7 @@ public class ResourcesManager {
* otherwise creates a new Resources object.
*/
private @NonNull Resources getOrCreateResourcesLocked(@NonNull ClassLoader classLoader,
- @NonNull ResourcesImpl impl) {
+ @NonNull ResourcesImpl impl, @NonNull CompatibilityInfo compatInfo) {
// Find an existing Resources that has this ResourcesImpl set.
final int refCount = mResourceReferences.size();
for (int i = 0; i < refCount; i++) {
@@ -498,7 +501,8 @@ public class ResourcesManager {
}
// Create a new Resources reference and use the existing ResourcesImpl object.
- Resources resources = new Resources(classLoader);
+ Resources resources = compatInfo.needsCompatResources() ? new CompatResources(classLoader)
+ : new Resources(classLoader);
resources.setImpl(impl);
mResourceReferences.add(new WeakReference<>(resources));
if (DEBUG) {
@@ -614,7 +618,7 @@ public class ResourcesManager {
Slog.d(TAG, "- using existing impl=" + resourcesImpl);
}
return getOrCreateResourcesForActivityLocked(activityToken, classLoader,
- resourcesImpl);
+ resourcesImpl, key.mCompatInfo);
}
// We will create the ResourcesImpl object outside of holding this lock.
@@ -629,7 +633,7 @@ public class ResourcesManager {
if (DEBUG) {
Slog.d(TAG, "- using existing impl=" + resourcesImpl);
}
- return getOrCreateResourcesLocked(classLoader, resourcesImpl);
+ return getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
}
// We will create the ResourcesImpl object outside of holding this lock.
@@ -659,9 +663,9 @@ public class ResourcesManager {
final Resources resources;
if (activityToken != null) {
resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
- resourcesImpl);
+ resourcesImpl, key.mCompatInfo);
} else {
- resources = getOrCreateResourcesLocked(classLoader, resourcesImpl);
+ resources = getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
}
return resources;
}
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 483a7a121a9e..d1b2a158979c 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -26,6 +26,7 @@ import android.view.autofill.AutoFillType;
import android.view.autofill.AutoFillValue;
import java.util.ArrayList;
+import java.util.Arrays;
/**
* Assist data automatically created by the platform's implementation
@@ -533,6 +534,7 @@ public class AssistStructure implements Parcelable {
String mIdPackage;
String mIdType;
String mIdEntry;
+
// TODO(b/33197203): once we have more flags, it might be better to store the individual
// fields (viewId and childId) of the field.
AutoFillId mAutoFillId;
@@ -540,6 +542,7 @@ public class AssistStructure implements Parcelable {
AutoFillValue mAutoFillValue;
String[] mAutoFillOptions;
boolean mSanitized;
+
int mX;
int mY;
int mScrollX;
@@ -581,6 +584,7 @@ public class AssistStructure implements Parcelable {
static final int FLAGS_HAS_ID = 0x00200000;
static final int FLAGS_HAS_CHILDREN = 0x00100000;
static final int FLAGS_HAS_URL = 0x00080000;
+ static final int FLAGS_HAS_INPUT_TYPE = 0x00040000;
static final int FLAGS_ALL_CONTROL = 0xfff00000;
int mFlags;
@@ -589,6 +593,7 @@ public class AssistStructure implements Parcelable {
CharSequence mContentDescription;
ViewNodeText mText;
+ int mInputType;
String mUrl;
Bundle mExtras;
@@ -655,6 +660,9 @@ public class AssistStructure implements Parcelable {
if ((flags&FLAGS_HAS_TEXT) != 0) {
mText = new ViewNodeText(in, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0);
}
+ if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
+ mInputType = in.readInt();
+ }
if ((flags&FLAGS_HAS_URL) != 0) {
mUrl = in.readString();
}
@@ -711,6 +719,9 @@ public class AssistStructure implements Parcelable {
flags |= FLAGS_HAS_COMPLEX_TEXT;
}
}
+ if (mInputType != 0) {
+ flags |= FLAGS_HAS_INPUT_TYPE;
+ }
if (mUrl != null) {
flags |= FLAGS_HAS_URL;
}
@@ -778,6 +789,10 @@ public class AssistStructure implements Parcelable {
if ((flags&FLAGS_HAS_TEXT) != 0) {
mText.writeToParcel(out, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0, writeSensitive);
}
+ if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
+ out.writeInt(mInputType);
+ }
+
if ((flags&FLAGS_HAS_URL) != 0) {
out.writeString(mUrl);
}
@@ -867,6 +882,15 @@ public class AssistStructure implements Parcelable {
return mAutoFillOptions;
}
+ /**
+ * Gets the {@link android.text.InputType} bits of this structure.
+ *
+ * @return bits as defined by {@link android.text.InputType}.
+ */
+ public int getInputType() {
+ return mInputType;
+ }
+
/** @hide */
public boolean isSanitized() {
return mSanitized;
@@ -1534,6 +1558,11 @@ public class AssistStructure implements Parcelable {
mNode.mAutoFillOptions = options;
}
+ @Override
+ public void setInputType(int inputType) {
+ mNode.mInputType = inputType;
+ }
+
/**
* @hide
*/
@@ -1664,6 +1693,8 @@ public class AssistStructure implements Parcelable {
} else {
Log.i(TAG, prefix + "AutoFill info: id= " + autoFillId
+ ", type=" + node.getAutoFillType()
+ + ", options=" + Arrays.toString(node.getAutoFillOptions())
+ + ", inputType=" + node.getInputType()
+ ", value=" + node.getAutoFillValue()
+ ", sanitized=" + node.isSanitized());
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index be49f24027f2..9958a79ea3ee 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1898,7 +1898,7 @@ public abstract class ContentResolver {
ContentProvider.getUriWithoutUserId(uri),
notifyForDescendants,
observer,
- ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
+ ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
}
/** @hide - designated user version */
@@ -1982,7 +1982,7 @@ public abstract class ContentResolver {
ContentProvider.getUriWithoutUserId(uri),
observer,
syncToNetwork,
- ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
+ ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
}
/**
@@ -2016,7 +2016,7 @@ public abstract class ContentResolver {
ContentProvider.getUriWithoutUserId(uri),
observer,
flags,
- ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
+ ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
}
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index aff00c3e84b6..de503c0f5499 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2711,6 +2711,7 @@ public abstract class Context {
VIBRATOR_SERVICE,
//@hide: STATUS_BAR_SERVICE,
CONNECTIVITY_SERVICE,
+ IPSEC_SERVICE,
//@hide: UPDATE_LOCK_SERVICE,
//@hide: NETWORKMANAGEMENT_SERVICE,
NETWORK_STATS_SERVICE,
@@ -2814,6 +2815,9 @@ public abstract class Context {
* <dt> {@link #CONNECTIVITY_SERVICE} ("connection")
* <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
* handling management of network connections.
+ * <dt> {@link #IPSEC_SERVICE} ("ipsec")
+ * <dd> A {@link android.net.IpSecManager IpSecManager} for managing IPSec on
+ * sockets and networks.
* <dt> {@link #WIFI_SERVICE} ("wifi")
* <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
* connectivity. On releases before NYC, it should only be obtained from an application
@@ -3154,6 +3158,15 @@ public abstract class Context {
public static final String CONNECTIVITY_SERVICE = "connectivity";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
+ * IPSec.
+ *
+ * @see #getSystemService
+ */
+ public static final String IPSEC_SERVICE = "ipsec";
+
+ /**
* Use with {@link #getSystemService} to retrieve a {@link
* android.os.IUpdateLock} for managing runtime sequences that
* must not be interrupted by headless OTA application or similar.
diff --git a/core/java/android/content/pm/BaseParceledListSlice.java b/core/java/android/content/pm/BaseParceledListSlice.java
new file mode 100644
index 000000000000..c4e4e06be749
--- /dev/null
+++ b/core/java/android/content/pm/BaseParceledListSlice.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011 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.content.pm;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Transfer a large list of Parcelable objects across an IPC. Splits into
+ * multiple transactions if needed.
+ *
+ * Caveat: for efficiency and security, all elements must be the same concrete type.
+ * In order to avoid writing the class name of each object, we must ensure that
+ * each object is the same type, or else unparceling then reparceling the data may yield
+ * a different result if the class name encoded in the Parcelable is a Base type.
+ * See b/17671747.
+ *
+ * @hide
+ */
+abstract class BaseParceledListSlice<T> implements Parcelable {
+ private static String TAG = "ParceledListSlice";
+ private static boolean DEBUG = false;
+
+ /*
+ * TODO get this number from somewhere else. For now set it to a quarter of
+ * the 1MB limit.
+ */
+ private static final int MAX_IPC_SIZE = IBinder.MAX_IPC_SIZE;
+
+ private final List<T> mList;
+
+ public BaseParceledListSlice(List<T> list) {
+ mList = list;
+ }
+
+ @SuppressWarnings("unchecked")
+ BaseParceledListSlice(Parcel p, ClassLoader loader) {
+ final int N = p.readInt();
+ mList = new ArrayList<T>(N);
+ if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
+ if (N <= 0) {
+ return;
+ }
+
+ Parcelable.Creator<?> creator = readParcelableCreator(p, loader);
+ Class<?> listElementClass = null;
+
+ int i = 0;
+ while (i < N) {
+ if (p.readInt() == 0) {
+ break;
+ }
+
+ final T parcelable = readCreator(creator, p, loader);
+ if (listElementClass == null) {
+ listElementClass = parcelable.getClass();
+ } else {
+ verifySameType(listElementClass, parcelable.getClass());
+ }
+
+ mList.add(parcelable);
+
+ if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
+ i++;
+ }
+ if (i >= N) {
+ return;
+ }
+ final IBinder retriever = p.readStrongBinder();
+ while (i < N) {
+ if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInt(i);
+ try {
+ retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
+ return;
+ }
+ while (i < N && reply.readInt() != 0) {
+ final T parcelable = reply.readCreator(creator, loader);
+ verifySameType(listElementClass, parcelable.getClass());
+
+ mList.add(parcelable);
+
+ if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
+ i++;
+ }
+ reply.recycle();
+ data.recycle();
+ }
+ }
+
+ private T readCreator(Parcelable.Creator<?> creator, Parcel p, ClassLoader loader) {
+ if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
+ Parcelable.ClassLoaderCreator<?> classLoaderCreator =
+ (Parcelable.ClassLoaderCreator<?>) creator;
+ return (T) classLoaderCreator.createFromParcel(p, loader);
+ }
+ return (T) creator.createFromParcel(p);
+ }
+
+ private static void verifySameType(final Class<?> expected, final Class<?> actual) {
+ if (!actual.equals(expected)) {
+ throw new IllegalArgumentException("Can't unparcel type "
+ + actual.getName() + " in list of type "
+ + expected.getName());
+ }
+ }
+
+ public List<T> getList() {
+ return mList;
+ }
+
+ /**
+ * Write this to another Parcel. Note that this discards the internal Parcel
+ * and should not be used anymore. This is so we can pass this to a Binder
+ * where we won't have a chance to call recycle on this.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ final int N = mList.size();
+ final int callFlags = flags;
+ dest.writeInt(N);
+ if (DEBUG) Log.d(TAG, "Writing " + N + " items");
+ if (N > 0) {
+ final Class<?> listElementClass = mList.get(0).getClass();
+ writeParcelableCreator(mList.get(0), dest);
+ int i = 0;
+ while (i < N && dest.dataSize() < MAX_IPC_SIZE) {
+ dest.writeInt(1);
+
+ final T parcelable = mList.get(i);
+ verifySameType(listElementClass, parcelable.getClass());
+ writeElement(parcelable, dest, callFlags);
+
+ if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
+ i++;
+ }
+ if (i < N) {
+ dest.writeInt(0);
+ Binder retriever = new Binder() {
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ if (code != FIRST_CALL_TRANSACTION) {
+ return super.onTransact(code, data, reply, flags);
+ }
+ int i = data.readInt();
+ if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
+ while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
+ reply.writeInt(1);
+
+ final T parcelable = mList.get(i);
+ verifySameType(listElementClass, parcelable.getClass());
+ writeElement(parcelable, reply, callFlags);
+
+ if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
+ i++;
+ }
+ if (i < N) {
+ if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
+ reply.writeInt(0);
+ }
+ return true;
+ }
+ };
+ if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
+ dest.writeStrongBinder(retriever);
+ }
+ }
+ }
+
+ protected abstract void writeElement(T parcelable, Parcel reply, int callFlags);
+
+ protected abstract void writeParcelableCreator(T parcelable, Parcel dest);
+
+ protected abstract Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader);
+}
diff --git a/core/java/android/content/pm/InstantAppInfo.java b/core/java/android/content/pm/InstantAppInfo.java
index 898ee1101c07..67afc928fd78 100644
--- a/core/java/android/content/pm/InstantAppInfo.java
+++ b/core/java/android/content/pm/InstantAppInfo.java
@@ -75,7 +75,7 @@ public final class InstantAppInfo implements Parcelable {
}
/**
- * @return The pakcage name.
+ * @return The package name.
*/
public @NonNull String getPackageName() {
if (mApplicationInfo != null) {
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 776492a140c3..c3fd08932f77 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -829,7 +829,7 @@ public class LauncherApps {
final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
if (bmp != null) {
BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
- if (shortcut.hasMaskableBitmap()) {
+ if (shortcut.hasAdaptiveBitmap()) {
return new AdaptiveIconDrawable(null, dr);
} else {
return dr;
@@ -854,7 +854,7 @@ public class LauncherApps {
icon.getResId(), shortcut.getUserHandle(), density);
}
case Icon.TYPE_BITMAP:
- case Icon.TYPE_BITMAP_MASKABLE: {
+ case Icon.TYPE_ADAPTIVE_BITMAP: {
return icon.loadDrawable(mContext);
}
default:
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 278a6d09d9fe..9d04cc9bff5e 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -95,6 +95,18 @@ public class PackageInstaller {
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
+ /**
+ * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session
+ * for a new install is committed. For managed profile, this is sent to the default launcher
+ * of the primary profile.
+ * <p>
+ * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this
+ * session was created in {@link Intent#EXTRA_USER}.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SESSION_COMMITTED =
+ "android.content.pm.action.SESSION_COMMITTED";
+
/** {@hide} */
public static final String
ACTION_CONFIRM_PERMISSIONS = "android.content.pm.action.CONFIRM_PERMISSIONS";
@@ -107,6 +119,13 @@ public class PackageInstaller {
public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
/**
+ * {@link SessionInfo} that an operation is working with.
+ *
+ * @see Intent#getParcelableExtra(String)
+ */
+ public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
+
+ /**
* Package name that an operation is working with.
*
* @see Intent#getStringExtra(String)
@@ -1184,6 +1203,8 @@ public class PackageInstaller {
/** {@hide} */
public int mode;
/** {@hide} */
+ public int installReason;
+ /** {@hide} */
public long sizeBytes;
/** {@hide} */
public String appPackageName;
@@ -1206,6 +1227,7 @@ public class PackageInstaller {
active = source.readInt() != 0;
mode = source.readInt();
+ installReason = source.readInt();
sizeBytes = source.readLong();
appPackageName = source.readString();
appIcon = source.readParcelable(null);
@@ -1256,6 +1278,15 @@ public class PackageInstaller {
return active;
}
+ /**
+ * Return the reason for installing this package.
+ *
+ * @see PackageManager#INSTALL_REASON_UNKNOWN
+ */
+ public int getInstallReason() {
+ return installReason;
+ }
+
/** {@hide} */
@Deprecated
public boolean isOpen() {
@@ -1324,6 +1355,7 @@ public class PackageInstaller {
dest.writeInt(active ? 1 : 0);
dest.writeInt(mode);
+ dest.writeInt(installReason);
dest.writeLong(sizeBytes);
dest.writeString(appPackageName);
dest.writeParcelable(appIcon, flags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0482f5136b0c..b3b5bcfe79c0 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -745,7 +745,8 @@ public abstract class PackageManager {
public static final int DONT_KILL_APP = 0x00000001;
/** @hide */
- @IntDef({INSTALL_REASON_UNKNOWN, INSTALL_REASON_POLICY})
+ @IntDef({INSTALL_REASON_UNKNOWN, INSTALL_REASON_POLICY, INSTALL_REASON_DEVICE_RESTORE,
+ INSTALL_REASON_DEVICE_SETUP, INSTALL_REASON_USER})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallReason {}
@@ -760,6 +761,21 @@ public abstract class PackageManager {
public static final int INSTALL_REASON_POLICY = 1;
/**
+ * Code indicating that this package was installed as part of restoring from another device.
+ */
+ public static final int INSTALL_REASON_DEVICE_RESTORE = 2;
+
+ /**
+ * Code indicating that this package was installed as part of device setup.
+ */
+ public static final int INSTALL_REASON_DEVICE_SETUP = 3;
+
+ /**
+ * Code indicating that the package installation was initiated by the user.
+ */
+ public static final int INSTALL_REASON_USER = 4;
+
+ /**
* Installation return code: this is passed to the
* {@link IPackageInstallObserver} on success.
*
@@ -3737,10 +3753,11 @@ public abstract class PackageManager {
public abstract @Nullable Drawable getInstantAppIcon(String packageName);
/**
- * Gets whether the caller is an instant app.
+ * Gets whether this application is an instant app.
*
* @return Whether caller is an instant app.
*
+ * @see #isInstantApp(String)
* @see #setInstantAppCookie(byte[])
* @see #getInstantAppCookie()
* @see #getInstantAppCookieMaxSize()
@@ -3748,12 +3765,26 @@ public abstract class PackageManager {
public abstract boolean isInstantApp();
/**
+ * Gets whether the given package is an instant app.
+ *
+ * @param packageName The package to check
+ * @return Whether the given package is an instant app.
+ *
+ * @see #isInstantApp()
+ * @see #setInstantAppCookie(byte[])
+ * @see #getInstantAppCookie()
+ * @see #getInstantAppCookieMaxSize()
+ */
+ public abstract boolean isInstantApp(String packageName);
+
+ /**
* Gets the maximum size in bytes of the cookie data an instant app
* can store on the device.
*
* @return The max cookie size in bytes.
*
* @see #isInstantApp()
+ * @see #isInstantApp(String)
* @see #setInstantAppCookie(byte[])
* @see #getInstantAppCookie()
*/
@@ -3770,6 +3801,7 @@ public abstract class PackageManager {
* @return The cookie.
*
* @see #isInstantApp()
+ * @see #isInstantApp(String)
* @see #setInstantAppCookie(byte[])
* @see #getInstantAppCookieMaxSize()
*/
@@ -3792,6 +3824,7 @@ public abstract class PackageManager {
* @return Whether the cookie was set.
*
* @see #isInstantApp()
+ * @see #isInstantApp(String)
* @see #getInstantAppCookieMaxSize()
* @see #getInstantAppCookie()
*/
@@ -4983,6 +5016,7 @@ public abstract class PackageManager {
*/
public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) {
final PackageParser parser = new PackageParser();
+ parser.setCallback(new PackageParser.CallbackImpl(this));
final File apkFile = new File(archiveFilePath);
try {
if ((flags & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
@@ -6108,6 +6142,9 @@ public abstract class PackageManager {
*
* @see #INSTALL_REASON_UNKNOWN
* @see #INSTALL_REASON_POLICY
+ * @see #INSTALL_REASON_DEVICE_RESTORE
+ * @see #INSTALL_REASON_DEVICE_SETUP
+ * @see #INSTALL_REASON_USER
*
* @hide
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f801e4547658..60cc6b06bf11 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -285,6 +285,7 @@ public class PackageParser {
private String[] mSeparateProcesses;
private boolean mOnlyCoreApps;
private DisplayMetrics mMetrics;
+ private Callback mCallback;
private File mCacheDir;
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
@@ -506,6 +507,37 @@ public class PackageParser {
mCacheDir = cacheDir;
}
+ /**
+ * Callback interface for retrieving information that may be needed while parsing
+ * a package.
+ */
+ public interface Callback {
+ boolean hasFeature(String feature);
+ }
+
+ /**
+ * Standard implementation of {@link Callback} on top of the public {@link PackageManager}
+ * class.
+ */
+ public static final class CallbackImpl implements Callback {
+ private final PackageManager mPm;
+
+ public CallbackImpl(PackageManager pm) {
+ mPm = pm;
+ }
+
+ @Override public boolean hasFeature(String feature) {
+ return mPm.hasSystemFeature(feature);
+ }
+ }
+
+ /**
+ * Set the {@link Callback} that can be used while parsing.
+ */
+ public void setCallback(Callback cb) {
+ mCallback = cb;
+ }
+
public static final boolean isApkFile(File file) {
return isApkPath(file.getName());
}
@@ -2079,15 +2111,15 @@ public class PackageParser {
return null;
}
} else if (tagName.equals(TAG_PERMISSION_GROUP)) {
- if (parsePermissionGroup(pkg, flags, res, parser, outError) == null) {
+ if (!parsePermissionGroup(pkg, flags, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION)) {
- if (parsePermission(pkg, res, parser, outError) == null) {
+ if (!parsePermission(pkg, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION_TREE)) {
- if (parsePermissionTree(pkg, res, parser, outError) == null) {
+ if (!parsePermissionTree(pkg, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_USES_PERMISSION)) {
@@ -2708,22 +2740,44 @@ public class PackageParser {
}
}
+ final String requiredFeature = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
+
+ final String requiredNotfeature = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredNotFeature, 0);
+
sa.recycle();
- if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
- if (name != null) {
- int index = pkg.requestedPermissions.indexOf(name);
- if (index == -1) {
- pkg.requestedPermissions.add(name.intern());
- } else {
- Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
- + name + " in package: " + pkg.packageName + " at: "
- + parser.getPositionDescription());
- }
- }
+ XmlUtils.skipCurrentTag(parser);
+
+ if (name == null) {
+ return true;
+ }
+
+ if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
+ return true;
+ }
+
+ // Only allow requesting this permission if the platform supports the given feature.
+ if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(requiredFeature)) {
+ return true;
+ }
+
+ // Only allow requesting this permission if the platform doesn't support the given feature.
+ if (requiredNotfeature != null && mCallback != null
+ && mCallback.hasFeature(requiredNotfeature)) {
+ return true;
+ }
+
+ int index = pkg.requestedPermissions.indexOf(name);
+ if (index == -1) {
+ pkg.requestedPermissions.add(name.intern());
+ } else {
+ Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+ + name + " in package: " + pkg.packageName + " at: "
+ + parser.getPositionDescription());
}
- XmlUtils.skipCurrentTag(parser);
return true;
}
@@ -2951,7 +3005,7 @@ public class PackageParser {
return true;
}
- private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res,
+ private boolean parsePermissionGroup(Package owner, int flags, Resources res,
XmlResourceParser parser, String[] outError)
throws XmlPullParserException, IOException {
PermissionGroup perm = new PermissionGroup(owner);
@@ -2968,7 +3022,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
perm.info.descriptionRes = sa.getResourceId(
@@ -2987,22 +3041,22 @@ public class PackageParser {
if (!parseAllMetaData(res, parser, "<permission-group>", perm,
outError)) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
owner.permissionGroups.add(perm);
- return perm;
+ return true;
}
- private Permission parsePermission(Package owner, Resources res,
+ private boolean parsePermission(Package owner, Resources res,
XmlResourceParser parser, String[] outError)
throws XmlPullParserException, IOException {
- Permission perm = new Permission(owner);
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestPermission);
+ Permission perm = new Permission(owner);
if (!parsePackageItemInfo(owner, perm.info, outError,
"<permission>", sa, true /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestPermission_name,
@@ -3013,7 +3067,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
// Note: don't allow this value to be a reference to a resource
@@ -3040,7 +3094,7 @@ public class PackageParser {
if (perm.info.protectionLevel == -1) {
outError[0] = "<permission> does not specify protectionLevel";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
@@ -3052,21 +3106,21 @@ public class PackageParser {
outError[0] = "<permission> protectionLevel specifies a non-ephemeral flag but is "
+ "not based on signature type";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
}
if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
owner.permissions.add(perm);
- return perm;
+ return true;
}
- private Permission parsePermissionTree(Package owner, Resources res,
+ private boolean parsePermissionTree(Package owner, Resources res,
XmlResourceParser parser, String[] outError)
throws XmlPullParserException, IOException {
Permission perm = new Permission(owner);
@@ -3084,7 +3138,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
sa.recycle();
@@ -3097,7 +3151,7 @@ public class PackageParser {
outError[0] = "<permission-tree> name has less than three segments: "
+ perm.info.name;
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
perm.info.descriptionRes = 0;
@@ -3107,12 +3161,12 @@ public class PackageParser {
if (!parseAllMetaData(res, parser, "<permission-tree>", perm,
outError)) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
+ return false;
}
owner.permissions.add(perm);
- return perm;
+ return true;
}
private Instrumentation parseInstrumentation(Package owner, Resources res,
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index 945858e6d3c6..d12e8846aabb 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -16,14 +16,9 @@
package android.content.pm;
-import android.os.Binder;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -31,171 +26,46 @@ import java.util.List;
* Transfer a large list of Parcelable objects across an IPC. Splits into
* multiple transactions if needed.
*
- * Caveat: for efficiency and security, all elements must be the same concrete type.
- * In order to avoid writing the class name of each object, we must ensure that
- * each object is the same type, or else unparceling then reparceling the data may yield
- * a different result if the class name encoded in the Parcelable is a Base type.
- * See b/17671747.
+ * @see BaseParceledListSlice
*
* @hide
*/
-public class ParceledListSlice<T extends Parcelable> implements Parcelable {
- private static String TAG = "ParceledListSlice";
- private static boolean DEBUG = false;
-
- /*
- * TODO get this number from somewhere else. For now set it to a quarter of
- * the 1MB limit.
- */
- private static final int MAX_IPC_SIZE = IBinder.MAX_IPC_SIZE;
-
- private final List<T> mList;
-
- public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
- return new ParceledListSlice<T>(Collections.<T> emptyList());
- }
-
+public class ParceledListSlice<T extends Parcelable> extends BaseParceledListSlice<T> {
public ParceledListSlice(List<T> list) {
- mList = list;
- }
-
- @SuppressWarnings("unchecked")
- private ParceledListSlice(Parcel p, ClassLoader loader) {
- final int N = p.readInt();
- mList = new ArrayList<T>(N);
- if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
- if (N <= 0) {
- return;
- }
-
- Parcelable.Creator<?> creator = p.readParcelableCreator(loader);
- Class<?> listElementClass = null;
-
- int i = 0;
- while (i < N) {
- if (p.readInt() == 0) {
- break;
- }
-
- final T parcelable = p.readCreator(creator, loader);
- if (listElementClass == null) {
- listElementClass = parcelable.getClass();
- } else {
- verifySameType(listElementClass, parcelable.getClass());
- }
-
- mList.add(parcelable);
-
- if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
- i++;
- }
- if (i >= N) {
- return;
- }
- final IBinder retriever = p.readStrongBinder();
- while (i < N) {
- if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInt(i);
- try {
- retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
- return;
- }
- while (i < N && reply.readInt() != 0) {
- final T parcelable = reply.readCreator(creator, loader);
- verifySameType(listElementClass, parcelable.getClass());
-
- mList.add(parcelable);
-
- if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
- i++;
- }
- reply.recycle();
- data.recycle();
- }
+ super(list);
}
- private static void verifySameType(final Class<?> expected, final Class<?> actual) {
- if (!actual.equals(expected)) {
- throw new IllegalArgumentException("Can't unparcel type "
- + actual.getName() + " in list of type "
- + expected.getName());
- }
+ private ParceledListSlice(Parcel in, ClassLoader loader) {
+ super(in, loader);
}
- public List<T> getList() {
- return mList;
+ public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
+ return new ParceledListSlice<T>(Collections.<T> emptyList());
}
@Override
public int describeContents() {
int contents = 0;
- for (int i=0; i<mList.size(); i++) {
- contents |= mList.get(i).describeContents();
+ final List<T> list = getList();
+ for (int i=0; i<list.size(); i++) {
+ contents |= list.get(i).describeContents();
}
return contents;
}
- /**
- * Write this to another Parcel. Note that this discards the internal Parcel
- * and should not be used anymore. This is so we can pass this to a Binder
- * where we won't have a chance to call recycle on this.
- */
@Override
- public void writeToParcel(Parcel dest, int flags) {
- final int N = mList.size();
- final int callFlags = flags;
- dest.writeInt(N);
- if (DEBUG) Log.d(TAG, "Writing " + N + " items");
- if (N > 0) {
- final Class<?> listElementClass = mList.get(0).getClass();
- dest.writeParcelableCreator(mList.get(0));
- int i = 0;
- while (i < N && dest.dataSize() < MAX_IPC_SIZE) {
- dest.writeInt(1);
-
- final T parcelable = mList.get(i);
- verifySameType(listElementClass, parcelable.getClass());
- parcelable.writeToParcel(dest, callFlags);
-
- if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
- i++;
- }
- if (i < N) {
- dest.writeInt(0);
- Binder retriever = new Binder() {
- @Override
- protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- if (code != FIRST_CALL_TRANSACTION) {
- return super.onTransact(code, data, reply, flags);
- }
- int i = data.readInt();
- if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
- while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
- reply.writeInt(1);
+ protected void writeElement(T parcelable, Parcel dest, int callFlags) {
+ parcelable.writeToParcel(dest, callFlags);
+ }
- final T parcelable = mList.get(i);
- verifySameType(listElementClass, parcelable.getClass());
- parcelable.writeToParcel(reply, callFlags);
+ @Override
+ protected void writeParcelableCreator(T parcelable, Parcel dest) {
+ dest.writeParcelableCreator((Parcelable) parcelable);
+ }
- if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
- i++;
- }
- if (i < N) {
- if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
- reply.writeInt(0);
- }
- return true;
- }
- };
- if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
- dest.writeStrongBinder(retriever);
- }
- }
+ @Override
+ protected Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) {
+ return from.readParcelableCreator(loader);
}
@SuppressWarnings("unchecked")
@@ -210,6 +80,7 @@ public class ParceledListSlice<T extends Parcelable> implements Parcelable {
return new ParceledListSlice(in, loader);
}
+ @Override
public ParceledListSlice[] newArray(int size) {
return new ParceledListSlice[size];
}
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 50f2d5371019..650b4c008dcc 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -69,6 +69,11 @@ public class ResolveInfo implements Parcelable {
public AuxiliaryResolveInfo auxiliaryInfo;
/**
+ * Whether or not an instant app is available for the resolved intent.
+ */
+ public boolean instantAppAvailable;
+
+ /**
* The IntentFilter that was matched for this ResolveInfo.
*/
public IntentFilter filter;
@@ -325,6 +330,7 @@ public class ResolveInfo implements Parcelable {
system = orig.system;
targetUserId = orig.targetUserId;
handleAllWebDataURI = orig.handleAllWebDataURI;
+ instantAppAvailable = orig.instantAppAvailable;
}
public String toString() {
@@ -388,6 +394,7 @@ public class ResolveInfo implements Parcelable {
dest.writeInt(noResourceId ? 1 : 0);
dest.writeInt(iconResourceId);
dest.writeInt(handleAllWebDataURI ? 1 : 0);
+ dest.writeInt(instantAppAvailable ? 1 : 0);
}
public static final Creator<ResolveInfo> CREATOR
@@ -435,6 +442,7 @@ public class ResolveInfo implements Parcelable {
noResourceId = source.readInt() != 0;
iconResourceId = source.readInt();
handleAllWebDataURI = source.readInt() != 0;
+ instantAppAvailable = source.readInt() != 0;
}
public static class DisplayNameComparator
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index d3d3c66b20c0..520169499718 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -96,7 +96,7 @@ public final class ShortcutInfo implements Parcelable {
public static final int FLAG_IMMUTABLE = 1 << 8;
/** @hide */
- public static final int FLAG_MASKABLE_BITMAP = 1 << 9;
+ public static final int FLAG_ADAPTIVE_BITMAP = 1 << 9;
/** @hide */
public static final int FLAG_CHOOSER = 1 << 10;
@@ -118,7 +118,7 @@ public final class ShortcutInfo implements Parcelable {
FLAG_DISABLED,
FLAG_STRINGS_RESOLVED,
FLAG_IMMUTABLE,
- FLAG_MASKABLE_BITMAP,
+ FLAG_ADAPTIVE_BITMAP,
FLAG_CHOOSER,
})
@Retention(RetentionPolicy.SOURCE)
@@ -784,7 +784,7 @@ public final class ShortcutInfo implements Parcelable {
switch (icon.getType()) {
case Icon.TYPE_RESOURCE:
case Icon.TYPE_BITMAP:
- case Icon.TYPE_BITMAP_MASKABLE:
+ case Icon.TYPE_ADAPTIVE_BITMAP:
break; // OK
default:
throw getInvalidIconException();
@@ -917,7 +917,7 @@ public final class ShortcutInfo implements Parcelable {
* and will be ignored.
*
* <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)},
- * {@link Icon#createWithMaskableBitmap(Bitmap)}
+ * {@link Icon#createWithAdaptiveBitmap(Bitmap)}
* and {@link Icon#createWithResource} are supported.
* Other types, such as URI-based icons, are not supported.
*
@@ -1615,12 +1615,13 @@ public final class ShortcutInfo implements Parcelable {
}
/**
- * Return whether a shortcut's icon is maskable.
+ * Return whether a shortcut's icon is adaptive bitmap following design guideline
+ * defined in {@link AdaptiveIconDrawable}.
*
* @hide internal/unit tests only
*/
- public boolean hasMaskableBitmap() {
- return hasFlags(FLAG_MASKABLE_BITMAP);
+ public boolean hasAdaptiveBitmap() {
+ return hasFlags(FLAG_ADAPTIVE_BITMAP);
}
/**
diff --git a/core/java/android/content/pm/StringParceledListSlice.aidl b/core/java/android/content/pm/StringParceledListSlice.aidl
new file mode 100644
index 000000000000..345f3a7b5e3e
--- /dev/null
+++ b/core/java/android/content/pm/StringParceledListSlice.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017, 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.content.pm;
+
+parcelable StringParceledListSlice;
diff --git a/core/java/android/content/pm/StringParceledListSlice.java b/core/java/android/content/pm/StringParceledListSlice.java
new file mode 100644
index 000000000000..95407449a018
--- /dev/null
+++ b/core/java/android/content/pm/StringParceledListSlice.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 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.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Transfer a large list of Parcelable objects across an IPC. Splits into
+ * multiple transactions if needed.
+ *
+ * @see BaseParceledListSlice
+ *
+ * @hide
+ */
+public class StringParceledListSlice extends BaseParceledListSlice<String> {
+ public StringParceledListSlice(List<String> list) {
+ super(list);
+ }
+
+ private StringParceledListSlice(Parcel in, ClassLoader loader) {
+ super(in, loader);
+ }
+
+ public static StringParceledListSlice emptyList() {
+ return new StringParceledListSlice(Collections.<String> emptyList());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ protected void writeElement(String parcelable, Parcel reply, int callFlags) {
+ reply.writeString(parcelable);
+ }
+
+ @Override
+ protected void writeParcelableCreator(String parcelable, Parcel dest) {
+ return;
+ }
+
+ @Override
+ protected Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) {
+ return Parcel.STRING_CREATOR;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final Parcelable.ClassLoaderCreator<StringParceledListSlice> CREATOR =
+ new Parcelable.ClassLoaderCreator<StringParceledListSlice>() {
+ public StringParceledListSlice createFromParcel(Parcel in) {
+ return new StringParceledListSlice(in, null);
+ }
+
+ @Override
+ public StringParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {
+ return new StringParceledListSlice(in, loader);
+ }
+
+ @Override
+ public StringParceledListSlice[] newArray(int size) {
+ return new StringParceledListSlice[size];
+ }
+ };
+}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 4cf55ba27eec..af953e6ce98f 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -776,7 +776,6 @@ public final class AssetManager implements AutoCloseable {
* applications.
* {@hide}
*/
- @FastNative
public native final void setConfiguration(int mcc, int mnc, String locale,
int orientation, int touchscreen, int density, int keyboard,
int keyboardHidden, int navigation, int screenWidth, int screenHeight,
@@ -786,18 +785,13 @@ public final class AssetManager implements AutoCloseable {
/**
* Retrieve the resource identifier for the given resource name.
*/
- @FastNative
/*package*/ native final int getResourceIdentifier(String type,
String name,
String defPackage);
- @FastNative
/*package*/ native final String getResourceName(int resid);
- @FastNative
/*package*/ native final String getResourcePackageName(int resid);
- @FastNative
/*package*/ native final String getResourceTypeName(int resid);
- @FastNative
/*package*/ native final String getResourceEntryName(int resid);
private native final long openAsset(String fileName, int accessMode);
@@ -811,19 +805,15 @@ public final class AssetManager implements AutoCloseable {
private native final int readAssetChar(long asset);
private native final int readAsset(long asset, byte[] b, int off, int len);
private native final long seekAsset(long asset, long offset, int whence);
- @FastNative
private native final long getAssetLength(long asset);
- @FastNative
private native final long getAssetRemainingLength(long asset);
/** Returns true if the resource was found, filling in mRetStringBlock and
* mRetData. */
- @FastNative
private native final int loadResourceValue(int ident, short density, TypedValue outValue,
boolean resolve);
/** Returns true if the resource was found, filling in mRetStringBlock and
* mRetData. */
- @FastNative
private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
boolean resolve);
/*package*/ static final int STYLE_NUM_ENTRIES = 6;
@@ -836,24 +826,17 @@ public final class AssetManager implements AutoCloseable {
static final int STYLE_CHANGING_CONFIGURATIONS = 4;
/*package*/ static final int STYLE_DENSITY = 5;
- @FastNative
/*package*/ native static final void applyStyle(long theme,
int defStyleAttr, int defStyleRes, long xmlParser,
int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress);
- @FastNative
/*package*/ native static final boolean resolveAttrs(long theme,
int defStyleAttr, int defStyleRes, int[] inValues,
int[] inAttrs, int[] outValues, int[] outIndices);
- @FastNative
/*package*/ native final boolean retrieveAttributes(
long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
- @FastNative
/*package*/ native final int getArraySize(int resource);
- @FastNative
/*package*/ native final int retrieveArray(int resource, int[] outValues);
- @FastNative
private native final int getStringBlockCount();
- @FastNative
private native final long getNativeStringBlock(int block);
/**
@@ -886,22 +869,17 @@ public final class AssetManager implements AutoCloseable {
/*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
/*package*/ native static final void copyTheme(long dest, long source);
/*package*/ native static final void clearTheme(long theme);
- @FastNative
/*package*/ native static final int loadThemeAttributeValue(long theme, int ident,
TypedValue outValue,
boolean resolve);
/*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix);
- @FastNative
/*package*/ native static final @NativeConfig int getThemeChangingConfigurations(long theme);
private native final long openXmlAssetNative(int cookie, String fileName);
private native final String[] getArrayStringResource(int arrayRes);
- @FastNative
private native final int[] getArrayStringInfo(int arrayRes);
- @FastNative
/*package*/ native final int[] getArrayIntResource(int arrayRes);
- @FastNative
/*package*/ native final int[] getStyleAttributes(int themeRes);
private native final void init(boolean isSystem);
diff --git a/core/java/android/content/res/CompatResources.java b/core/java/android/content/res/CompatResources.java
index 15575fd10e83..829b6b7f9a47 100644
--- a/core/java/android/content/res/CompatResources.java
+++ b/core/java/android/content/res/CompatResources.java
@@ -27,11 +27,17 @@ import java.lang.ref.WeakReference;
*/
public class CompatResources extends Resources {
- private final WeakReference<Context> mContext;
+ private WeakReference<Context> mContext;
- public CompatResources(Resources base, Context context) {
- super(base.getClassLoader());
- setImpl(base.getImpl());
+ public CompatResources(ClassLoader cls) {
+ super(cls);
+ mContext = new WeakReference<>(null);
+ }
+
+ /**
+ * @hide
+ */
+ public void setContext(Context context) {
mContext = new WeakReference<>(context);
}
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index da35ee92267e..781e23533870 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -21,6 +21,8 @@ import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.DisplayMetrics;
@@ -78,6 +80,11 @@ public class CompatibilityInfo implements Parcelable {
private static final int NEEDS_SCREEN_COMPAT = 8;
/**
+ * Set if the application needs to run in with compat resources.
+ */
+ private static final int NEEDS_COMPAT_RES = 16;
+
+ /**
* The effective screen density we have selected for this application.
*/
public final int applicationDensity;
@@ -96,6 +103,9 @@ public class CompatibilityInfo implements Parcelable {
boolean forceCompat) {
int compatFlags = 0;
+ if (appInfo.targetSdkVersion < VERSION_CODES.O) {
+ compatFlags |= NEEDS_COMPAT_RES;
+ }
if (appInfo.requiresSmallestWidthDp != 0 || appInfo.compatibleWidthLimitDp != 0
|| appInfo.largestWidthLimitDp != 0) {
// New style screen requirements spec.
@@ -274,6 +284,10 @@ public class CompatibilityInfo implements Parcelable {
return (mCompatibilityFlags&NEVER_NEEDS_COMPAT) != 0;
}
+ public boolean needsCompatResources() {
+ return (mCompatibilityFlags&NEEDS_COMPAT_RES) != 0;
+ }
+
/**
* Returns the translator which translates the coordinates in compatibility mode.
* @param params the window's parameter
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1259de602f29..72f51cf65057 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2913,11 +2913,14 @@ public class ConnectivityManager {
if (callback == null) {
throw new IllegalArgumentException("null NetworkCallback");
}
- if (need == null && action != REQUEST) {
+ if ((need == null) && (action != REQUEST)) {
throw new IllegalArgumentException("null NetworkCapabilities");
}
- // TODO: throw an exception if callback.networkRequest is not null.
- // http://b/20701525
+ final int targetSdk = mContext.getApplicationInfo().targetSdkVersion;
+ if ((targetSdk > VERSION_CODES.N_MR1) && (callback.networkRequest != null)) {
+ // http://b/20701525
+ throw new IllegalArgumentException("NetworkCallback already registered");
+ }
final NetworkRequest request;
try {
synchronized(sCallbacks) {
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
new file mode 100644
index 000000000000..da5cb37961ab
--- /dev/null
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2017 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.StringDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
+ * RFC 4301.
+ */
+public final class IpSecAlgorithm implements Parcelable {
+
+ /**
+ * AES-CBC Encryption/Ciphering Algorithm.
+ *
+ * <p>Valid lengths for this key are {128, 192, 256}.
+ */
+ public static final String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+
+ /**
+ * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new
+ * applications and is provided for legacy compatibility with 3gpp infrastructure.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
+ */
+ public static final String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+
+ /**
+ * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in
+ * new applications and is provided for legacy compatibility with 3gpp infrastructure.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+
+ /**
+ * SHA256 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+
+ /**
+ * SHA384 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ /**
+ * SHA512 HMAC Authentication/Integrity Algorithm
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+
+ /** @hide */
+ @StringDef({
+ ALGO_CRYPT_AES_CBC,
+ ALGO_AUTH_HMAC_MD5,
+ ALGO_AUTH_HMAC_SHA1,
+ ALGO_AUTH_HMAC_SHA256,
+ ALGO_AUTH_HMAC_SHA512
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AlgorithmName {}
+
+ private final String mName;
+ private final byte[] mKey;
+ private final int mTruncLenBits;
+
+ /**
+ * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
+ * algorithm
+ *
+ * @param algorithm type for IpSec.
+ * @param key non-null Key padded to a multiple of 8 bits.
+ */
+ public IpSecAlgorithm(String algorithm, byte[] key) {
+ this(algorithm, key, key.length * 8);
+ }
+
+ /**
+ * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
+ * algorithm
+ *
+ * @param algoName precise name of the algorithm to be used.
+ * @param key non-null Key padded to a multiple of 8 bits.
+ * @param truncLenBits the number of bits of output hash to use; only meaningful for
+ * Authentication.
+ */
+ public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) {
+ if (!isTruncationLengthValid(algoName, truncLenBits)) {
+ throw new IllegalArgumentException("Unknown algorithm or invalid length");
+ }
+ mName = algoName;
+ mKey = key.clone();
+ mTruncLenBits = Math.min(truncLenBits, key.length * 8);
+ }
+
+ /** Retrieve the algorithm name */
+ public String getName() {
+ return mName;
+ }
+
+ /** Retrieve the key for this algorithm */
+ public byte[] getKey() {
+ return mKey.clone();
+ }
+
+ /**
+ * Retrieve the truncation length, in bits, for the key in this algo. By default this will be
+ * the length in bits of the key.
+ */
+ public int getTruncationLengthBits() {
+ return mTruncLenBits;
+ }
+
+ /* Parcelable Implementation */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Write to parcel */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mName);
+ out.writeByteArray(mKey);
+ out.writeInt(mTruncLenBits);
+ }
+
+ /** Parcelable Creator */
+ public static final Parcelable.Creator<IpSecAlgorithm> CREATOR =
+ new Parcelable.Creator<IpSecAlgorithm>() {
+ public IpSecAlgorithm createFromParcel(Parcel in) {
+ return new IpSecAlgorithm(in);
+ }
+
+ public IpSecAlgorithm[] newArray(int size) {
+ return new IpSecAlgorithm[size];
+ }
+ };
+
+ private IpSecAlgorithm(Parcel in) {
+ mName = in.readString();
+ mKey = in.createByteArray();
+ mTruncLenBits = in.readInt();
+ }
+
+ private static boolean isTruncationLengthValid(String algo, int truncLenBits) {
+ switch (algo) {
+ case ALGO_AUTH_HMAC_MD5:
+ return (truncLenBits >= 96 && truncLenBits <= 128);
+ case ALGO_AUTH_HMAC_SHA1:
+ return (truncLenBits >= 96 && truncLenBits <= 160);
+ case ALGO_AUTH_HMAC_SHA256:
+ return (truncLenBits >= 96 && truncLenBits <= 256);
+ case ALGO_AUTH_HMAC_SHA384:
+ return (truncLenBits >= 192 && truncLenBits <= 384);
+ case ALGO_AUTH_HMAC_SHA512:
+ return (truncLenBits >= 256 && truncLenBits <= 512);
+ default:
+ return false;
+ }
+ }
+};
diff --git a/core/java/android/net/IpSecConfig.aidl b/core/java/android/net/IpSecConfig.aidl
new file mode 100644
index 000000000000..eaefca74d3a0
--- /dev/null
+++ b/core/java/android/net/IpSecConfig.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2017 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;
+
+/** @hide */
+parcelable IpSecConfig;
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
new file mode 100644
index 000000000000..b58bf421a86a
--- /dev/null
+++ b/core/java/android/net/IpSecConfig.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2017 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.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/** @hide */
+public final class IpSecConfig implements Parcelable {
+ private static final String TAG = IpSecConfig.class.getSimpleName();
+
+ //MODE_TRANSPORT or MODE_TUNNEL
+ int mode;
+
+ // For tunnel mode
+ InetAddress localAddress;
+
+ InetAddress remoteAddress;
+
+ // Limit selection by network interface
+ Network network;
+
+ public static class Flow {
+ // Minimum requirements for identifying a transform
+ // SPI identifying the IPsec flow in packet processing
+ // and a remote IP address
+ int spi;
+
+ // Encryption Algorithm
+ IpSecAlgorithm encryptionAlgo;
+
+ // Authentication Algorithm
+ IpSecAlgorithm authenticationAlgo;
+ }
+
+ Flow[] flow = new Flow[2];
+
+ // For tunnel mode IPv4 UDP Encapsulation
+ // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE
+ int encapType;
+ int encapLocalPort;
+ int encapRemotePort;
+
+ // An optional protocol to match with the selector
+ int selectorProto;
+
+ // A bitmask of FEATURE_* indicating which of the fields
+ // of this class are valid.
+ long features;
+
+ // An interval, in seconds between the NattKeepalive packets
+ int nattKeepaliveInterval;
+
+ public InetAddress getLocalIp() {
+ return localAddress;
+ }
+
+ public int getSpi(int direction) {
+ return flow[direction].spi;
+ }
+
+ public InetAddress getRemoteIp() {
+ return remoteAddress;
+ }
+
+ public IpSecAlgorithm getEncryptionAlgo(int direction) {
+ return flow[direction].encryptionAlgo;
+ }
+
+ public IpSecAlgorithm getAuthenticationAlgo(int direction) {
+ return flow[direction].authenticationAlgo;
+ }
+
+ Network getNetwork() {
+ return network;
+ }
+
+ public int getEncapType() {
+ return encapType;
+ }
+
+ public int getEncapLocalPort() {
+ return encapLocalPort;
+ }
+
+ public int getEncapRemotePort() {
+ return encapRemotePort;
+ }
+
+ public int getSelectorProto() {
+ return selectorProto;
+ }
+
+ int getNattKeepaliveInterval() {
+ return nattKeepaliveInterval;
+ }
+
+ public boolean hasProperty(int featureBits) {
+ return (features & featureBits) == featureBits;
+ }
+
+ // Parcelable Methods
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(features);
+ // TODO: Use a byte array or other better method for storing IPs that can also include scope
+ out.writeString((localAddress != null) ? localAddress.getHostAddress() : null);
+ // TODO: Use a byte array or other better method for storing IPs that can also include scope
+ out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null);
+ out.writeParcelable(network, flags);
+ out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags);
+ out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags);
+ out.writeInt(encapType);
+ out.writeInt(encapLocalPort);
+ out.writeInt(encapRemotePort);
+ out.writeInt(selectorProto);
+ }
+
+ // Package Private: Used by the IpSecTransform.Builder;
+ // there should be no public constructor for this object
+ IpSecConfig() {
+ flow[IpSecTransform.DIRECTION_IN].spi = 0;
+ flow[IpSecTransform.DIRECTION_OUT].spi = 0;
+ nattKeepaliveInterval = 0; //FIXME constant
+ }
+
+ private static InetAddress readInetAddressFromParcel(Parcel in) {
+ String addrString = in.readString();
+ if (addrString == null) {
+ return null;
+ }
+ try {
+ return InetAddress.getByName(addrString);
+ } catch (UnknownHostException e) {
+ Log.wtf(TAG, "Invalid IpAddress " + addrString);
+ return null;
+ }
+ }
+
+ private IpSecConfig(Parcel in) {
+ features = in.readLong();
+ localAddress = readInetAddressFromParcel(in);
+ remoteAddress = readInetAddressFromParcel(in);
+ network = (Network) in.readParcelable(Network.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_IN].spi = in.readInt();
+ flow[IpSecTransform.DIRECTION_IN].encryptionAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_IN].authenticationAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt();
+ flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ encapType = in.readInt();
+ encapLocalPort = in.readInt();
+ encapRemotePort = in.readInt();
+ selectorProto = in.readInt();
+ }
+
+ public static final Parcelable.Creator<IpSecConfig> CREATOR =
+ new Parcelable.Creator<IpSecConfig>() {
+ public IpSecConfig createFromParcel(Parcel in) {
+ return new IpSecConfig(in);
+ }
+
+ public IpSecConfig[] newArray(int size) {
+ return new IpSecConfig[size];
+ }
+ };
+}
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
new file mode 100644
index 000000000000..2c544e9b9bfe
--- /dev/null
+++ b/core/java/android/net/IpSecManager.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.INetworkManagementService;
+import android.os.ParcelFileDescriptor;
+import android.util.AndroidException;
+import dalvik.system.CloseGuard;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Socket;
+
+/**
+ * This class contains methods for managing IPsec sessions, which will perform kernel-space
+ * encryption and decryption of socket or Network traffic.
+ *
+ * <p>An IpSecManager may be obtained by calling {@link
+ * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link
+ * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE}
+ */
+public final class IpSecManager {
+ private static final String TAG = "IpSecManager";
+
+ /**
+ * Indicates that the combination of remote InetAddress and SPI was non-unique for a given
+ * request. If encountered, selection of a new SPI is required before a transform may be
+ * created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random
+ * or reserved using reserveSecurityParameterIndex.
+ */
+ public static final class SpiUnavailableException extends AndroidException {
+ private final int mSpi;
+
+ /**
+ * Construct an exception indicating that a transform with the given SPI is already in use
+ * or otherwise unavailable.
+ *
+ * @param msg Description indicating the colliding SPI
+ * @param spi the SPI that could not be used due to a collision
+ */
+ SpiUnavailableException(String msg, int spi) {
+ super(msg + "(spi: " + spi + ")");
+ mSpi = spi;
+ }
+
+ /** Retrieve the SPI that caused a collision */
+ public int getSpi() {
+ return mSpi;
+ }
+ }
+
+ /**
+ * Indicates that the requested system resource for IPsec, such as a socket or other system
+ * resource is unavailable. If this exception is thrown, try releasing allocated objects of the
+ * type requested.
+ */
+ public static final class ResourceUnavailableException extends AndroidException {
+
+ ResourceUnavailableException(String msg) {
+ super(msg);
+ }
+ }
+
+ private final Context mContext;
+ private final INetworkManagementService mService;
+
+ public static final class SecurityParameterIndex implements AutoCloseable {
+ private final Context mContext;
+ private final InetAddress mDestinationAddress;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private int mSpi;
+
+ /** Return the underlying SPI held by this object */
+ public int getSpi() {
+ return mSpi;
+ }
+
+ private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi)
+ throws ResourceUnavailableException, SpiUnavailableException {
+ mContext = context;
+ mDestinationAddress = destinationAddress;
+ mSpi = spi;
+ mCloseGuard.open("open");
+ }
+
+ /**
+ * Release an SPI that was previously reserved.
+ *
+ * <p>Release an SPI for use by other users in the system. This will fail if the SPI is
+ * currently in use by an IpSecTransform.
+ *
+ * @param destinationAddress SPIs must be unique for each combination of SPI and destination
+ * address. Thus, the destinationAddress to which the SPI will communicate must be
+ * supplied.
+ * @param spi the previously reserved SPI to be freed.
+ */
+ @Override
+ public void close() {
+ mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+
+ close();
+ }
+ }
+
+ /**
+ * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
+ *
+ * <p>No IPsec packet may contain an SPI of 0.
+ */
+ public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
+
+ /**
+ * Reserve an SPI for traffic bound towards the specified destination address.
+ *
+ * <p>If successful, this SPI is guaranteed available until released by a call to {@link
+ * SecurityParameterIndex#close()}.
+ *
+ * @param destinationAddress SPIs must be unique for each combination of SPI and destination
+ * address.
+ * @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
+ * @return the reserved SecurityParameterIndex
+ * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
+ * for this user
+ * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved
+ */
+ public SecurityParameterIndex reserveSecurityParameterIndex(
+ InetAddress destinationAddress, int requestedSpi)
+ throws SpiUnavailableException, ResourceUnavailableException {
+ return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi);
+ }
+
+ /**
+ * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
+ * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
+ * transform. For security reasons, attempts to send traffic to any IP address other than the
+ * address associated with that transform will throw an IOException. In addition, if the
+ * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
+ * send() or receive() until the transform is removed from the socket by calling {@link
+ * #removeTransportModeTransform(Socket, IpSecTransform)};
+ *
+ * @param socket a stream socket
+ * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ */
+ public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
+ throws IOException {
+ applyTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
+ }
+
+ /**
+ * Apply an active Transport Mode IPsec Transform to a datagram socket to perform IPsec
+ * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
+ * transform. For security reasons, attempts to send traffic to any IP address other than the
+ * address associated with that transform will throw an IOException. In addition, if the
+ * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
+ * send() or receive() until the transform is removed from the socket by calling {@link
+ * #removeTransportModeTransform(DatagramSocket, IpSecTransform)};
+ *
+ * @param socket a datagram socket
+ * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ */
+ public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
+ throws IOException {
+ applyTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
+ }
+
+ /* Call down to activate a transform */
+ private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+
+ /**
+ * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to
+ * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to
+ * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic).
+ * Applications should probably not use this API directly. Instead, they should use {@link
+ * VpnService} to provide VPN capability in a more generic fashion.
+ *
+ * @param net a {@link Network} that will be tunneled via IP Sec.
+ * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform.
+ * @hide
+ */
+ @SystemApi
+ public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
+
+ /**
+ * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
+ * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
+ * communication in the clear in the event socket reuse is desired. This operation will succeed
+ * regardless of the underlying state of a transform. If a transform is removed, communication
+ * on all sockets to which that transform was applied will fail until this method is called.
+ *
+ * @param socket a socket that previously had a transform applied to it.
+ * @param transform the IPsec Transform that was previously applied to the given socket
+ */
+ public void removeTransportModeTransform(Socket socket, IpSecTransform transform) {
+ removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
+ }
+
+ /**
+ * Remove a transform from a given datagram socket. Once removed, traffic on the socket will not
+ * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
+ * communication in the clear in the event socket reuse is desired. This operation will succeed
+ * regardless of the underlying state of a transform. If a transform is removed, communication
+ * on all sockets to which that transform was applied will fail until this method is called.
+ *
+ * @param socket a socket that previously had a transform applied to it.
+ * @param transform the IPsec Transform that was previously applied to the given socket
+ */
+ public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) {
+ removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
+ }
+
+ /* Call down to activate a transform */
+ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+
+ /**
+ * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
+ * cleanup if a tunneled Network experiences a change in default route. The Network will drop
+ * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
+ * lost, all traffic will drop.
+ *
+ * @param net a network that currently has transform applied to it.
+ * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
+ * network
+ * @hide
+ */
+ @SystemApi
+ public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
+
+ /**
+ * Class providing access to a system-provided UDP Encapsulation Socket, which may be used for
+ * IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic.
+ *
+ * <p>The socket provided by this class cannot be re-bound or closed via the inner
+ * FileDescriptor. Instead, disposing of this socket requires a call to close().
+ */
+ public static final class UdpEncapsulationSocket implements AutoCloseable {
+ private final FileDescriptor mFd;
+ private final Context mContext;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ private UdpEncapsulationSocket(Context context, int port)
+ throws ResourceUnavailableException {
+ mContext = context;
+ mCloseGuard.open("constructor");
+ // TODO: go down to the kernel and get a socket on the specified
+ mFd = new FileDescriptor();
+ }
+
+ private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException {
+ mContext = context;
+ mCloseGuard.open("constructor");
+ // TODO: go get a random socket on a random port
+ mFd = new FileDescriptor();
+ }
+
+ /** Access the inner UDP Encapsulation Socket */
+ public FileDescriptor getSocket() {
+ return mFd;
+ }
+
+ /** Retrieve the port number of the inner encapsulation socket */
+ public int getPort() {
+ return 0; // TODO get the port number from the Socket;
+ }
+
+ @Override
+ /**
+ * Release the resources that have been reserved for this Socket.
+ *
+ * <p>This method closes the underlying socket, reducing a user's allocated sockets in the
+ * system. This must be done as part of cleanup following use of a socket. Failure to do so
+ * will cause the socket to count against a total allocation limit for IpSec and eventually
+ * fail due to resource limits.
+ *
+ * @param fd a file descriptor previously returned as a UDP Encapsulation socket.
+ */
+ public void close() {
+ // TODO: Go close the socket
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+
+ close();
+ }
+ };
+
+ /**
+ * Open a socket that is bound to a free UDP port on the system.
+ *
+ * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
+ * the caller. This provides safe access to a socket on a port that can later be used as a UDP
+ * Encapsulation port.
+ *
+ * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
+ * socket port. Explicitly opening this port is only necessary if communication is desired on
+ * that port.
+ *
+ * @param port a local UDP port to be reserved for UDP Encapsulation. is provided, then this
+ * method will bind to the specified port or fail. To retrieve the port number, call {@link
+ * android.system.Os#getsockname(FileDescriptor)}.
+ * @return a {@link UdpEncapsulationSocket} that is bound to the requested port for the lifetime
+ * of the object.
+ */
+ // Returning a socket in this fashion that has been created and bound by the system
+ // is the only safe way to ensure that a socket is both accessible to the user and
+ // safely usable for Encapsulation without allowing a user to possibly unbind from/close
+ // the port, which could potentially impact the traffic of the next user who binds to that
+ // socket.
+ public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
+ throws IOException, ResourceUnavailableException {
+ // Temporary code
+ return new UdpEncapsulationSocket(mContext, port);
+ }
+
+ /**
+ * Open a socket that is bound to a port selected by the system.
+ *
+ * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
+ * the caller. This provides safe access to a socket on a port that can later be used as a UDP
+ * Encapsulation port.
+ *
+ * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
+ * socket port. Explicitly opening this port is only necessary if communication is desired on
+ * that port.
+ *
+ * @return a {@link UdpEncapsulationSocket} that is bound to an arbitrarily selected port
+ */
+ // Returning a socket in this fashion that has been created and bound by the system
+ // is the only safe way to ensure that a socket is both accessible to the user and
+ // safely usable for Encapsulation without allowing a user to possibly unbind from/close
+ // the port, which could potentially impact the traffic of the next user who binds to that
+ // socket.
+ public UdpEncapsulationSocket openUdpEncapsulationSocket()
+ throws IOException, ResourceUnavailableException {
+ // Temporary code
+ return new UdpEncapsulationSocket(mContext);
+ }
+
+ /**
+ * Retrieve an instance of an IpSecManager within you application context
+ *
+ * @param context the application context for this manager
+ * @hide
+ */
+ public IpSecManager(Context context, INetworkManagementService service) {
+ mContext = checkNotNull(context, "missing context");
+ mService = checkNotNull(service, "missing service");
+ }
+}
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
new file mode 100644
index 000000000000..d6dd28bec390
--- /dev/null
+++ b/core/java/android/net/IpSecTransform.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2017 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.SystemApi;
+import android.content.Context;
+import android.system.ErrnoException;
+import android.util.Log;
+import dalvik.system.CloseGuard;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.InetAddress;
+
+/**
+ * This class represents an IpSecTransform, which encapsulates both properties and state of IPsec.
+ *
+ * <p>IpSecTransforms must be built from an IpSecTransform.Builder, and they must persist throughout
+ * the lifetime of the underlying transform. If a transform object leaves scope, the underlying
+ * transform may be disabled automatically, with likely undesirable results.
+ *
+ * <p>An IpSecTransform may either represent a tunnel mode transform that operates on a wide array
+ * of traffic or may represent a transport mode transform operating on a Socket or Sockets.
+ */
+public final class IpSecTransform implements AutoCloseable {
+ private static final String TAG = "IpSecTransform";
+
+ /**
+ * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
+ * to traffic towards the host.
+ */
+ public static final int DIRECTION_IN = 0;
+
+ /**
+ * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
+ * to traffic from the host.
+ */
+ public static final int DIRECTION_OUT = 1;
+
+ /** @hide */
+ @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TransformDirection {}
+
+ /** @hide */
+ private static final int MODE_TUNNEL = 0;
+
+ /** @hide */
+ private static final int MODE_TRANSPORT = 1;
+
+ /** @hide */
+ public static final int ENCAP_NONE = 0;
+
+ /**
+ * IpSec traffic will be encapsulated within UDP as per <a
+ * href="https://tools.ietf.org/html/rfc3948">RFC3498</a>.
+ *
+ * @hide
+ */
+ public static final int ENCAP_ESPINUDP = 1;
+
+ /**
+ * IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad
+ * (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP.
+ *
+ * @hide
+ */
+ public static final int ENCAP_ESPINUDP_NONIKE = 2;
+
+ /** @hide */
+ @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NONIKE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EncapType {}
+
+ /**
+ * Sentinel for an invalid transform (means that this transform is inactive).
+ *
+ * @hide
+ */
+ public static final int INVALID_TRANSFORM_ID = -1;
+
+ private IpSecTransform(Context context, IpSecConfig config) {
+ mContext = context;
+ mConfig = config;
+ mTransformId = INVALID_TRANSFORM_ID;
+ }
+
+ private IpSecTransform activate()
+ throws IOException, IpSecManager.ResourceUnavailableException,
+ IpSecManager.SpiUnavailableException {
+ int transformId;
+ synchronized (this) {
+ //try {
+ transformId = INVALID_TRANSFORM_ID;
+ //} catch (RemoteException e) {
+ // throw e.rethrowFromSystemServer();
+ //}
+
+ if (transformId < 0) {
+ throw new ErrnoException("addTransform", -transformId).rethrowAsIOException();
+ }
+
+ startKeepalive(mContext); // Will silently fail if not required
+ mTransformId = transformId;
+ Log.d(TAG, "Added Transform with Id " + transformId);
+ }
+ mCloseGuard.open("build");
+
+ return this;
+ }
+
+ /**
+ * Deactivate an IpSecTransform and free all resources for that transform that are managed by
+ * the system for this Transform.
+ *
+ * <p>Deactivating a transform while it is still applied to any Socket will result in sockets
+ * refusing to send or receive data. This method will silently succeed if the specified
+ * transform has already been removed; thus, it is always safe to attempt cleanup when a
+ * transform is no longer needed.
+ */
+ public void close() {
+ Log.d(TAG, "Removing Transform with Id " + mTransformId);
+
+ // Always safe to attempt cleanup
+ if (mTransformId == INVALID_TRANSFORM_ID) {
+ return;
+ }
+ //try {
+ stopKeepalive();
+ //} catch (RemoteException e) {
+ // transform.setTransformId(transformId);
+ // throw e.rethrowFromSystemServer();
+ //} finally {
+ mTransformId = INVALID_TRANSFORM_ID;
+ //}
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ }
+
+ /* Package */
+ IpSecConfig getConfig() {
+ return mConfig;
+ }
+
+ private final IpSecConfig mConfig;
+ private int mTransformId;
+ private final Context mContext;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private ConnectivityManager.PacketKeepalive mKeepalive;
+ private int mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
+ private Object mKeepaliveSyncLock = new Object();
+ private ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback =
+ new ConnectivityManager.PacketKeepaliveCallback() {
+
+ @Override
+ public void onStarted() {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = ConnectivityManager.PacketKeepalive.SUCCESS;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void onStopped() {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void onError(int error) {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = error;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+ };
+
+ /* Package */
+ void startKeepalive(Context c) {
+ if (mConfig.getNattKeepaliveInterval() == 0) {
+ return;
+ }
+
+ ConnectivityManager cm =
+ (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (mKeepalive != null) {
+ Log.e(TAG, "Keepalive already started for this IpSecTransform.");
+ return;
+ }
+
+ synchronized (mKeepaliveSyncLock) {
+ mKeepalive =
+ cm.startNattKeepalive(
+ mConfig.getNetwork(),
+ mConfig.getNattKeepaliveInterval(),
+ mKeepaliveCallback,
+ mConfig.getLocalIp(),
+ mConfig.getEncapLocalPort(),
+ mConfig.getRemoteIp());
+ try {
+ mKeepaliveSyncLock.wait(2000);
+ } catch (InterruptedException e) {
+ }
+ }
+ if (mKeepaliveStatus != ConnectivityManager.PacketKeepalive.SUCCESS) {
+ throw new UnsupportedOperationException("Packet Keepalive cannot be started");
+ }
+ }
+
+ /* Package */
+ void stopKeepalive() {
+ if (mKeepalive == null) {
+ return;
+ }
+ mKeepalive.stop();
+ synchronized (mKeepaliveSyncLock) {
+ if (mKeepaliveStatus == ConnectivityManager.PacketKeepalive.SUCCESS) {
+ try {
+ mKeepaliveSyncLock.wait(2000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
+ /* Package */
+ void setTransformId(int transformId) {
+ mTransformId = transformId;
+ }
+
+ /* Package */
+ int getTransformId() {
+ return mTransformId;
+ }
+
+ /**
+ * Builder object to facilitate the creation of IpSecTransform objects.
+ *
+ * <p>Apply additional properties to the transform and then call a build() method to return an
+ * IpSecTransform object.
+ *
+ * @see Builder#buildTransportModeTransform(InetAddress)
+ */
+ public static class Builder {
+ private Context mContext;
+ private IpSecConfig mConfig;
+
+ /**
+ * Add an encryption algorithm to the transform for the given direction.
+ *
+ * <p>If encryption is set for a given direction without also providing an SPI for that
+ * direction, creation of an IpSecTransform will fail upon calling a build() method.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
+ */
+ public IpSecTransform.Builder setEncryption(
+ @TransformDirection int direction, IpSecAlgorithm algo) {
+ mConfig.flow[direction].encryptionAlgo = algo;
+ return this;
+ }
+
+ /**
+ * Add an authentication/integrity algorithm to the transform.
+ *
+ * <p>If authentication is set for a given direction without also providing an SPI for that
+ * direction, creation of an IpSecTransform will fail upon calling a build() method.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
+ */
+ public IpSecTransform.Builder setAuthentication(
+ @TransformDirection int direction, IpSecAlgorithm algo) {
+ mConfig.flow[direction].authenticationAlgo = algo;
+ return this;
+ }
+
+ /**
+ * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
+ * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
+ * given destination address.
+ *
+ * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
+ * possible. Random number generation is a reasonable approach to selecting an SPI. For
+ * outbound SPIs, they must be reserved by calling {@link
+ * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
+ * fail to build.
+ *
+ * <p>Unless an SPI is set for a given direction, traffic in that direction will be
+ * sent/received without any IPsec applied.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param spi a unique 32-bit integer to identify transformed traffic
+ */
+ public IpSecTransform.Builder setSpi(@TransformDirection int direction, int spi) {
+ mConfig.flow[direction].spi = spi;
+ return this;
+ }
+
+ /**
+ * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
+ * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
+ * given destination address.
+ *
+ * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
+ * possible. Random number generation is a reasonable approach to selecting an SPI. For
+ * outbound SPIs, they must be reserved by calling {@link
+ * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
+ * fail to activate.
+ *
+ * <p>Unless an SPI is set for a given direction, traffic in that direction will be
+ * sent/received without any IPsec applied.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
+ * traffic
+ */
+ public IpSecTransform.Builder setSpi(
+ @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) {
+ mConfig.flow[direction].spi = spi.getSpi();
+ return this;
+ }
+
+ /**
+ * Specify the network on which this transform will emit its traffic; (otherwise it will
+ * emit on the default network).
+ *
+ * <p>Restricts the transformed traffic to a particular {@link Network}. This is required in
+ * tunnel mode.
+ *
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform.Builder setUnderlyingNetwork(Network net) {
+ mConfig.network = net;
+ return this;
+ }
+
+ /**
+ * Add UDP encapsulation to an IPv4 transform
+ *
+ * <p>This option allows IPsec traffic to pass through NAT. Refer to RFC 3947 and 3948 for
+ * details on how UDP should be applied to IPsec.
+ *
+ * @param localSocket a {@link IpSecManager.UdpEncapsulationSocket} for sending and
+ * receiving encapsulating traffic.
+ * @param remotePort the UDP port number of the remote that will send and receive
+ * encapsulated traffic. In the case of IKE, this is likely port 4500.
+ */
+ public IpSecTransform.Builder setIpv4Encapsulation(
+ IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
+ // TODO: check encap type is valid.
+ mConfig.encapType = ENCAP_ESPINUDP;
+ mConfig.encapLocalPort = localSocket.getPort(); // TODO: plug in the encap socket
+ mConfig.encapRemotePort = remotePort;
+ return this;
+ }
+
+ // TODO: Decrease the minimum keepalive to maybe 10?
+ // TODO: Probably a better exception to throw for NATTKeepalive failure
+ // TODO: Specify the needed NATT keepalive permission.
+ /**
+ * Send a NATT Keepalive packet with a given maximum interval. This will create an offloaded
+ * request to do power-efficient NATT Keepalive. If NATT keepalive is requested but cannot
+ * be activated, then the transform will fail to activate and throw an IOException.
+ *
+ * @param intervalSeconds the maximum number of seconds between keepalive packets, no less
+ * than 20s and no more than 3600s.
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform.Builder setNattKeepalive(int intervalSeconds) {
+ mConfig.nattKeepaliveInterval = intervalSeconds;
+ return this;
+ }
+
+ /**
+ * Build and return an active {@link IpSecTransform} object as a Transport Mode Transform.
+ * Some parameters have interdependencies that are checked at build time. If a well-formed
+ * transform cannot be created from the supplied parameters, this method will throw an
+ * Exception.
+ *
+ * <p>Upon a successful return from this call, the provided IpSecTransform will be active
+ * and may be applied to sockets. If too many IpSecTransform objects are active for a given
+ * user this operation will fail and throw ResourceUnavailableException. To avoid these
+ * exceptions, unused Transform objects must be cleaned up by calling {@link
+ * IpSecTransform#close()} when they are no longer needed.
+ *
+ * @param remoteAddress the {@link InetAddress} that, when matched on traffic to/from this
+ * socket will cause the transform to be applied.
+ * <p>Note that an active transform will not impact any network traffic until it has
+ * been applied to one or more Sockets. Calling this method is a necessary precondition
+ * for applying it to a socket, but is not sufficient to actually apply IPsec.
+ * @throws IllegalArgumentException indicating that a particular combination of transform
+ * properties is invalid.
+ * @throws IpSecManager.ResourceUnavailableException in the event that no more Transforms
+ * may be allocated
+ * @throws SpiUnavailableException if the SPI collides with an existing transform
+ * (unlikely).
+ * @throws ResourceUnavailableException if the current user currently has exceeded the
+ * number of allowed active transforms.
+ */
+ public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress)
+ throws IpSecManager.ResourceUnavailableException,
+ IpSecManager.SpiUnavailableException, IOException {
+ //FIXME: argument validation here
+ //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
+ mConfig.mode = MODE_TRANSPORT;
+ mConfig.remoteAddress = remoteAddress;
+ return new IpSecTransform(mContext, mConfig).activate();
+ }
+
+ /**
+ * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some
+ * parameters have interdependencies that are checked at build time.
+ *
+ * @param localAddress the {@link InetAddress} that provides the local endpoint for this
+ * IPsec tunnel. This is almost certainly an address belonging to the {@link Network}
+ * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}.
+ * @param remoteAddress the {@link InetAddress} representing the remote endpoint of this
+ * IPsec tunnel.
+ * @throws IllegalArgumentException indicating that a particular combination of transform
+ * properties is invalid.
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform buildTunnelModeTransform(
+ InetAddress localAddress, InetAddress remoteAddress) {
+ //FIXME: argument validation here
+ //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
+ mConfig.localAddress = localAddress;
+ mConfig.remoteAddress = remoteAddress;
+ mConfig.mode = MODE_TUNNEL;
+ return new IpSecTransform(mContext, mConfig);
+ }
+
+ /**
+ * Create a new IpSecTransform.Builder to construct an IpSecTransform
+ *
+ * @param context current Context
+ */
+ public Builder(Context context) {
+ mContext = context;
+ mConfig = new IpSecConfig();
+ }
+ }
+}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 1b715af0da29..43fab037f254 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -19,6 +19,7 @@ package android.net;
import static android.content.pm.PackageManager.GET_SIGNATURES;
import static android.net.NetworkPolicy.CYCLE_NONE;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -381,4 +382,20 @@ public class NetworkPolicyManager {
string.append(")");
return string.toString();
}
+
+ /**
+ * Returns true if {@param procState} is considered foreground and as such will be allowed
+ * to access network when the device is idle or in battery saver mode. Otherwise, false.
+ */
+ public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
+ return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+ }
+
+ /**
+ * Returns true if {@param procState} is considered foreground and as such will be allowed
+ * to access network when the device is in data saver mode. Otherwise, false.
+ */
+ public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState) {
+ return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+ }
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 815d4807a39e..7b7a21cdae4c 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -103,6 +103,14 @@ public class NetworkScoreManager {
public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
/**
+ * Meta-data specified on a {@link NetworkRecommendationProvider} that provides a user-visible
+ * label of the recommendation service.
+ * @hide
+ */
+ public static final String RECOMMENDATION_SERVICE_LABEL_META_DATA =
+ "android.net.scoring.recommendation_service_label";
+
+ /**
* Meta-data specified on a {@link NetworkRecommendationProvider} that specified the package
* name of the application that connects and secures open wifi networks automatically. The
* specified package must provide an Activity for {@link #ACTION_CUSTOM_ENABLE}.
@@ -265,8 +273,8 @@ public class NetworkScoreManager {
* the {@link #ACTION_CHANGE_ACTIVE} broadcast, or using a custom configuration activity.
*
* @return true if the operation succeeded, or false if the new package is not a valid scorer.
- * @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#SCORE_NETWORKS} permission.
+ * @throws SecurityException if the caller is not a system process or does not hold the
+ * {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission
* @hide
*/
@SystemApi
diff --git a/core/java/android/net/NetworkScorerAppData.java b/core/java/android/net/NetworkScorerAppData.java
index fca0a2e10bcd..5bf1e103a2de 100644
--- a/core/java/android/net/NetworkScorerAppData.java
+++ b/core/java/android/net/NetworkScorerAppData.java
@@ -16,6 +16,8 @@ public final class NetworkScorerAppData implements Parcelable {
/** UID of the scorer app. */
public final int packageUid;
private final ComponentName mRecommendationService;
+ /** User visible label in Settings for the recommendation service. */
+ private final String mRecommendationServiceLabel;
/**
* The {@link ComponentName} of the Activity to start before enabling the "connect to open
* wifi networks automatically" feature.
@@ -23,15 +25,17 @@ public final class NetworkScorerAppData implements Parcelable {
private final ComponentName mEnableUseOpenWifiActivity;
public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp,
- ComponentName enableUseOpenWifiActivity) {
+ String recommendationServiceLabel, ComponentName enableUseOpenWifiActivity) {
this.packageUid = packageUid;
this.mRecommendationService = recommendationServiceComp;
+ this.mRecommendationServiceLabel = recommendationServiceLabel;
this.mEnableUseOpenWifiActivity = enableUseOpenWifiActivity;
}
protected NetworkScorerAppData(Parcel in) {
packageUid = in.readInt();
mRecommendationService = ComponentName.readFromParcel(in);
+ mRecommendationServiceLabel = in.readString();
mEnableUseOpenWifiActivity = ComponentName.readFromParcel(in);
}
@@ -39,6 +43,7 @@ public final class NetworkScorerAppData implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(packageUid);
ComponentName.writeToParcel(mRecommendationService, dest);
+ dest.writeString(mRecommendationServiceLabel);
ComponentName.writeToParcel(mEnableUseOpenWifiActivity, dest);
}
@@ -73,11 +78,17 @@ public final class NetworkScorerAppData implements Parcelable {
return mEnableUseOpenWifiActivity;
}
+ @Nullable
+ public String getRecommendationServiceLabel() {
+ return mRecommendationServiceLabel;
+ }
+
@Override
public String toString() {
return "NetworkScorerAppData{" +
"packageUid=" + packageUid +
", mRecommendationService=" + mRecommendationService +
+ ", mRecommendationServiceLabel=" + mRecommendationServiceLabel +
", mEnableUseOpenWifiActivity=" + mEnableUseOpenWifiActivity +
'}';
}
@@ -89,11 +100,13 @@ public final class NetworkScorerAppData implements Parcelable {
NetworkScorerAppData that = (NetworkScorerAppData) o;
return packageUid == that.packageUid &&
Objects.equals(mRecommendationService, that.mRecommendationService) &&
+ Objects.equals(mRecommendationServiceLabel, that.mRecommendationServiceLabel) &&
Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity);
}
@Override
public int hashCode() {
- return Objects.hash(packageUid, mRecommendationService, mEnableUseOpenWifiActivity);
+ return Objects.hash(packageUid, mRecommendationService, mRecommendationServiceLabel,
+ mEnableUseOpenWifiActivity);
}
}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 9ffe2fe7a709..734d89eb72af 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -211,7 +211,7 @@ public class BatteryManager {
/**
* Battery charge status, from a BATTERY_STATUS_* value.
*/
- public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6;
+ public static final int BATTERY_PROPERTY_STATUS = 6;
private final IBatteryStats mBatteryStats;
private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index b9e4bad5cf26..caea2020244c 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -506,7 +506,7 @@ public final class StrictMode {
}
/**
- * Detect unbuffered input/output operations.
+ * Disable detection of unbuffered input/output operations.
*/
public Builder permitUnbufferedIo() {
return disable(DETECT_UNBUFFERED_IO);
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index bf03cce947e2..8549cff1faad 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -26,7 +26,18 @@ import android.util.Log;
/**
* UpdateEngine handles calls to the update engine which takes care of A/B OTA
* updates. It wraps up the update engine Binder APIs and exposes them as
- * SystemApis, which will be called by system apps like GmsCore.
+ * SystemApis, which will be called by the system app responsible for OTAs.
+ * On a Google device, this will be GmsCore.
+ *
+ * The minimal flow is:
+ * <ol>
+ * <li>Create a new UpdateEngine instance.
+ * <li>Call {@link #bind}, optionally providing callbacks.
+ * <li>Call {@link #applyPayload}.
+ * </ol>
+ *
+ * In addition, methods are provided to {@link #cancel} or
+ * {@link #suspend}/{@link #resume} application of an update.
*
* The APIs defined in this class and UpdateEngineCallback class must be in
* sync with the ones in
@@ -80,12 +91,20 @@ public class UpdateEngine {
private IUpdateEngine mUpdateEngine;
+ /**
+ * Creates a new instance.
+ */
@SystemApi
public UpdateEngine() {
mUpdateEngine = IUpdateEngine.Stub.asInterface(
ServiceManager.getService(UPDATE_ENGINE_SERVICE));
}
+ /**
+ * Prepares this instance for use. The callback will be notified on any
+ * status change, and when the update completes. A handler can be supplied
+ * to control which thread runs the callback, or null.
+ */
@SystemApi
public boolean bind(final UpdateEngineCallback callback, final Handler handler) {
IUpdateEngineCallback updateEngineCallback = new IUpdateEngineCallback.Stub() {
@@ -125,11 +144,42 @@ public class UpdateEngine {
}
}
+ /**
+ * Equivalent to {@code bind(callback, null)}.
+ */
@SystemApi
public boolean bind(final UpdateEngineCallback callback) {
return bind(callback, null);
}
+ /**
+ * Applies the payload found at the given {@code url}. For non-streaming
+ * updates, the URL can be a local file using the {@code file://} scheme.
+ *
+ * <p>The {@code offset} and {@code size} parameters specify the location
+ * of the payload within the file represented by the URL. This is useful
+ * if the downloadable package at the URL contains more than just the
+ * update_engine payload (such as extra metadata). This is true for
+ * Google's OTA system, where the URL points to a zip file in which the
+ * payload is stored uncompressed within the zip file alongside other
+ * data.
+ *
+ * <p>The {@code headerKeyValuePairs} parameter is used to pass metadata
+ * to update_engine. In Google's implementation, this is stored as
+ * {@code payload_properties.txt} in the zip file. It's generated by the
+ * script {@code system/update_engine/scripts/brillo_update_payload}.
+ * The complete list of keys and their documentation is in
+ * {@code system/update_engine/common/constants.cc}, but an example
+ * might be:
+ * <pre>
+ * String[] pairs = {
+ * "FILE_HASH=lURPCIkIAjtMOyB/EjQcl8zDzqtD6Ta3tJef6G/+z2k=",
+ * "FILE_SIZE=871903868",
+ * "METADATA_HASH=tBvj43QOB0Jn++JojcpVdbRLz0qdAuL+uTkSy7hokaw=",
+ * "METADATA_SIZE=70604"
+ * };
+ * </pre>
+ */
@SystemApi
public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) {
try {
@@ -139,6 +189,15 @@ public class UpdateEngine {
}
}
+ /**
+ * Permanently cancels an in-progress update.
+ *
+ * <p>See {@link #resetStatus} to undo a finshed update (only available
+ * before the updated system has been rebooted).
+ *
+ * <p>See {@link #suspend} for a way to temporarily stop an in-progress
+ * update with the ability to resume it later.
+ */
@SystemApi
public void cancel() {
try {
@@ -148,6 +207,10 @@ public class UpdateEngine {
}
}
+ /**
+ * Suspends an in-progress update. This can be undone by calling
+ * {@link #resume}.
+ */
@SystemApi
public void suspend() {
try {
@@ -157,6 +220,9 @@ public class UpdateEngine {
}
}
+ /**
+ * Resumes a suspended update.
+ */
@SystemApi
public void resume() {
try {
@@ -166,6 +232,15 @@ public class UpdateEngine {
}
}
+ /**
+ * Resets the bootable flag on the non-current partition and all internal
+ * update_engine state. This can be used after an unwanted payload has been
+ * successfully applied and the device has not yet been rebooted to signal
+ * that we no longer want to boot into that updated system. After this call
+ * completes, update_engine will no longer report
+ * {@code UPDATED_NEED_REBOOT}, so your callback can remove any outstanding
+ * notification that rebooting into the new system is possible.
+ */
@SystemApi
public void resetStatus() {
try {
diff --git a/core/java/android/os/UpdateEngineCallback.java b/core/java/android/os/UpdateEngineCallback.java
index b3b856fcf142..afff60abb22b 100644
--- a/core/java/android/os/UpdateEngineCallback.java
+++ b/core/java/android/os/UpdateEngineCallback.java
@@ -19,7 +19,8 @@ package android.os;
import android.annotation.SystemApi;
/**
- * Callback function for UpdateEngine.
+ * Callback function for UpdateEngine. Used to keep the caller up to date
+ * with progress, so the UI (if any) can be updated.
*
* The APIs defined in this class and UpdateEngine class must be in sync with
* the ones in
@@ -31,9 +32,19 @@ import android.annotation.SystemApi;
@SystemApi
public abstract class UpdateEngineCallback {
+ /**
+ * Invoked when anything changes. The value of {@code status} will
+ * be one of the values from {@link UpdateEngine.UpdateStatusConstants},
+ * and {@code percent} will be valid [TODO: in which cases?].
+ */
@SystemApi
public abstract void onStatusUpdate(int status, float percent);
+ /**
+ * Invoked when the payload has been applied, whether successfully or
+ * unsuccessfully. The value of {@code errorCode} will be one of the
+ * values from {@link UpdateEngine.ErrorCodeConstants}.
+ */
@SystemApi
public abstract void onPayloadApplicationComplete(int errorCode);
}
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 7b63b626175f..a21e05e314b2 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -435,7 +435,7 @@ public class VolumeInfo implements Parcelable {
return null;
}
- final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(uri, DocumentsContract.Root.MIME_TYPE_ITEM);
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 089eaeceac55..62c5dca0ada1 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -410,11 +410,13 @@ public class Preference implements Comparable<Preference> {
/**
* Sets a {@link PreferenceDataStore} to be used by this Preference instead of using
* {@link android.content.SharedPreferences}.
- * <p>
- * The data store will remain assigned even if the Preference is moved between multiple
- * instances of {@link PreferenceFragment}.
+ *
+ * <p>The data store will remain assigned even if the Preference is moved around the preference
+ * hierarchy. It will also override a data store propagated from the {@link PreferenceManager}
+ * that owns this Preference.
*
* @param dataStore The {@link PreferenceDataStore} to be used by this Preference.
+ * @see PreferenceManager#setPreferenceDataStore(PreferenceDataStore)
*/
public void setPreferenceDataStore(PreferenceDataStore dataStore) {
mPreferenceDataStore = dataStore;
@@ -424,6 +426,12 @@ public class Preference implements Comparable<Preference> {
* Returns {@link PreferenceDataStore} used by this Preference. Returns {@code null} if
* {@link android.content.SharedPreferences} is used instead.
*
+ * <p>By default preferences always use {@link android.content.SharedPreferences}. To make this
+ * preference to use the {@link PreferenceDataStore} you need to assign your implementation
+ * to the Preference itself via {@link #setPreferenceDataStore(PreferenceDataStore)} or to its
+ * {@link PreferenceManager} via
+ * {@link PreferenceManager#setPreferenceDataStore(PreferenceDataStore)}.
+ *
* @return The {@link PreferenceDataStore} used by this Preference or {@code null} if none.
*/
@Nullable
@@ -1457,12 +1465,12 @@ public class Preference implements Comparable<Preference> {
}
/**
- * Implement this to set the initial value of the Preference.
+ * Implement this to set the initial value of the Preference.
* <p>
- * If <var>restorePersistedValue</var> is true, you should restore the
- * Preference value from the {@link android.content.SharedPreferences}. If
- * <var>restorePersistedValue</var> is false, you should set the Preference
- * value to defaultValue that is given (and possibly store to SharedPreferences
+ * If <var>restorePersistedValue</var> is true, you should restore the
+ * Preference value from the {@link android.content.SharedPreferences}. If
+ * <var>restorePersistedValue</var> is false, you should set the Preference
+ * value to defaultValue that is given (and possibly store to SharedPreferences
* if {@link #shouldPersist()} is true).
* <p>
* This may not always be called. One example is if it should not persist
diff --git a/core/java/android/preference/PreferenceDataStore.java b/core/java/android/preference/PreferenceDataStore.java
index e1a08acab6b7..8caa404d9859 100644
--- a/core/java/android/preference/PreferenceDataStore.java
+++ b/core/java/android/preference/PreferenceDataStore.java
@@ -21,16 +21,32 @@ import android.annotation.Nullable;
import java.util.Set;
/**
- * A data store interface to be implemented and provided to the Preferences framework.
+ * A data store interface to be implemented and provided to the Preferences framework. This can be
+ * used to replace the default {@link android.content.SharedPreferences}, if needed.
*
- * Use this to replace the default {@link android.content.SharedPreferences}. By default, all "put"
- * methods throw {@link UnsupportedOperationException}.
+ * <p>In most cases you want to use {@link android.content.SharedPreferences} as it is automatically
+ * backed up and migrated to new devices. However, providing custom data store to preferences can be
+ * useful if your app stores its preferences in a local db, cloud or they are device specific like
+ * "Developer settings". It might be also useful when you want to use the preferences UI but
+ * the data are not supposed to be stored at all because they are valid per session only.
+ *
+ * <p>Once a put method is called it is full responsibility of the data store implementation to
+ * safely store the given values. Time expensive operations need to be done in the background to
+ * prevent from blocking the UI. You also need to have a plan on how to serialize the data in case
+ * the activity holding this object gets destroyed.
+ *
+ * <p>By default, all "put" methods throw {@link UnsupportedOperationException}.
+ *
+ * @see Preference#setPreferenceDataStore(PreferenceDataStore)
+ * @see PreferenceManager#setPreferenceDataStore(PreferenceDataStore)
*/
public interface PreferenceDataStore {
/**
* Set a String value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param value The new value for the preference.
* @see #getString(String, String)
@@ -42,6 +58,8 @@ public interface PreferenceDataStore {
/**
* Set a set of String value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param values The set of new values for the preference.
* @see #getStringSet(String, Set)
@@ -53,6 +71,8 @@ public interface PreferenceDataStore {
/**
* Set an int value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param value The new value for the preference.
* @see #getInt(String, int)
@@ -64,6 +84,8 @@ public interface PreferenceDataStore {
/**
* Set a long value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param value The new value for the preference.
* @see #getLong(String, long)
@@ -75,6 +97,8 @@ public interface PreferenceDataStore {
/**
* Set a float value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param value The new value for the preference.
* @see #getFloat(String, float)
@@ -86,6 +110,8 @@ public interface PreferenceDataStore {
/**
* Set a boolean value to the data store.
*
+ * <p>Once the value is set the data store is responsible for holding it.
+ *
* @param key The name of the preference to modify.
* @param value The new value for the preference.
* @see #getBoolean(String, boolean)
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 756c3f482120..257037436802 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -208,10 +208,13 @@ public class PreferenceManager {
/**
* Sets a {@link PreferenceDataStore} to be used by all Preferences associated with this manager
- * that don't have a custom {@link PreferenceDataStore} assigned. Also if the data store is set,
- * the Preferences will no longer use {@link android.content.SharedPreferences}.
+ * that don't have a custom {@link PreferenceDataStore} assigned via
+ * {@link Preference#setPreferenceDataStore(PreferenceDataStore)}. Also if the data store is
+ * set, the child preferences won't use {@link android.content.SharedPreferences} as long as
+ * they are assigned to this manager.
*
* @param dataStore The {@link PreferenceDataStore} to be used by this manager.
+ * @see Preference#setPreferenceDataStore(PreferenceDataStore)
*/
public void setPreferenceDataStore(PreferenceDataStore dataStore) {
mPreferenceDataStore = dataStore;
@@ -219,9 +222,10 @@ public class PreferenceManager {
/**
* Returns the {@link PreferenceDataStore} associated with this manager or {@code null} if
- * {@link android.content.SharedPreferences} are used instead.
+ * the default {@link android.content.SharedPreferences} are used instead.
*
* @return The {@link PreferenceDataStore} associated with this manager or {@code null} if none.
+ * @see #setPreferenceDataStore(PreferenceDataStore)
*/
@Nullable
public PreferenceDataStore getPreferenceDataStore() {
@@ -358,8 +362,11 @@ public class PreferenceManager {
* Sets the name of the SharedPreferences file that preferences managed by this
* will use.
*
+ * <p>If custom {@link PreferenceDataStore} is set, this won't override its usage.
+ *
* @param sharedPreferencesName The name of the SharedPreferences file.
* @see Context#getSharedPreferences(String, int)
+ * @see #setPreferenceDataStore(PreferenceDataStore)
*/
public void setSharedPreferencesName(String sharedPreferencesName) {
mSharedPreferencesName = sharedPreferencesName;
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 54861628c465..71a0349bce54 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -162,9 +162,6 @@ public final class DocumentsContract {
public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT";
/** {@hide} */
- public static final String ACTION_BROWSE = "android.provider.action.BROWSE";
-
- /** {@hide} */
public static final String
ACTION_DOCUMENT_ROOT_SETTINGS = "android.provider.action.DOCUMENT_ROOT_SETTINGS";
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 5461e6b6d699..ad8ad69cb2b8 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -138,8 +138,6 @@ public final class KeymasterDefs {
public static final int KM_PURPOSE_DECRYPT = 1;
public static final int KM_PURPOSE_SIGN = 2;
public static final int KM_PURPOSE_VERIFY = 3;
- public static final int KM_PURPOSE_DERIVE_KEY = 4;
- public static final int KM_PURPOSE_WRAP_KEY = 5;
// Key formats.
public static final int KM_KEY_FORMAT_X509 = 0;
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 1781c2ac0d78..21168475adf7 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -126,7 +126,9 @@ public class TileService extends Service {
public static final String EXTRA_TOKEN = "token";
/**
- * @hide
+ * May be included when {@link #ACTION_QS_TILE_PREFERENCES} is launched from a tile.
+ * This extra may contain the {@link ComponentName} of the tile that triggered
+ * the preferences to be opened.
*/
public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b718696b2202..0ac16c1fa023 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -95,6 +95,11 @@ public class SurfaceControl {
IBinder displayToken, int mode);
private static native void nativeDeferTransactionUntil(long nativeObject,
IBinder handle, long frame);
+ private static native void nativeDeferTransactionUntilSurface(long nativeObject,
+ long surfaceObject, long frame);
+ private static native void nativeReparentChildren(long nativeObject,
+ IBinder handle);
+ private static native void nativeSeverChildren(long nativeObject);
private static native void nativeSetOverrideScalingMode(long nativeObject,
int scalingMode);
private static native IBinder nativeGetHandle(long nativeObject);
@@ -421,6 +426,18 @@ public class SurfaceControl {
nativeDeferTransactionUntil(mNativeObject, handle, frame);
}
+ public void deferTransactionUntil(Surface barrier, long frame) {
+ nativeDeferTransactionUntilSurface(mNativeObject, barrier.mNativeObject, frame);
+ }
+
+ public void reparentChildren(IBinder newParentHandle) {
+ nativeReparentChildren(mNativeObject, newParentHandle);
+ }
+
+ public void detachChildren() {
+ nativeSeverChildren(mNativeObject);
+ }
+
public void setOverrideScalingMode(int scalingMode) {
checkNotReleased();
nativeSetOverrideScalingMode(mNativeObject, scalingMode);
diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java
index 3cf5af484625..b5912bc1e1c8 100644
--- a/core/java/android/view/SurfaceSession.java
+++ b/core/java/android/view/SurfaceSession.java
@@ -27,6 +27,7 @@ public final class SurfaceSession {
private long mNativeClient; // SurfaceComposerClient*
private static native long nativeCreate();
+ private static native long nativeCreateScoped(long surfacePtr);
private static native void nativeDestroy(long ptr);
private static native void nativeKill(long ptr);
@@ -35,6 +36,10 @@ public final class SurfaceSession {
mNativeClient = nativeCreate();
}
+ public SurfaceSession(Surface root) {
+ mNativeClient = nativeCreateScoped(root.mNativeObject);
+ }
+
/* no user serviceable parts here ... */
@Override
protected void finalize() throws Throwable {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d2577d48c3d1..61b12475d542 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,6 +16,10 @@
package android.view;
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
+
import android.content.Context;
import android.content.res.CompatibilityInfo.Translator;
import android.content.res.Configuration;
@@ -26,16 +30,12 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.os.Handler;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
-import com.android.internal.view.BaseIWindow;
import com.android.internal.view.SurfaceCallbackHelper;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
@@ -92,8 +92,8 @@ import java.util.concurrent.locks.ReentrantLock;
* positioned asynchronously.</p>
*/
public class SurfaceView extends View {
- static private final String TAG = "SurfaceView";
- static private final boolean DEBUG = false;
+ private static final String TAG = "SurfaceView";
+ private static final boolean DEBUG = false;
final ArrayList<SurfaceHolder.Callback> mCallbacks
= new ArrayList<SurfaceHolder.Callback>();
@@ -102,28 +102,23 @@ public class SurfaceView extends View {
final ReentrantLock mSurfaceLock = new ReentrantLock();
final Surface mSurface = new Surface(); // Current surface in use
- final Surface mNewSurface = new Surface(); // New surface we are switching to
boolean mDrawingStopped = true;
+ // We use this to track if the application has produced a frame
+ // in to the Surface. Up until that point, we should be careful not to punch
+ // holes.
+ boolean mDrawFinished = false;
+
+ final Rect mScreenRect = new Rect();
+ SurfaceSession mSurfaceSession;
- final WindowManager.LayoutParams mLayout
- = new WindowManager.LayoutParams();
- IWindowSession mSession;
- MyWindow mWindow;
- final Rect mVisibleInsets = new Rect();
- final Rect mWinFrame = new Rect();
- final Rect mOverscanInsets = new Rect();
- final Rect mContentInsets = new Rect();
- final Rect mStableInsets = new Rect();
- final Rect mOutsets = new Rect();
- final Rect mBackdropFrame = new Rect();
+ SurfaceControl mSurfaceControl;
final Rect mTmpRect = new Rect();
final Configuration mConfiguration = new Configuration();
static final int KEEP_SCREEN_ON_MSG = 1;
- static final int GET_NEW_SURFACE_MSG = 2;
- static final int UPDATE_WINDOW_MSG = 3;
+ static final int DRAW_FINISHED_MSG = 2;
- int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+ int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
boolean mIsCreating = false;
private volatile boolean mRtHandlingPositionUpdates = false;
@@ -135,11 +130,9 @@ public class SurfaceView extends View {
case KEEP_SCREEN_ON_MSG: {
setKeepScreenOn(msg.arg1 != 0);
} break;
- case GET_NEW_SURFACE_MSG: {
- handleGetNewSurface();
- } break;
- case UPDATE_WINDOW_MSG: {
- updateWindow();
+ case DRAW_FINISHED_MSG: {
+ mDrawFinished = true;
+ invalidate();
} break;
}
}
@@ -149,7 +142,7 @@ public class SurfaceView extends View {
= new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
- updateWindow();
+ updateSurface();
}
};
@@ -159,13 +152,14 @@ public class SurfaceView extends View {
public boolean onPreDraw() {
// reposition ourselves where the surface is
mHaveFrame = getWidth() > 0 && getHeight() > 0;
- updateWindow();
+ updateSurface();
return true;
}
};
boolean mRequestedVisible = false;
boolean mWindowVisibility = false;
+ boolean mLastWindowVisibility = false;
boolean mViewVisibility = false;
int mRequestedWidth = -1;
int mRequestedHeight = -1;
@@ -181,19 +175,17 @@ public class SurfaceView extends View {
boolean mVisible = false;
int mWindowSpaceLeft = -1;
int mWindowSpaceTop = -1;
- int mWindowSpaceWidth = -1;
- int mWindowSpaceHeight = -1;
+ int mSurfaceWidth = -1;
+ int mSurfaceHeight = -1;
int mFormat = -1;
final Rect mSurfaceFrame = new Rect();
int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
- boolean mUpdateWindowNeeded;
- boolean mReportDrawNeeded;
private Translator mTranslator;
- private int mWindowInsetLeft;
- private int mWindowInsetTop;
private boolean mGlobalListenersAdded;
+ private int mSurfaceFlags = SurfaceControl.HIDDEN;
+
public SurfaceView(Context context) {
this(context, null);
}
@@ -227,11 +219,8 @@ public class SurfaceView extends View {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mParent.requestTransparentRegion(this);
- mSession = getWindowSession();
- mLayout.token = getWindowToken();
- mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
- mLayout.packageName = mContext.getOpPackageName();
mViewVisibility = getVisibility() == VISIBLE;
+ mRequestedVisible = mViewVisibility && mWindowVisibility;
if (!mGlobalListenersAdded) {
ViewTreeObserver observer = getViewTreeObserver();
@@ -246,7 +235,7 @@ public class SurfaceView extends View {
super.onWindowVisibilityChanged(visibility);
mWindowVisibility = visibility == VISIBLE;
mRequestedVisible = mWindowVisibility && mViewVisibility;
- updateWindow();
+ updateSurface();
}
@Override
@@ -264,7 +253,7 @@ public class SurfaceView extends View {
requestLayout();
}
mRequestedVisible = newRequestedVisible;
- updateWindow();
+ updateSurface();
}
@Override
@@ -277,19 +266,14 @@ public class SurfaceView extends View {
}
mRequestedVisible = false;
- updateWindow();
- mHaveFrame = false;
- if (mWindow != null) {
- try {
- mSession.remove(mWindow);
- } catch (RemoteException ex) {
- // Not much we can do here...
- }
- mWindow = null;
+
+ updateSurface();
+ if (mSurfaceControl != null) {
+ mSurfaceControl.destroy();
}
- mSession = null;
- mLayout.token = null;
+ mSurfaceControl = null;
+ mHaveFrame = false;
super.onDetachedFromWindow();
}
@@ -308,13 +292,13 @@ public class SurfaceView extends View {
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
boolean result = super.setFrame(left, top, right, bottom);
- updateWindow();
+ updateSurface();
return result;
}
@Override
public boolean gatherTransparentRegion(Region region) {
- if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+ if (isAboveParent()) {
return super.gatherTransparentRegion(region);
}
@@ -341,7 +325,7 @@ public class SurfaceView extends View {
@Override
public void draw(Canvas canvas) {
- if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+ if (mDrawFinished && !isAboveParent()) {
// draw() is not called when SKIP_DRAW is set
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
// punch a whole in the view-hierarchy below us
@@ -353,8 +337,8 @@ public class SurfaceView extends View {
@Override
protected void dispatchDraw(Canvas canvas) {
- if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
- // if SKIP_DRAW is cleared, draw() has already punched a hole
+ if (mDrawFinished && !isAboveParent()) {
+ // draw() is not called when SKIP_DRAW is set
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
// punch a whole in the view-hierarchy below us
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
@@ -375,9 +359,8 @@ public class SurfaceView extends View {
* <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
*/
public void setZOrderMediaOverlay(boolean isMediaOverlay) {
- mWindowType = isMediaOverlay
- ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
- : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+ mSubLayer = isMediaOverlay
+ ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
}
/**
@@ -395,12 +378,9 @@ public class SurfaceView extends View {
*/
public void setZOrderOnTop(boolean onTop) {
if (onTop) {
- mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
- // ensures the surface is placed below the IME
- mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mSubLayer = APPLICATION_PANEL_SUBLAYER;
} else {
- mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
- mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mSubLayer = APPLICATION_MEDIA_SUBLAYER;
}
}
@@ -418,31 +398,32 @@ public class SurfaceView extends View {
*/
public void setSecure(boolean isSecure) {
if (isSecure) {
- mLayout.flags |= WindowManager.LayoutParams.FLAG_SECURE;
+ mSurfaceFlags |= SurfaceControl.SECURE;
} else {
- mLayout.flags &= ~WindowManager.LayoutParams.FLAG_SECURE;
+ mSurfaceFlags &= ~SurfaceControl.SECURE;
}
}
- /**
- * Hack to allow special layering of windows. The type is one of the
- * types in WindowManager.LayoutParams. This is a hack so:
- * @hide
- */
- public void setWindowType(int type) {
- mWindowType = type;
+ private Rect getParentSurfaceInsets() {
+ final ViewRootImpl root = getViewRootImpl();
+ if (root == null) {
+ return null;
+ } else {
+ return root.mWindowAttributes.surfaceInsets;
+ }
}
/** @hide */
- protected void updateWindow() {
+ protected void updateSurface() {
if (!mHaveFrame) {
return;
}
ViewRootImpl viewRoot = getViewRootImpl();
- if (viewRoot != null) {
- mTranslator = viewRoot.mTranslator;
+ if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
+ return;
}
+ mTranslator = viewRoot.mTranslator;
if (mTranslator != null) {
mSurface.setCompatibilityTranslator(mTranslator);
}
@@ -452,17 +433,15 @@ public class SurfaceView extends View {
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
- final boolean creating = mWindow == null;
final boolean formatChanged = mFormat != mRequestedFormat;
- final boolean sizeChanged = mWindowSpaceWidth != myWidth || mWindowSpaceHeight != myHeight;
+ final boolean creating = (mSurfaceControl == null || formatChanged)
+ && mRequestedVisible;
+ final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
final boolean visibleChanged = mVisible != mRequestedVisible;
- final boolean layoutSizeChanged = getWidth() != mLayout.width
- || getHeight() != mLayout.height;
-
+ final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
boolean redrawNeeded = false;
- if (creating || formatChanged || sizeChanged || visibleChanged
- || mUpdateWindowNeeded || mReportDrawNeeded) {
+ if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
getLocationInWindow(mLocation);
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
@@ -476,93 +455,77 @@ public class SurfaceView extends View {
final boolean visible = mVisible = mRequestedVisible;
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
- mWindowSpaceWidth = myWidth;
- mWindowSpaceHeight = myHeight;
+ mSurfaceWidth = myWidth;
+ mSurfaceHeight = myHeight;
mFormat = mRequestedFormat;
+ mLastWindowVisibility = mWindowVisibility;
- // Scaling/Translate window's layout here because mLayout is not used elsewhere.
-
- // Places the window relative
- mLayout.x = mWindowSpaceLeft;
- mLayout.y = mWindowSpaceTop;
- mLayout.width = getWidth();
- mLayout.height = getHeight();
+ mScreenRect.left = mWindowSpaceLeft;
+ mScreenRect.top = mWindowSpaceTop;
+ mScreenRect.right = mWindowSpaceLeft + getWidth();
+ mScreenRect.bottom = mWindowSpaceTop + getHeight();
if (mTranslator != null) {
- mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
+ mTranslator.translateRectInAppWindowToScreen(mScreenRect);
}
- mLayout.format = mRequestedFormat;
- mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
- | WindowManager.LayoutParams.FLAG_SCALED
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- ;
- if (!creating && !sizeChanged) {
- mLayout.privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
- } else {
- mLayout.privateFlags &=
- ~WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
- }
+ final Rect surfaceInsets = getParentSurfaceInsets();
+ mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
- if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
- mLayout.privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
- }
- mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
- | WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
-
- if (mWindow == null) {
- Display display = getDisplay();
- mWindow = new MyWindow(this);
- mLayout.type = mWindowType;
- mLayout.gravity = Gravity.START|Gravity.TOP;
- mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
- mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets,
- mStableInsets);
+ if (creating) {
+ mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
+ mSurfaceControl = new SurfaceControl(mSurfaceSession,
+ "SurfaceView - " + viewRoot.getTitle().toString(),
+ mSurfaceWidth, mSurfaceHeight, mFormat,
+ mSurfaceFlags);
}
- boolean realSizeChanged;
- boolean reportDrawNeeded;
-
- int relayoutResult;
+ boolean realSizeChanged = false;
mSurfaceLock.lock();
try {
- mUpdateWindowNeeded = false;
- reportDrawNeeded = mReportDrawNeeded;
- mReportDrawNeeded = false;
mDrawingStopped = !visible;
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "Cur surface: " + mSurface);
- relayoutResult = mSession.relayout(
- mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight,
- visible ? VISIBLE : GONE,
- WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
- mWinFrame, mOverscanInsets, mContentInsets,
- mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
- mConfiguration, mNewSurface);
- if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
- reportDrawNeeded = true;
+ SurfaceControl.openTransaction();
+ try {
+ mSurfaceControl.setLayer(mSubLayer);
+ if (mViewVisibility) {
+ mSurfaceControl.show();
+ } else {
+ mSurfaceControl.hide();
+ }
+
+ // While creating the surface, we will set it's initial
+ // geometry. Outside of that though, we should generally
+ // leave it to the RenderThread.
+ if (creating || !mRtHandlingPositionUpdates) {
+ mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
+ mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
+ 0.0f, 0.0f,
+ mScreenRect.height() / (float) mSurfaceHeight);
+ }
+ if (sizeChanged) {
+ mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
+ }
+ } finally {
+ SurfaceControl.closeTransaction();
}
- if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
- + "New surface: " + mNewSurface
- + ", vis=" + visible + ", frame=" + mWinFrame);
+ if (sizeChanged || creating) {
+ redrawNeeded = true;
+ }
mSurfaceFrame.left = 0;
mSurfaceFrame.top = 0;
if (mTranslator == null) {
- mSurfaceFrame.right = mWinFrame.width();
- mSurfaceFrame.bottom = mWinFrame.height();
+ mSurfaceFrame.right = mSurfaceWidth;
+ mSurfaceFrame.bottom = mSurfaceHeight;
} else {
float appInvertedScale = mTranslator.applicationInvertedScale;
- mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
- mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
+ mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
+ mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
}
final int surfaceWidth = mSurfaceFrame.right;
@@ -576,12 +539,11 @@ public class SurfaceView extends View {
}
try {
- redrawNeeded |= creating | reportDrawNeeded;
+ redrawNeeded |= visible && !mDrawFinished;
SurfaceHolder.Callback callbacks[] = null;
- final boolean surfaceChanged = (relayoutResult
- & WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
+ final boolean surfaceChanged = creating;
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
mSurfaceCreated = false;
if (mSurface.isValid()) {
@@ -608,7 +570,10 @@ public class SurfaceView extends View {
}
}
- mSurface.transferFrom(mNewSurface);
+ if (creating) {
+ mSurface.copyFrom(mSurfaceControl);
+ }
+
if (visible && mSurface.isValid()) {
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
@@ -641,53 +606,55 @@ public class SurfaceView extends View {
callbacks = getSurfaceCallbacks();
}
SurfaceCallbackHelper sch =
- new SurfaceCallbackHelper(mSession, mWindow);
+ new SurfaceCallbackHelper(this::onDrawFinished);
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
}
}
} finally {
mIsCreating = false;
- mSession.performDeferredDestroy(mWindow);
+ if (mSurfaceControl != null && !mSurfaceCreated) {
+ mSurfaceControl.destroy();
+ mSurfaceControl = null;
+ }
}
- } catch (RemoteException ex) {
+ } catch (Exception ex) {
Log.e(TAG, "Exception from relayout", ex);
}
if (DEBUG) Log.v(
- TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
- " w=" + mLayout.width + " h=" + mLayout.height +
- ", frame=" + mSurfaceFrame);
+ TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
+ + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
+ + ", frame=" + mSurfaceFrame);
} else {
// Calculate the window position in case RT loses the window
// and we need to fallback to a UI-thread driven position update
- getLocationInWindow(mLocation);
+ getLocationInSurface(mLocation);
final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
|| mWindowSpaceTop != mLocation[1];
+ final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
+ || getHeight() != mScreenRect.height();
if (positionChanged || layoutSizeChanged) { // Only the position has changed
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
- // For our size changed check, we keep mLayout.width and mLayout.height
+ // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
// in view local space.
- mLocation[0] = mLayout.width = getWidth();
- mLocation[1] = mLayout.height = getHeight();
-
- transformFromViewToWindowSpace(mLocation);
+ mLocation[0] = getWidth();
+ mLocation[1] = getHeight();
- mTmpRect.set(mWindowSpaceLeft, mWindowSpaceTop,
+ mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
mLocation[0], mLocation[1]);
if (mTranslator != null) {
- mTranslator.translateRectInAppWindowToScreen(mTmpRect);
+ mTranslator.translateRectInAppWindowToScreen(mScreenRect);
}
if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
try {
- if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition UI, " +
+ if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
- mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom));
- mSession.repositionChild(mWindow, mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom, -1, mTmpRect);
- } catch (RemoteException ex) {
+ mScreenRect.left, mScreenRect.top,
+ mScreenRect.right, mScreenRect.bottom));
+ setParentSpaceRectangle(mScreenRect, -1);
+ } catch (Exception ex) {
Log.e(TAG, "Exception from relayout", ex);
}
}
@@ -695,20 +662,43 @@ public class SurfaceView extends View {
}
}
+ private void onDrawFinished() {
+ if (DEBUG) {
+ Log.i(TAG, System.identityHashCode(this) + " "
+ + "finishedDrawing");
+ }
+ mHandler.sendEmptyMessage(DRAW_FINISHED_MSG);
+ }
+
+ private void setParentSpaceRectangle(Rect position, long frameNumber) {
+ ViewRootImpl viewRoot = getViewRootImpl();
+
+ SurfaceControl.openTransaction();
+ try {
+ if (frameNumber > 0) {
+ mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber);
+ }
+ mSurfaceControl.setPosition(position.left, position.top);
+ mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth,
+ 0.0f, 0.0f,
+ position.height() / (float) mSurfaceHeight);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+
private Rect mRTLastReportedPosition = new Rect();
/**
* Called by native by a Rendering Worker thread to update the window position
* @hide
*/
- public final void updateWindowPosition_renderWorker(long frameNumber,
+ public final void updateSurfacePosition_renderWorker(long frameNumber,
int left, int top, int right, int bottom) {
- IWindowSession session = mSession;
- MyWindow window = mWindow;
- if (session == null || window == null) {
- // Guess we got detached, that sucks
+ if (mSurfaceControl == null) {
return;
}
+
// TODO: This is teensy bit racey in that a brand new SurfaceView moving on
// its 2nd frame if RenderThread is running slowly could potentially see
// this as false, enter the branch, get pre-empted, then this comes along
@@ -726,35 +716,29 @@ public class SurfaceView extends View {
}
try {
if (DEBUG) {
- Log.d(TAG, String.format("%d updateWindowPosition RenderWorker, frameNr = %d, " +
+ Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
frameNumber, left, top, right, bottom));
}
- // Just using mRTLastReportedPosition as a dummy rect here
- session.repositionChild(window, left, top, right, bottom,
- frameNumber,
- mRTLastReportedPosition);
- // Now overwrite mRTLastReportedPosition with our values
mRTLastReportedPosition.set(left, top, right, bottom);
- } catch (RemoteException ex) {
+ setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
+ // Now overwrite mRTLastReportedPosition with our values
+ } catch (Exception ex) {
Log.e(TAG, "Exception from repositionChild", ex);
}
}
/**
- * Called by native on RenderThread to notify that the window is no longer in the
+ * Called by native on RenderThread to notify that the view is no longer in the
* draw tree. UI thread is blocked at this point.
* @hide
*/
- public final void windowPositionLost_uiRtSync(long frameNumber) {
+ public final void surfacePositionLost_uiRtSync(long frameNumber) {
if (DEBUG) {
Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
System.identityHashCode(this), frameNumber));
}
- IWindowSession session = mSession;
- MyWindow window = mWindow;
- if (session == null || window == null) {
- // We got detached prior to receiving this, abort
+ if (mSurfaceControl == null) {
return;
}
if (mRtHandlingPositionUpdates) {
@@ -763,19 +747,14 @@ public class SurfaceView extends View {
// safely access other member variables at this time.
// So do what the UI thread would have done if RT wasn't handling position
// updates.
- mTmpRect.set(mLayout.x, mLayout.y,
- mLayout.x + mLayout.width,
- mLayout.y + mLayout.height);
-
- if (!mTmpRect.isEmpty() && !mTmpRect.equals(mRTLastReportedPosition)) {
+ if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
try {
- if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition, " +
+ if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
- mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom));
- session.repositionChild(window, mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom, frameNumber, mWinFrame);
- } catch (RemoteException ex) {
+ mScreenRect.left, mScreenRect.top,
+ mScreenRect.right, mScreenRect.bottom));
+ setParentSpaceRectangle(mScreenRect, frameNumber);
+ } catch (Exception ex) {
Log.e(TAG, "Exception from relayout", ex);
}
}
@@ -792,10 +771,6 @@ public class SurfaceView extends View {
return callbacks;
}
- void handleGetNewSurface() {
- updateWindow();
- }
-
/**
* Check to see if the surface has fixed size dimensions or if the surface's
* dimensions are dimensions are dependent on its current layout.
@@ -807,65 +782,8 @@ public class SurfaceView extends View {
return (mRequestedWidth != -1 || mRequestedHeight != -1);
}
- private static class MyWindow extends BaseIWindow {
- private final WeakReference<SurfaceView> mSurfaceView;
-
- public MyWindow(SurfaceView surfaceView) {
- mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
- }
-
- @Override
- public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropRect, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
- SurfaceView surfaceView = mSurfaceView.get();
- if (surfaceView != null) {
- if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width()
- + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
- surfaceView.mSurfaceLock.lock();
- try {
- if (reportDraw) {
- surfaceView.mUpdateWindowNeeded = true;
- surfaceView.mReportDrawNeeded = true;
- surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
- } else if (surfaceView.mWinFrame.width() != frame.width()
- || surfaceView.mWinFrame.height() != frame.height()
- || forceLayout) {
- surfaceView.mUpdateWindowNeeded = true;
- surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
- }
- } finally {
- surfaceView.mSurfaceLock.unlock();
- }
- }
- }
-
- @Override
- public void dispatchAppVisibility(boolean visible) {
- // The point of SurfaceView is to let the app control the surface.
- }
-
- @Override
- public void dispatchGetNewSurface() {
- SurfaceView surfaceView = mSurfaceView.get();
- if (surfaceView != null) {
- Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
- surfaceView.mHandler.sendMessage(msg);
- }
- }
-
- @Override
- public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
- Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
- }
-
- @Override
- public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
- }
-
- int mCurWidth = -1;
- int mCurHeight = -1;
+ private boolean isAboveParent() {
+ return mSubLayer >= 0;
}
private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
@@ -913,15 +831,14 @@ public class SurfaceView extends View {
@Override
public void setFormat(int format) {
-
// for backward compatibility reason, OPAQUE always
// means 565 for SurfaceView
if (format == PixelFormat.OPAQUE)
format = PixelFormat.RGB_565;
mRequestedFormat = format;
- if (mWindow != null) {
- updateWindow();
+ if (mSurfaceControl != null) {
+ updateSurface();
}
}
@@ -982,10 +899,10 @@ public class SurfaceView extends View {
mSurfaceLock.lock();
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
- + mDrawingStopped + ", win=" + mWindow);
+ + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
Canvas c = null;
- if (!mDrawingStopped && mWindow != null) {
+ if (!mDrawingStopped && mSurfaceControl != null) {
try {
if (hardware) {
c = mSurface.lockHardwareCanvas();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 20d960fff661..f9863b0a6761 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2632,6 +2632,14 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ private void onDrawFinished() {
+ try {
+ mWindowSession.finishDrawing(mWindow);
+ } catch (RemoteException e) {
+ // Have fun!
+ }
+ }
+
private void performDraw() {
if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
return;
@@ -2682,7 +2690,7 @@ public final class ViewRootImpl implements ViewParent,
}
if (mSurfaceHolder != null && mSurface.isValid()) {
- SurfaceCallbackHelper sch = new SurfaceCallbackHelper(mWindowSession, mWindow);
+ SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::onDrawFinished);
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 84c2c8452e98..43560f0cab1c 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -316,6 +316,13 @@ public abstract class ViewStructure {
public abstract void setAutoFillOptions(String[] options);
/**
+ * Sets the {@link android.text.InputType} bits of this node.
+ *
+ * @param inputType inputType bits as defined by {@link android.text.InputType}.
+ */
+ public abstract void setInputType(int inputType);
+
+ /**
* Marks this node as sanitized so its content are sent on {@link
* android.service.autofill.AutoFillService#onFillRequest(android.app.assist.AssistStructure,
* Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback)}.
diff --git a/core/java/android/view/autofill/AutoFillType.java b/core/java/android/view/autofill/AutoFillType.java
index 5d85bfdac095..e97470517833 100644
--- a/core/java/android/view/autofill/AutoFillType.java
+++ b/core/java/android/view/autofill/AutoFillType.java
@@ -40,18 +40,13 @@ public final class AutoFillType implements Parcelable {
private static class DefaultTypesHolder {
static final AutoFillType TOGGLE = new AutoFillType(TYPE_TOGGLE, 0);
static final AutoFillType LIST = new AutoFillType(TYPE_LIST, 0);
+ static final AutoFillType DATE = new AutoFillType(TYPE_DATE, 0);
}
private static final int TYPE_TEXT = 1;
private static final int TYPE_TOGGLE = 2;
private static final int TYPE_LIST = 3;
-
- // TODO(b/33197203): add others, like date picker? That would be trick, because they're set as:
- // updateDate(int year, int month, int dayOfMonth)
- // So, we would have to either use a long representing the Date.time(), or a custom long
- // representing:
- // year * 10000 + month * 100 + day
- // Then a custom getDatePickerValue(Bundle) that returns an immutable object with these 3 fields
+ private static final int TYPE_DATE = 4;
private final int mType;
private final int mSubType;
@@ -65,7 +60,7 @@ public final class AutoFillType implements Parcelable {
* Checks if this is a type for a text field, which is filled by a {@link CharSequence}.
*
* <p>{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through
- * {@link AutoFillValue#forText(CharSequence)}, and the value of a bundle passed to auto-fill a
+ * {@link AutoFillValue#forText(CharSequence)}, and the value passed to auto-fill a
* {@link View} can be fetched through {@link AutoFillValue#getTextValue()}.
*
* <p>Sub-type for this type is the value defined by {@link TextView#getInputType()}.
@@ -78,7 +73,7 @@ public final class AutoFillType implements Parcelable {
* Checks if this is a a type for a togglable field, which is filled by a {@code boolean}.
*
* <p>{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through
- * {@link AutoFillValue#forToggle(boolean)}, and the value of a bundle passed to auto-fill a
+ * {@link AutoFillValue#forToggle(boolean)}, and the value passed to auto-fill a
* {@link View} can be fetched through {@link AutoFillValue#getToggleValue()}.
*
* <p>This type has no sub-types.
@@ -92,7 +87,7 @@ public final class AutoFillType implements Parcelable {
* representing the element index inside the list (starting at {@code 0}.
*
* <p>{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through
- * {@link AutoFillValue#forList(int)}, and the value of a bundle passed to auto-fill a
+ * {@link AutoFillValue#forList(int)}, and the value passed to auto-fill a
* {@link View} can be fetched through {@link AutoFillValue#getListValue()}.
*
* <p>This type has no sub-types.
@@ -101,6 +96,20 @@ public final class AutoFillType implements Parcelable {
return mType == TYPE_LIST;
}
+ /**
+ * Checks if this is a type for a date and time, which is represented by a long representing
+ * the number of milliseconds since the standard base time known as "the epoch", namely
+ * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}.
+ *
+ * <p>{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through
+ * {@link AutoFillValue#forDate(long)}, and the values passed to
+ * auto-fill a {@link View} can be fetched through {@link AutoFillValue#getDateValue()}.
+ *
+ * <p>This type has no sub-types.
+ */
+ public boolean isDate() {
+ return mType == TYPE_DATE;
+ }
/**
* Gets the optional sub-type, representing the {@link View}'s semantic.
@@ -206,4 +215,13 @@ public final class AutoFillType implements Parcelable {
public static AutoFillType forList() {
return DefaultTypesHolder.LIST;
}
+
+ /**
+ * Creates a type that represents a date.
+ *
+ * <p>See {@link #isDate()} for more info.
+ */
+ public static AutoFillType forDate() {
+ return DefaultTypesHolder.DATE;
+ }
}
diff --git a/core/java/android/view/autofill/AutoFillValue.java b/core/java/android/view/autofill/AutoFillValue.java
index d9afa3ba2dee..c24e04e50154 100644
--- a/core/java/android/view/autofill/AutoFillValue.java
+++ b/core/java/android/view/autofill/AutoFillValue.java
@@ -35,11 +35,13 @@ public final class AutoFillValue implements Parcelable {
private final String mText;
private final int mListIndex;
private final boolean mToggle;
+ private final long mDate;
- private AutoFillValue(CharSequence text, int listIndex, boolean toggle) {
+ private AutoFillValue(CharSequence text, int listIndex, boolean toggle, long date) {
mText = (text == null) ? null : text.toString();
mListIndex = listIndex;
mToggle = toggle;
+ mDate = date;
}
/**
@@ -69,6 +71,17 @@ public final class AutoFillValue implements Parcelable {
return mListIndex;
}
+ /**
+ * Gets the value representing the the number of milliseconds since the standard base time known
+ * as "the epoch", namely January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}
+ * of a date field.
+ *
+ * <p>See {@link AutoFillType#isDate()} for more info.
+ */
+ public long getDateValue() {
+ return mDate;
+ }
+
/////////////////////////////////////
// Object "contract" methods. //
/////////////////////////////////////
@@ -77,9 +90,10 @@ public final class AutoFillValue implements Parcelable {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + mListIndex;
result = prime * result + ((mText == null) ? 0 : mText.hashCode());
+ result = prime * result + mListIndex;
result = prime * result + (mToggle ? 1231 : 1237);
+ result = prime * result + (int) (mDate ^ (mDate >>> 32));
return result;
}
@@ -89,13 +103,14 @@ public final class AutoFillValue implements Parcelable {
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final AutoFillValue other = (AutoFillValue) obj;
- if (mListIndex != other.mListIndex) return false;
if (mText == null) {
if (other.mText != null) return false;
} else {
if (!mText.equals(other.mText)) return false;
}
+ if (mListIndex != other.mListIndex) return false;
if (mToggle != other.mToggle) return false;
+ if (mDate != other.mDate) return false;
return true;
}
@@ -113,7 +128,7 @@ public final class AutoFillValue implements Parcelable {
return mText.length() + "_chars";
}
- return "[listIndex=" + mListIndex + ", toggle=" + mToggle + "]";
+ return "[l=" + mListIndex + ", t=" + mToggle + ", d=" + mDate + "]";
}
/////////////////////////////////////
@@ -130,12 +145,14 @@ public final class AutoFillValue implements Parcelable {
parcel.writeString(mText);
parcel.writeInt(mListIndex);
parcel.writeInt(mToggle ? 1 : 0);
+ parcel.writeLong(mDate);
}
private AutoFillValue(Parcel parcel) {
mText = parcel.readString();
mListIndex = parcel.readInt();
mToggle = parcel.readInt() == 1;
+ mDate = parcel.readLong();
}
public static final Parcelable.Creator<AutoFillValue> CREATOR =
@@ -157,31 +174,42 @@ public final class AutoFillValue implements Parcelable {
// TODO(b/33197203): add unit tests for each supported type (new / get should return same value)
/**
- * Creates a new {@link AutoFillValue} to auto-fill a text field.
+ * Creates a new {@link AutoFillValue} to auto-fill a {@link View} representing a text field.
*
* <p>See {@link AutoFillType#isText()} for more info.
*/
// TODO(b/33197203): use cache
@Nullable
public static AutoFillValue forText(@Nullable CharSequence value) {
- return value == null ? null : new AutoFillValue(value, 0, false);
+ return value == null ? null : new AutoFillValue(value, 0, false, 0);
}
/**
- * Creates a new {@link AutoFillValue} to auto-fill a toggable field.
+ * Creates a new {@link AutoFillValue} to auto-fill a {@link View} representing a toggable
+ * field.
*
* <p>See {@link AutoFillType#isToggle()} for more info.
*/
public static AutoFillValue forToggle(boolean value) {
- return new AutoFillValue(null, 0, value);
+ return new AutoFillValue(null, 0, value, 0);
}
/**
- * Creates a new {@link AutoFillValue} to auto-fill a selection list field.
+ * Creates a new {@link AutoFillValue} to auto-fill a {@link View} representing a selection
+ * list.
*
* <p>See {@link AutoFillType#isList()} for more info.
*/
public static AutoFillValue forList(int value) {
- return new AutoFillValue(null, value, false);
+ return new AutoFillValue(null, value, false, 0);
+ }
+
+ /**
+ * Creates a new {@link AutoFillValue} to auto-fill a {@link View} representing a date.
+ *
+ * <p>See {@link AutoFillType#isDate()} for more info.
+ */
+ public static AutoFillValue forDate(long date) {
+ return new AutoFillValue(null, 0, false, date);
}
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 887c59a2d71c..141b52fd2ce3 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -591,7 +591,7 @@ public abstract class CompoundButton extends Button implements Checkable {
@Override
public AutoFillType getAutoFillType() {
- return AutoFillType.forToggle();
+ return isEnabled() ? AutoFillType.forToggle() : null;
}
@Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 517e20cd1947..0ffefd091b06 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -31,7 +31,11 @@ import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.View;
+import android.view.ViewStructure;
import android.view.accessibility.AccessibilityEvent;
+import android.view.autofill.AutoFillManager;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
import com.android.internal.R;
@@ -170,6 +174,13 @@ public class DatePicker extends FrameLayout {
if (firstDayOfWeek != 0) {
setFirstDayOfWeek(firstDayOfWeek);
}
+
+ mDelegate.setAutoFillChangeListener((v, y, m, d) -> {
+ final AutoFillManager afm = context.getSystemService(AutoFillManager.class);
+ if (afm != null) {
+ afm.valueChanged(this);
+ }
+ });
}
private DatePickerDelegate createSpinnerUIDelegate(Context context, AttributeSet attrs,
@@ -503,12 +514,15 @@ public class DatePicker extends FrameLayout {
OnDateChangedListener onDateChangedListener);
void setOnDateChangedListener(OnDateChangedListener onDateChangedListener);
+ void setAutoFillChangeListener(OnDateChangedListener onDateChangedListener);
void updateDate(int year, int month, int dayOfMonth);
+ void updateDate(long date);
int getYear();
int getMonth();
int getDayOfMonth();
+ long getDate();
void setFirstDayOfWeek(int firstDayOfWeek);
int getFirstDayOfWeek();
@@ -558,6 +572,7 @@ public class DatePicker extends FrameLayout {
// Callbacks
protected OnDateChangedListener mOnDateChangedListener;
+ protected OnDateChangedListener mAutoFillChangeListener;
protected ValidationCallback mValidationCallback;
public AbstractDatePickerDelegate(DatePicker delegator, Context context) {
@@ -580,10 +595,28 @@ public class DatePicker extends FrameLayout {
}
@Override
+ public void setAutoFillChangeListener(OnDateChangedListener callback) {
+ mAutoFillChangeListener = callback;
+ }
+
+ @Override
public void setValidationCallback(ValidationCallback callback) {
mValidationCallback = callback;
}
+ @Override
+ public void updateDate(long date) {
+ Calendar cal = Calendar.getInstance(mCurrentLocale);
+ cal.setTimeInMillis(date);
+ updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
+ cal.get(Calendar.DAY_OF_MONTH));
+ }
+
+ @Override
+ public long getDate() {
+ return mCurrentDate.getTimeInMillis();
+ }
+
protected void onValidationChanged(boolean valid) {
if (mValidationCallback != null) {
mValidationCallback.onValidationChanged(valid);
@@ -723,4 +756,31 @@ public class DatePicker extends FrameLayout {
public interface ValidationCallback {
void onValidationChanged(boolean valid);
}
+
+ // TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
+
+ @Override
+ public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
+ // This view is self-sufficient for auto-fill, so it needs to call
+ // onProvideAutoFillStructure() to fill itself, but it does not need to call
+ // dispatchProvideAutoFillStructure() to fill its children.
+ onProvideAutoFillStructure(structure, flags);
+ }
+
+ @Override
+ public void autoFill(AutoFillValue value) {
+ if (!isEnabled()) return;
+
+ mDelegate.updateDate(value.getDateValue());
+ }
+
+ @Override
+ public AutoFillType getAutoFillType() {
+ return isEnabled() ? AutoFillType.forDate() : null;
+ }
+
+ @Override
+ public AutoFillValue getAutoFillValue() {
+ return isEnabled() ? AutoFillValue.forDate(mDelegate.getDate()) : null;
+ }
}
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 907250aa5598..ca1bf582e603 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -390,10 +390,16 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
private void onDateChanged(boolean fromUser, boolean callbackToClient) {
final int year = mCurrentDate.get(Calendar.YEAR);
- if (callbackToClient && mOnDateChangedListener != null) {
+ if (callbackToClient
+ && (mOnDateChangedListener != null || mAutoFillChangeListener != null)) {
final int monthOfYear = mCurrentDate.get(Calendar.MONTH);
final int dayOfMonth = mCurrentDate.get(Calendar.DAY_OF_MONTH);
- mOnDateChangedListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth);
+ if (mOnDateChangedListener != null) {
+ mOnDateChangedListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth);
+ }
+ if (mAutoFillChangeListener != null) {
+ mAutoFillChangeListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth);
+ }
}
mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 702b2a5f822a..fc2d1faca019 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -576,6 +576,10 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
mOnDateChangedListener.onDateChanged(mDelegator, getYear(), getMonth(),
getDayOfMonth());
}
+ if (mAutoFillChangeListener != null) {
+ mAutoFillChangeListener.onDateChanged(mDelegator, getYear(), getMonth(),
+ getDayOfMonth());
+ }
}
/**
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index bba3a11042e0..be5fc5381ac7 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -436,7 +436,7 @@ public class RadioGroup extends LinearLayout {
@Override
public AutoFillType getAutoFillType() {
- return AutoFillType.forList();
+ return isEnabled() ? AutoFillType.forList() : null;
}
@Override
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 493774038e4e..3d10917a6448 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10002,6 +10002,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style);
}
structure.setHint(getHint());
+ structure.setInputType(getInputType());
}
// TODO(b/33197203): add unit/CTS tests for auto-fill methods
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 9f38b04d4e09..1df202e96a3b 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -23,12 +23,17 @@ import android.annotation.TestApi;
import android.annotation.Widget;
import android.content.Context;
import android.content.res.TypedArray;
+import android.icu.util.Calendar;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.view.View;
+import android.view.ViewStructure;
import android.view.accessibility.AccessibilityEvent;
+import android.view.autofill.AutoFillManager;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
import com.android.internal.R;
@@ -132,6 +137,12 @@ public class TimePicker extends FrameLayout {
this, context, attrs, defStyleAttr, defStyleRes);
break;
}
+ mDelegate.setAutoFillChangeListener((v, h, m) -> {
+ final AutoFillManager afm = context.getSystemService(AutoFillManager.class);
+ if (afm != null) {
+ afm.valueChanged(this);
+ }
+ });
}
/**
@@ -348,12 +359,16 @@ public class TimePicker extends FrameLayout {
void setMinute(@IntRange(from = 0, to = 59) int minute);
int getMinute();
+ void setDate(long date);
+ long getDate();
+
void setIs24Hour(boolean is24Hour);
boolean is24Hour();
boolean validateInput();
void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener);
+ void setAutoFillChangeListener(OnTimeChangedListener autoFillChangeListener);
void setEnabled(boolean enabled);
boolean isEnabled();
@@ -398,6 +413,7 @@ public class TimePicker extends FrameLayout {
protected final Locale mLocale;
protected OnTimeChangedListener mOnTimeChangedListener;
+ protected OnTimeChangedListener mAutoFillChangeListener;
public AbstractTimePickerDelegate(@NonNull TimePicker delegator, @NonNull Context context) {
mDelegator = delegator;
@@ -410,6 +426,27 @@ public class TimePicker extends FrameLayout {
mOnTimeChangedListener = callback;
}
+ @Override
+ public void setAutoFillChangeListener(OnTimeChangedListener callback) {
+ mAutoFillChangeListener = callback;
+ }
+
+ @Override
+ public void setDate(long date) {
+ Calendar cal = Calendar.getInstance(mLocale);
+ cal.setTimeInMillis(date);
+ setHour(cal.get(Calendar.HOUR_OF_DAY));
+ setMinute(cal.get(Calendar.MINUTE));
+ }
+
+ @Override
+ public long getDate() {
+ Calendar cal = Calendar.getInstance(mLocale);
+ cal.set(Calendar.HOUR_OF_DAY, getHour());
+ cal.set(Calendar.MINUTE, getMinute());
+ return cal.getTimeInMillis();
+ }
+
protected static class SavedState extends View.BaseSavedState {
private final int mHour;
private final int mMinute;
@@ -474,4 +511,31 @@ public class TimePicker extends FrameLayout {
};
}
}
+
+ // TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
+
+ @Override
+ public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
+ // This view is self-sufficient for auto-fill, so it needs to call
+ // onProvideAutoFillStructure() to fill itself, but it does not need to call
+ // dispatchProvideAutoFillStructure() to fill its children.
+ onProvideAutoFillStructure(structure, flags);
+ }
+
+ @Override
+ public void autoFill(AutoFillValue value) {
+ if (!isEnabled()) return;
+
+ mDelegate.setDate(value.getDateValue());
+ }
+
+ @Override
+ public AutoFillType getAutoFillType() {
+ return isEnabled() ? AutoFillType.forDate() : null;
+ }
+
+ @Override
+ public AutoFillValue getAutoFillValue() {
+ return isEnabled() ? AutoFillValue.forDate(mDelegate.getDate()) : null;
+ }
}
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 3a0906393b97..3605585fe605 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -671,6 +671,9 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
if (mOnTimeChangedListener != null) {
mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
}
+ if (mAutoFillChangeListener != null) {
+ mAutoFillChangeListener.onTimeChanged(mDelegator, getHour(), getMinute());
+ }
}
private void tryVibrate() {
@@ -813,8 +816,12 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
private final OnValueSelectedListener mOnValueSelectedListener = new OnValueSelectedListener() {
@Override
public void onValueSelected(int pickerType, int newValue, boolean autoAdvance) {
+ boolean valueChanged = false;
switch (pickerType) {
case RadialTimePickerView.HOURS:
+ if (getHour() != newValue) {
+ valueChanged = true;
+ }
final boolean isTransition = mAllowAutoAdvance && autoAdvance;
setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition);
if (isTransition) {
@@ -825,11 +832,14 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
}
break;
case RadialTimePickerView.MINUTES:
+ if (getMinute() != newValue) {
+ valueChanged = true;
+ }
setMinuteInternal(newValue, FROM_RADIAL_PICKER);
break;
}
- if (mOnTimeChangedListener != null) {
+ if (mOnTimeChangedListener != null && valueChanged) {
mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
}
}
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 20a55129a19d..813c30e344c0 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -495,6 +495,9 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(),
getMinute());
}
+ if (mAutoFillChangeListener != null) {
+ mAutoFillChangeListener.onTimeChanged(mDelegator, getHour(), getMinute());
+ }
}
private void updateHourControl() {
diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java
index 03cd729db62b..68afe02be825 100644
--- a/core/java/com/android/internal/app/NightDisplayController.java
+++ b/core/java/com/android/internal/app/NightDisplayController.java
@@ -18,13 +18,13 @@ package com.android.internal.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
-import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.util.Slog;
@@ -81,7 +81,7 @@ public final class NightDisplayController {
private Callback mCallback;
public NightDisplayController(@NonNull Context context) {
- this(context, UserHandle.myUserId());
+ this(context, ActivityManager.getCurrentUser());
}
public NightDisplayController(@NonNull Context context, int userId) {
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
new file mode 100644
index 000000000000..ec3aac21cb19
--- /dev/null
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 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.notification;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+// Manages the NotificationChannels used by the frameworks itself.
+public class SystemNotificationChannels {
+ public static String VIRTUAL_KEYBOARD = "VIRTUAL_KEYBOARD";
+ public static String PHYSICAL_KEYBOARD = "PHYSICAL_KEYBOARD";
+ public static String SECURITY = "SECURITY";
+ public static String CAR_MODE = "CAR_MODE";
+ public static String ACCOUNT = "ACCOUNT";
+ public static String DEVELOPER = "DEVELOPER";
+ public static String UPDATES = "UPDATES";
+ public static String NETWORK_STATUS = "NETWORK_STATUS";
+ public static String NETWORK_ALERTS = "NETWORK_ALERTS";
+ public static String VPN = "VPN";
+ public static String DEVICE_ADMIN = "DEVICE_ADMIN";
+ public static String ALERTS = "ALERTS";
+ public static String RETAIL_MODE = "RETAIL_MODE";
+ public static String USB = "USB";
+
+ public static void createAll(Context context) {
+ final NotificationManager nm = context.getSystemService(NotificationManager.class);
+ List<NotificationChannel> channelsList = new ArrayList<NotificationChannel>();
+ channelsList.add(new NotificationChannel(
+ VIRTUAL_KEYBOARD,
+ R.string.notification_channel_virtual_keyboard,
+ NotificationManager.IMPORTANCE_LOW));
+
+ final NotificationChannel physicalKeyboardChannel = new NotificationChannel(
+ PHYSICAL_KEYBOARD,
+ R.string.notification_channel_physical_keyboard,
+ NotificationManager.IMPORTANCE_DEFAULT);
+ physicalKeyboardChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channelsList.add(physicalKeyboardChannel);
+
+ channelsList.add(new NotificationChannel(
+ SECURITY,
+ R.string.notification_channel_security,
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ CAR_MODE,
+ R.string.notification_channel_car_mode,
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ DEVELOPER,
+ R.string.notification_channel_developer,
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ UPDATES,
+ R.string.notification_channel_updates,
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ NETWORK_STATUS,
+ R.string.notification_channel_network_status,
+ NotificationManager.IMPORTANCE_LOW));
+
+ final NotificationChannel networkAlertsChannel = new NotificationChannel(
+ NETWORK_ALERTS,
+ R.string.notification_channel_network_alerts,
+ NotificationManager.IMPORTANCE_HIGH);
+ networkAlertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channelsList.add(networkAlertsChannel);
+
+ channelsList.add(new NotificationChannel(
+ VPN,
+ R.string.notification_channel_vpn,
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ DEVICE_ADMIN,
+ R.string.notification_channel_device_admin,
+ NotificationManager.IMPORTANCE_LOW));
+
+ final NotificationChannel alertsChannel = new NotificationChannel(
+ ALERTS,
+ R.string.notification_channel_alerts,
+ NotificationManager.IMPORTANCE_DEFAULT);
+ alertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channelsList.add(alertsChannel);
+
+ channelsList.add(new NotificationChannel(
+ RETAIL_MODE,
+ R.string.notification_channel_retail_mode,
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ USB,
+ R.string.notification_channel_usb,
+ NotificationManager.IMPORTANCE_MIN));
+
+ nm.createNotificationChannels(channelsList);
+ createAccountChannelForPackage(context.getPackageName(), context);
+ }
+
+ public static void createAccountChannelForPackage(String pkg, Context context) {
+ final NotificationManager nm = context.getSystemService(NotificationManager.class);
+ nm.createNotificationChannelsForPackage(pkg, Arrays.asList(new NotificationChannel(
+ ACCOUNT,
+ R.string.notification_channel_account,
+ NotificationManager.IMPORTANCE_LOW)));
+ }
+
+ private SystemNotificationChannels() {}
+}
diff --git a/core/java/com/android/internal/util/ParcelableString.java b/core/java/com/android/internal/util/ParcelableString.java
deleted file mode 100644
index 6bd856f5521d..000000000000
--- a/core/java/com/android/internal/util/ParcelableString.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2014, 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.util;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Helper class to adapt a simple String to cases where a Parcelable is expected.
- * @hide
- */
-public class ParcelableString implements Parcelable {
- public String string;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(string);
- }
-
- public static final Parcelable.Creator<ParcelableString> CREATOR =
- new Parcelable.Creator<ParcelableString>() {
- @Override
- public ParcelableString createFromParcel(Parcel in) {
- ParcelableString ret = new ParcelableString();
- ret.string = in.readString();
- return ret;
- }
- @Override
- public ParcelableString[] newArray(int size) {
- return new ParcelableString[size];
- }
- };
-} \ No newline at end of file
diff --git a/core/java/com/android/internal/view/SurfaceCallbackHelper.java b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
index 5b6a82cf1c43..507b673ec279 100644
--- a/core/java/com/android/internal/view/SurfaceCallbackHelper.java
+++ b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
@@ -17,14 +17,11 @@
package com.android.internal.view;
import android.os.RemoteException;
-import android.view.IWindow;
-import android.view.IWindowSession;
import android.view.Surface;
import android.view.SurfaceHolder;
public class SurfaceCallbackHelper {
- IWindowSession mSession;
- IWindow.Stub mWindow;
+ Runnable mRunnable;
int mFinishDrawingCollected = 0;
int mFinishDrawingExpected = 0;
@@ -37,26 +34,18 @@ public class SurfaceCallbackHelper {
if (mFinishDrawingCollected < mFinishDrawingExpected) {
return;
}
- try {
- mSession.finishDrawing(mWindow);
- } catch (RemoteException e) {
- }
+ mRunnable.run();
}
}
};
- public SurfaceCallbackHelper(IWindowSession session,
- IWindow.Stub window) {
- mSession = session;
- mWindow = window;
+ public SurfaceCallbackHelper(Runnable callbacksCollected) {
+ mRunnable = callbacksCollected;
}
public void dispatchSurfaceRedrawNeededAsync(SurfaceHolder holder, SurfaceHolder.Callback callbacks[]) {
if (callbacks == null || callbacks.length == 0) {
- try {
- mSession.finishDrawing(mWindow);
- } catch (RemoteException e) {
- }
+ mRunnable.run();
return;
}
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 69e974c672d0..1de0af6f31df 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -388,14 +388,22 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey
final boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
mLastPosition = nextMenuPosition;
- final int[] tempLocation = new int[2];
-
- // This popup menu will be positioned relative to the top-left edge
- // of the view representing its parent menu.
- parentView.getLocationInWindow(tempLocation);
- final int parentOffsetLeft = parentInfo.window.getHorizontalOffset() + tempLocation[0];
- final int parentOffsetTop = parentInfo.window.getVerticalOffset() + tempLocation[1];
-
+ // A popup anchored to mAnchorView with (0,0) offset would be shown at this position.
+ final int[] offsetOrigin = new int[2];
+ mAnchorView.getLocationOnScreen(offsetOrigin);
+ offsetOrigin[1] += mAnchorView.getHeight();
+
+ final int[] parentViewScreenLocation = new int[2];
+ parentView.getLocationOnScreen(parentViewScreenLocation);
+
+ // Translate the parent view location into the offset coordinate space.
+ // If used as horizontal/vertical offsets, these values would position the submenu
+ // at the exact same position as the parent item.
+ final int parentOffsetLeft = parentViewScreenLocation[0] - offsetOrigin[0];
+ final int parentOffsetTop = parentViewScreenLocation[1] - offsetOrigin[1];
+
+ // Adjust the horizontal offset to display the submenu to the right or to the left
+ // of the parent item.
// By now, mDropDownGravity is the resolved absolute gravity, so
// this should work in both LTR and RTL.
final int x;
@@ -412,11 +420,10 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey
x = parentOffsetLeft - menuWidth;
}
}
-
popupWindow.setHorizontalOffset(x);
- final int y = parentOffsetTop;
- popupWindow.setVerticalOffset(y);
+ // Use the same vertical offset as the parent item.
+ popupWindow.setVerticalOffset(parentOffsetTop);
} else {
if (mHasXOffset) {
popupWindow.setHorizontalOffset(mXOffset);
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 3ca455dc24cf..a196540078f5 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -232,6 +232,73 @@ Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle) {
return localBitmap->bitmap();
}
+void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) {
+ SkASSERT(info);
+ SkASSERT(env);
+ SkASSERT(bitmap);
+ SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
+ jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
+ LocalScopedBitmap localBitmap(bitmapHandle);
+
+ const SkImageInfo& imageInfo = localBitmap->info();
+ info->width = imageInfo.width();
+ info->height = imageInfo.height();
+ info->stride = localBitmap->rowBytes();
+ info->flags = 0;
+ switch (imageInfo.colorType()) {
+ case kN32_SkColorType:
+ info->format = ANDROID_BITMAP_FORMAT_RGBA_8888;
+ break;
+ case kRGB_565_SkColorType:
+ info->format = ANDROID_BITMAP_FORMAT_RGB_565;
+ break;
+ case kARGB_4444_SkColorType:
+ info->format = ANDROID_BITMAP_FORMAT_RGBA_4444;
+ break;
+ case kAlpha_8_SkColorType:
+ info->format = ANDROID_BITMAP_FORMAT_A_8;
+ break;
+ default:
+ info->format = ANDROID_BITMAP_FORMAT_NONE;
+ break;
+ }
+}
+
+void* lockPixels(JNIEnv* env, jobject bitmap) {
+ SkASSERT(env);
+ SkASSERT(bitmap);
+ SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
+ jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
+
+ LocalScopedBitmap localBitmap(bitmapHandle);
+ if (!localBitmap->valid()) return nullptr;
+
+ SkPixelRef& pixelRef = localBitmap->bitmap();
+ pixelRef.lockPixels();
+ if (!pixelRef.pixels()) {
+ pixelRef.unlockPixels();
+ return nullptr;
+ }
+ pixelRef.ref();
+ return pixelRef.pixels();
+}
+
+bool unlockPixels(JNIEnv* env, jobject bitmap) {
+ SkASSERT(env);
+ SkASSERT(bitmap);
+ SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
+ jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
+
+ LocalScopedBitmap localBitmap(bitmapHandle);
+ if (!localBitmap->valid()) return false;
+
+ SkPixelRef& pixelRef = localBitmap->bitmap();
+ pixelRef.notifyPixelsChanged();
+ pixelRef.unlockPixels();
+ pixelRef.unref();
+ return true;
+}
+
} // namespace bitmap
} // namespace android
@@ -643,7 +710,7 @@ static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
if (!bitmap.get()) {
return NULL;
}
- return createBitmap(env, bitmap.release(), kBitmapCreateFlag_None);
+ return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable));
}
SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
@@ -1306,7 +1373,7 @@ static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bit
doThrowRE(env, "Could not copy a hardware bitmap.");
return NULL;
}
- return createBitmap(env, allocator.getStorageObjAndReset(), kBitmapCreateFlag_None);
+ return createBitmap(env, allocator.getStorageObjAndReset(), getPremulBitmapCreateFlags(false));
}
static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
@@ -1316,7 +1383,7 @@ static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphic
ALOGW("failed to create hardware bitmap from graphic buffer");
return NULL;
}
- return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None);
+ return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
}
static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h
index 387a1285ba12..a4bfc94b79e3 100644
--- a/core/jni/android/graphics/Bitmap.h
+++ b/core/jni/android/graphics/Bitmap.h
@@ -17,6 +17,7 @@
#define BITMAP_H_
#include <jni.h>
+#include <android/bitmap.h>
#include <SkBitmap.h>
#include <SkColorTable.h>
#include <SkImageInfo.h>
@@ -44,6 +45,13 @@ void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap);
Bitmap& toBitmap(JNIEnv* env, jobject bitmap);
Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle);
+// NDK access
+void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info);
+// Returns a pointer to the pixels or nullptr if the bitmap is not valid
+void* lockPixels(JNIEnv* env, jobject bitmap);
+// Returns true if unlocked, false if the bitmap is no longer valid (destroyed)
+bool unlockPixels(JNIEnv* env, jobject bitmap);
+
/** Reinitialize a bitmap. bitmap must already have its SkAlphaType set in
sync with isPremultiplied
*/
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 989a557986c4..2439b8210a89 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -346,7 +346,7 @@ static jobject JHwBinder_native_getService(
<< serviceName;
::android::vintf::Transport transport =
- ::android::hardware::getTransport(ifaceName);
+ ::android::hardware::getTransport(ifaceName, serviceName);
if ( transport != ::android::vintf::Transport::EMPTY
&& transport != ::android::vintf::Transport::HWBINDER) {
LOG(ERROR) << "service " << ifaceName << " declares transport method "
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 314595f73091..c2800e78698d 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1578,10 +1578,8 @@ static const JNINativeMethod gAssetManagerMethods[] = {
(void*) android_content_AssetManager_readAsset },
{ "seekAsset", "(JJI)J",
(void*) android_content_AssetManager_seekAsset },
- // @FastNative
{ "getAssetLength", "(J)J",
(void*) android_content_AssetManager_getAssetLength },
- // @FastNative
{ "getAssetRemainingLength", "(J)J",
(void*) android_content_AssetManager_getAssetRemainingLength },
{ "addAssetPathNative", "(Ljava/lang/String;Z)I",
@@ -1598,34 +1596,24 @@ static const JNINativeMethod gAssetManagerMethods[] = {
(void*) android_content_AssetManager_getNonSystemLocales },
{ "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
(void*) android_content_AssetManager_getSizeConfigurations },
- // @FastNative
{ "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIIII)V",
(void*) android_content_AssetManager_setConfiguration },
- // @FastNative
{ "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
(void*) android_content_AssetManager_getResourceIdentifier },
- // @FastNative
{ "getResourceName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getResourceName },
- // @FastNative
{ "getResourcePackageName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getResourcePackageName },
- // @FastNative
{ "getResourceTypeName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getResourceTypeName },
- // @FastNative
{ "getResourceEntryName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getResourceEntryName },
- // @FastNative
{ "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
(void*) android_content_AssetManager_loadResourceValue },
- // @FastNative
{ "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
(void*) android_content_AssetManager_loadResourceBagValue },
- // @FastNative
{ "getStringBlockCount","()I",
(void*) android_content_AssetManager_getStringBlockCount },
- // @FastNative
{ "getNativeStringBlock","(I)J",
(void*) android_content_AssetManager_getNativeStringBlock },
{ "getCookieName","(I)Ljava/lang/String;",
@@ -1644,27 +1632,20 @@ static const JNINativeMethod gAssetManagerMethods[] = {
(void*) android_content_AssetManager_copyTheme },
{ "clearTheme", "(J)V",
(void*) android_content_AssetManager_clearTheme },
- // @FastNative
{ "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
(void*) android_content_AssetManager_loadThemeAttributeValue },
- // @FastNative
{ "getThemeChangingConfigurations", "(J)I",
(void*) android_content_AssetManager_getThemeChangingConfigurations },
{ "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
(void*) android_content_AssetManager_dumpTheme },
- // @FastNative
{ "applyStyle","(JIIJ[IIJJ)V",
(void*) android_content_AssetManager_applyStyle },
- // @FastNative
{ "resolveAttrs","(JII[I[I[I[I)Z",
(void*) android_content_AssetManager_resolveAttrs },
- // @FastNative
{ "retrieveAttributes","(J[I[I[I)Z",
(void*) android_content_AssetManager_retrieveAttributes },
- // @FastNative
{ "getArraySize","(I)I",
(void*) android_content_AssetManager_getArraySize },
- // @FastNative
{ "retrieveArray","(I[I)I",
(void*) android_content_AssetManager_retrieveArray },
@@ -1675,13 +1656,10 @@ static const JNINativeMethod gAssetManagerMethods[] = {
// Arrays.
{ "getArrayStringResource","(I)[Ljava/lang/String;",
(void*) android_content_AssetManager_getArrayStringResource },
- // @FastNative
{ "getArrayStringInfo","(I)[I",
(void*) android_content_AssetManager_getArrayStringInfo },
- // @FastNative
{ "getArrayIntResource","(I)[I",
(void*) android_content_AssetManager_getArrayIntResource },
- // @FastNative
{ "getStyleAttributes","(I)[I",
(void*) android_content_AssetManager_getStyleAttributes },
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index c7998a169225..1c6ead0f1086 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -111,11 +111,12 @@ void android_view_InputChannel_setDisposeCallback(JNIEnv* env, jobject inputChan
}
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
- NativeInputChannel* nativeInputChannel) {
+ std::unique_ptr<NativeInputChannel> nativeInputChannel) {
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);
if (inputChannelObj) {
- android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
+ android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
+ nativeInputChannel.release());
}
return inputChannelObj;
}
@@ -143,13 +144,13 @@ static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv*
}
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
- new NativeInputChannel(serverChannel));
+ std::make_unique<NativeInputChannel>(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
- new NativeInputChannel(clientChannel));
+ std::make_unique<NativeInputChannel>(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index f221392f16bd..6e8c93132562 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -452,10 +452,6 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
const RenderProperties& props = node.properties();
uirenderer::Rect bounds(props.getWidth(), props.getHeight());
transform.mapRect(bounds);
- bounds.left -= info.windowInsetLeft;
- bounds.right -= info.windowInsetLeft;
- bounds.top -= info.windowInsetTop;
- bounds.bottom -= info.windowInsetTop;
if (CC_LIKELY(transform.isPureTranslate())) {
// snap/round the computed bounds, so they match the rounding behavior
@@ -627,9 +623,9 @@ static const JNINativeMethod gMethods[] = {
int register_android_view_RenderNode(JNIEnv* env) {
jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
- "updateWindowPosition_renderWorker", "(JIIII)V");
+ "updateSurfacePosition_renderWorker", "(JIIII)V");
gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
- "windowPositionLost_uiRtSync", "(J)V");
+ "surfacePositionLost_uiRtSync", "(J)V");
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a81901df9a1b..be86f5c6b8ab 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -693,7 +693,6 @@ static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject
return JNI_TRUE;
}
-
static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeObject,
jobject handleObject, jlong frameNumber) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
@@ -702,6 +701,27 @@ static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeO
ctrl->deferTransactionUntil(handle, frameNumber);
}
+static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong nativeObject,
+ jobject surfaceObject, jlong frameNumber) {
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ sp<Surface> barrier = reinterpret_cast<Surface *>(surfaceObject);
+
+ ctrl->deferTransactionUntil(barrier, frameNumber);
+}
+
+static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong nativeObject,
+ jobject newParentObject) {
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ sp<IBinder> handle = ibinderForJavaObject(env, newParentObject);
+
+ ctrl->reparentChildren(handle);
+}
+
+static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong nativeObject) {
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ ctrl->detachChildren();
+}
+
static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong nativeObject,
jint scalingMode) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
@@ -824,6 +844,12 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetDisplayPowerMode },
{"nativeDeferTransactionUntil", "(JLandroid/os/IBinder;J)V",
(void*)nativeDeferTransactionUntil },
+ {"nativeDeferTransactionUntilSurface", "(JJJ)V",
+ (void*)nativeDeferTransactionUntilSurface },
+ {"nativeReparentChildren", "(JLandroid/os/IBinder;)V",
+ (void*)nativeReparentChildren } ,
+ {"nativeSeverChildren", "(J)V",
+ (void*)nativeSeverChildren } ,
{"nativeSetOverrideScalingMode", "(JI)V",
(void*)nativeSetOverrideScalingMode },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index dad6958560c0..508d89795569 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -24,6 +24,7 @@
#include <utils/RefBase.h>
#include <gui/SurfaceComposerClient.h>
+#include <gui/Surface.h>
namespace android {
@@ -45,6 +46,13 @@ static jlong nativeCreate(JNIEnv* env, jclass clazz) {
return reinterpret_cast<jlong>(client);
}
+static jlong nativeCreateScoped(JNIEnv* env, jclass clazz, jlong surfaceObject) {
+ Surface *parent = reinterpret_cast<Surface*>(surfaceObject);
+ SurfaceComposerClient* client = new SurfaceComposerClient(parent->getIGraphicBufferProducer());
+ client->incStrong((void*)nativeCreate);
+ return reinterpret_cast<jlong>(client);
+}
+
static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
client->decStrong((void*)nativeCreate);
@@ -55,11 +63,12 @@ static void nativeKill(JNIEnv* env, jclass clazz, jlong ptr) {
client->dispose();
}
-
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeCreate", "()J",
(void*)nativeCreate },
+ { "nativeCreateScoped", "(J)J",
+ (void*)nativeCreateScoped },
{ "nativeDestroy", "(J)V",
(void*)nativeDestroy },
{ "nativeKill", "(J)V",
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 37eae48a7a11..99edf6ef944e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -178,13 +178,9 @@ public:
}
}
// TODO: This is hacky
- info.windowInsetLeft = -stagingProperties().getLeft();
- info.windowInsetTop = -stagingProperties().getTop();
info.updateWindowPositions = true;
RenderNode::prepareTree(info);
info.updateWindowPositions = false;
- info.windowInsetLeft = 0;
- info.windowInsetTop = 0;
info.errorHandler = nullptr;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 054fad2f0bca..5bfcda37294d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -522,6 +522,8 @@
<protected-broadcast android:name="android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED" />
<protected-broadcast android:name="com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION" />
+ <protected-broadcast android:name="android.content.pm.action.SESSION_COMMITTED" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -895,6 +897,17 @@
android:description="@string/permdesc_processOutgoingCalls"
android:protectionLevel="dangerous" />
+
+ <!-- Allows the app to answer an incoming phone call.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ANSWER_PHONE_CALLS"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_answerPhoneCalls"
+ android:description="@string/permdesc_answerPhoneCalls"
+ android:protectionLevel="dangerous" />
+
+
<!-- ====================================================================== -->
<!-- Permissions for accessing the device microphone -->
<!-- ====================================================================== -->
@@ -1272,7 +1285,7 @@
<permission android:name="android.permission.SCORE_NETWORKS"
android:protectionLevel="signature|privileged" />
- <!-- @SystemApi Allows applications to request network
+ <!-- Allows applications to request network
recommendations and scores from the NetworkScoreService.
<p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.REQUEST_NETWORK_SCORES"
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
index b91021172f90..fd5154af3b0c 100644
--- a/core/res/res/layout/notification_template_material_messaging.xml
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -24,7 +24,7 @@
<LinearLayout
android:id="@+id/notification_action_list_margin_target"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="@dimen/notification_content_margin_top"
android:clipToPadding="false"
@@ -38,6 +38,7 @@
android:paddingStart="@dimen/notification_content_margin_start"
android:paddingEnd="@dimen/notification_content_margin_end"
android:minHeight="@dimen/notification_min_content_height"
+ android:layout_marginBottom="@dimen/notification_content_margin_bottom"
android:clipToPadding="false"
android:orientation="vertical"
>
@@ -49,7 +50,6 @@
android:id="@+id/notification_messaging"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingBottom="@dimen/notification_content_margin_bottom"
android:spacing="@dimen/notification_messaging_spacing" >
<com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text0"
style="@style/Widget.Material.Notification.MessagingText"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e8169f853121..c137ae2afdd5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -804,16 +804,20 @@
<!-- Action bar styles -->
<!-- =================== -->
<eat-comment />
- <!-- Default style for tabs within an action bar -->
+ <!-- Default style for tabs within an action bar. -->
<attr name="actionBarTabStyle" format="reference" />
+ <!-- Reference to a style for the Action Bar Tab Bar. -->
<attr name="actionBarTabBarStyle" format="reference" />
+ <!-- Reference to a style for the Action Bar Tab text. -->
<attr name="actionBarTabTextStyle" format="reference" />
+ <!-- Reference to a style for Action Bar overflow buttons. -->
<attr name="actionOverflowButtonStyle" format="reference" />
+ <!-- Reference to a style for the Action Bar menu. -->
<attr name="actionOverflowMenuStyle" format="reference" />
<!-- Reference to a theme that should be used to inflate popups
shown by widgets in the action bar. -->
<attr name="actionBarPopupTheme" format="reference" />
- <!-- Reference to a style for the Action Bar -->
+ <!-- Reference to a style for the Action Bar. -->
<attr name="actionBarStyle" format="reference" />
<!-- Reference to a style for the split Action Bar. This style
controls the split component that holds the menu/action
@@ -851,28 +855,30 @@
<!-- Action mode styles -->
<!-- =================== -->
<eat-comment />
+ <!-- Reference to a style for the Action Mode. -->
<attr name="actionModeStyle" format="reference" />
+ <!-- Reference to a style for the Action Mode close button. -->
<attr name="actionModeCloseButtonStyle" format="reference" />
- <!-- Background drawable to use for action mode UI -->
+ <!-- Background drawable to use for action mode UI. -->
<attr name="actionModeBackground" format="reference" />
- <!-- Background drawable to use for action mode UI in the lower split bar -->
+ <!-- Background drawable to use for action mode UI in the lower split bar. -->
<attr name="actionModeSplitBackground" format="reference" />
- <!-- Drawable to use for the close action mode button -->
+ <!-- Drawable to use for the close action mode button. -->
<attr name="actionModeCloseDrawable" format="reference" />
- <!-- Drawable to use for the Cut action button in Contextual Action Bar -->
+ <!-- Drawable to use for the Cut action button in Contextual Action Bar. -->
<attr name="actionModeCutDrawable" format="reference" />
- <!-- Drawable to use for the Copy action button in Contextual Action Bar -->
+ <!-- Drawable to use for the Copy action button in Contextual Action Bar. -->
<attr name="actionModeCopyDrawable" format="reference" />
- <!-- Drawable to use for the Paste action button in Contextual Action Bar -->
+ <!-- Drawable to use for the Paste action button in Contextual Action Bar. -->
<attr name="actionModePasteDrawable" format="reference" />
- <!-- Drawable to use for the Select all action button in Contextual Action Bar -->
+ <!-- Drawable to use for the Select all action button in Contextual Action Bar. -->
<attr name="actionModeSelectAllDrawable" format="reference" />
- <!-- Drawable to use for the Share action button in WebView selection action modes -->
+ <!-- Drawable to use for the Share action button in WebView selection action modes. -->
<attr name="actionModeShareDrawable" format="reference" />
- <!-- Drawable to use for the Find action button in WebView selection action modes -->
+ <!-- Drawable to use for the Find action button in WebView selection action modes. -->
<attr name="actionModeFindDrawable" format="reference" />
- <!-- Drawable to use for the Web Search action button in WebView selection action modes -->
+ <!-- Drawable to use for the Web Search action button in WebView selection action modes. -->
<attr name="actionModeWebSearchDrawable" format="reference" />
<!-- PopupWindow style to use for action modes when showing as a window overlay. -->
@@ -969,7 +975,7 @@
<!-- Theme to use for alert dialogs spawned from this theme. -->
<attr name="alertDialogTheme" format="reference" />
- <!-- Icon drawable to use for alerts -->
+ <!-- Icon drawable to use for alerts. -->
<attr name="alertDialogIcon" format="reference" />
<!-- Theme to use for presentations spawned from this theme. -->
@@ -981,19 +987,19 @@
<!-- Drawable to use for generic horizontal dividers. -->
<attr name="dividerHorizontal" format="reference" />
- <!-- Style for button bars -->
+ <!-- Style for button bars. -->
<attr name="buttonBarStyle" format="reference" />
- <!-- Style for buttons within button bars -->
+ <!-- Style for buttons within button bars. -->
<attr name="buttonBarButtonStyle" format="reference" />
- <!-- Style for the "positive" buttons within button bars -->
+ <!-- Style for the "positive" buttons within button bars. -->
<attr name="buttonBarPositiveButtonStyle" format="reference" />
- <!-- Style for the "negative" buttons within button bars -->
+ <!-- Style for the "negative" buttons within button bars. -->
<attr name="buttonBarNegativeButtonStyle" format="reference" />
- <!-- Style for the "neutral" buttons within button bars -->
+ <!-- Style for the "neutral" buttons within button bars. -->
<attr name="buttonBarNeutralButtonStyle" format="reference" />
<!-- Style for the search query widget. -->
@@ -1012,19 +1018,19 @@
<!-- Style for buttons without an explicit border, often used in groups. -->
<attr name="borderlessButtonStyle" format="reference" />
- <!-- Background to use for toasts -->
+ <!-- Background to use for toasts. -->
<attr name="toastFrameBackground" format="reference" />
- <!-- Background to use for tooltip popups -->
+ <!-- Background to use for tooltip popups. -->
<attr name="tooltipFrameBackground" format="reference" />
- <!-- Foreground color to use for tooltip popups -->
+ <!-- Foreground color to use for tooltip popups. -->
<attr name="tooltipForegroundColor" format="reference|color" />
- <!-- Background color to use for tooltip popups -->
+ <!-- Background color to use for tooltip popups. -->
<attr name="tooltipBackgroundColor" format="reference|color" />
- <!-- Theme to use for Search Dialogs -->
+ <!-- Theme to use for Search Dialogs. -->
<attr name="searchDialogTheme" format="reference" />
<!-- Specifies a drawable to use for the 'home as up' indicator. -->
@@ -2287,7 +2293,7 @@
<enum name="auto" value="0x00000010" />
</attr>
- <!-- Controls the auto-fill behavior for this view -->
+ <!-- Controls the auto-fill behavior for this view. -->
<attr name="autoFillMode">
<!-- Inherit the behavior from the parent. If there is no parent it is auto. -->
<enum name="inherit" value="0" />
@@ -2338,13 +2344,13 @@
to appear at the edge of the view, ignoring the padding, then you can
use outsideOverlay or outsideInset.-->
<attr name="scrollbarStyle">
- <!-- Inside the padding and overlaid -->
+ <!-- Inside the padding and overlaid. -->
<enum name="insideOverlay" value="0x0" />
- <!-- Inside the padding and inset -->
+ <!-- Inside the padding and inset. -->
<enum name="insideInset" value="0x01000000" />
- <!-- Edge of the view and overlaid -->
+ <!-- Edge of the view and overlaid. -->
<enum name="outsideOverlay" value="0x02000000" />
- <!-- Edge of the view and inset -->
+ <!-- Edge of the view and inset. -->
<enum name="outsideInset" value="0x03000000" />
</attr>
@@ -2548,7 +2554,7 @@
(completely opaque). -->
<attr name="alpha" format="float" />
- <!-- base z depth of the view -->
+ <!-- base z depth of the view. -->
<attr name="elevation" format="dimension" />
<!-- translation in x of the view. This value is added post-layout to the left
@@ -2617,19 +2623,19 @@
to inherit, "locale" is used. "locale" falls back to "en-US". "ltr" is the direction
used in "en-US". The default for this attribute is "inherit". -->
<attr name="layoutDirection">
- <!-- Left-to-Right -->
+ <!-- Left-to-Right. -->
<enum name="ltr" value="0" />
- <!-- Right-to-Left -->
+ <!-- Right-to-Left. -->
<enum name="rtl" value="1" />
- <!-- Inherit from parent -->
+ <!-- Inherit from parent. -->
<enum name="inherit" value="2" />
- <!-- Locale -->
+ <!-- Locale. -->
<enum name="locale" value="3" />
</attr>
<!-- Defines the direction of the text. -->
<attr name="textDirection" format="integer">
- <!-- Default -->
+ <!-- Default. -->
<enum name="inherit" value="0" />
<!-- Default for the root view. The first strong directional character determines the
paragraph direction. If there is no strong directional character, the paragraph
@@ -2655,23 +2661,23 @@
<!-- Defines the alignment of the text. -->
<attr name="textAlignment" format="integer">
- <!-- Default -->
+ <!-- Default. -->
<enum name="inherit" value="0" />
<!-- Default for the root view. The gravity determines the alignment, ALIGN_NORMAL,
ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s
- text direction -->
+ text direction. -->
<enum name="gravity" value="1" />
- <!-- Align to the start of the paragraph, e.g. ALIGN_NORMAL. -->
+ <!-- Align to the start of the paragraph, for example: ALIGN_NORMAL. -->
<enum name="textStart" value="2" />
- <!-- Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. -->
+ <!-- Align to the end of the paragraph, for example: ALIGN_OPPOSITE. -->
<enum name="textEnd" value="3" />
- <!-- Center the paragraph, e.g. ALIGN_CENTER. -->
+ <!-- Center the paragraph, for example: ALIGN_CENTER. -->
<enum name="center" value="4" />
<!-- Align to the start of the view, which is ALIGN_LEFT if the view’s resolved
layoutDirection is LTR, and ALIGN_RIGHT otherwise. -->
<enum name="viewStart" value="5" />
<!-- Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved
- layoutDirection is LTR, and ALIGN_LEFT otherwise -->
+ layoutDirection is LTR, and ALIGN_LEFT otherwise. -->
<enum name="viewEnd" value="6" />
</attr>
@@ -3181,7 +3187,7 @@
method should be considered an option as the default. -->
<attr name="isDefault" format="boolean" />
<!-- Set to true if this input method supports ways to switch to
- a next input method (e.g. a globe key.). When this is true and
+ a next input method (for example, a globe key.). When this is true and
InputMethodManager#shouldOfferSwitchingToNextInputMethod() returns true,
the IME has to offer ways to invoke InputMethodManager#switchToNextInputMethod()
accordingly.
@@ -3190,7 +3196,7 @@
between IMEs and subtypes. -->
<attr name="supportsSwitchingToNextInputMethod" format="boolean" />
<!-- Set to true if this input method supports ways to dismiss the windows assigned to
- the input method (e.g. a dismiss button rendered by the input method itself). The
+ the input method (for example, a dismiss button rendered by the input method itself). The
System UI may optimize the UI by not showing system-level dismiss button if this
value is true.
<p> Must be a boolean value, either "true" or "false". The default value is "false".
@@ -3203,21 +3209,21 @@
<attr name="supportsDismissingWindow" format="boolean" />
</declare-styleable>
- <!-- This is the subtype of InputMethod. Subtype can describe locales (e.g. en_US, fr_FR...)
- and modes (e.g. voice, keyboard...), and is used for IME switch. This subtype allows
- the system to call the specified subtype of the IME directly. -->
+ <!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
+ fr_FR) and modes (for example, voice and keyboard), and is used for IME switch. This
+ subtype allows the system to call the specified subtype of the IME directly. -->
<declare-styleable name="InputMethod_Subtype">
<!-- The name of the subtype. -->
<attr name="label" />
<!-- The icon of the subtype. -->
<attr name="icon" />
- <!-- The locale of the subtype. This string should be a locale (e.g. en_US, fr_FR...)
+ <!-- The locale of the subtype. This string should be a locale (for example en_US and fr_FR)
and will be passed to the IME when the framework calls the IME
with the subtype. This is also used by the framework to know the supported locales
of the IME. -->
<attr name="imeSubtypeLocale" format="string" />
- <!-- The mode of the subtype. This string can be a mode (e.g. voice, keyboard...) and this
- string will be passed to the IME when the framework calls the IME with the
+ <!-- The mode of the subtype. This string can be a mode (for example, voice and keyboard)
+ and this string will be passed to the IME when the framework calls the IME with the
subtype. {@link android.view.inputmethod.InputMethodSubtype#getLocale()} returns the
value specified in this attribute. -->
<attr name="imeSubtypeMode" format="string" />
@@ -3264,12 +3270,13 @@
<attr name="settingsActivity"/>
</declare-styleable>
- <!-- This is the subtype of the spell checker. Subtype can describe locales (e.g. en_US, fr_FR...) -->
+ <!-- This is the subtype of the spell checker. Subtype can describe locales (for example,
+ en_US and fr_FR). -->
<declare-styleable name="SpellChecker_Subtype">
<!-- The name of the subtype. -->
<attr name="label" />
- <!-- The locale of the subtype. This string should be a locale (e.g. en_US, fr_FR...)
- This is also used by the framework to know the supported locales
+ <!-- The locale of the subtype. This string should be a locale (for example, en_US and
+ fr_FR). This is also used by the framework to know the supported locales
of the spell checker. {@link android.view.textservice.SpellCheckerSubtype#getLocale()}
returns the value specified in this attribute. -->
<attr name="subtypeLocale" format="string" />
@@ -3387,25 +3394,25 @@
{@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
<attr name="accessibilityFlags">
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#DEFAULT} -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#DEFAULT}. -->
<flag name="flagDefault" value="0x00000001" />
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS}. -->
<flag name="flagIncludeNotImportantViews" value="0x00000002" />
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}. -->
<flag name="flagRequestTouchExplorationMode" value="0x00000004" />
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY}. -->
<flag name="flagRequestEnhancedWebAccessibility" value="0x00000008" />
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}. -->
<flag name="flagReportViewIds" value="0x00000010" />
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS} -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS}. -->
<flag name="flagRequestFilterKeyEvents" value="0x00000020" />
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}. -->
<flag name="flagRetrieveInteractiveWindows" value="0x00000040" />
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_ENABLE_ACCESSIBILITY_VOLUME} -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_ENABLE_ACCESSIBILITY_VOLUME}. -->
<flag name="flagEnableAccessibilityVolume" value="0x00000080" />
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON}. -->
<flag name="flagRequestAccessibilityButton" value="0x00000100" />
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_CAPTURE_FINGERPRINT_GESTURES} -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_CAPTURE_FINGERPRINT_GESTURES}. -->
<flag name="flagCaptureFingerprintGestures" value="0x00000200" />
</attr>
<!-- Component name of an activity that allows the user to modify
@@ -3682,7 +3689,7 @@
<declare-styleable name="CompoundButton">
<!-- Indicates the initial checked state of this button. -->
<attr name="checked" format="boolean" />
- <!-- Drawable used for the button graphic (e.g. checkbox, radio button, etc). -->
+ <!-- Drawable used for the button graphic (for example, checkbox and radio button). -->
<attr name="button" format="reference" />
<!-- Tint to apply to the button graphic. -->
<attr name="buttonTint" format="color" />
@@ -4105,11 +4112,11 @@
<attr name="minHeight" format="dimension" />
<attr name="maxHeight" />
<attr name="interpolator" format="reference" />
- <!-- Timeout between frames of animation in milliseconds
- {@deprecated Not used by the framework.} -->
+ <!-- Timeout between frames of animation in milliseconds.
+ {@deprecated Not used by the framework}. -->
<attr name="animationResolution" format="integer" />
<!-- Defines if the associated drawables need to be mirrored when in RTL mode.
- Default is false -->
+ Default is false. -->
<attr name="mirrorForRtl" format="boolean" />
<!-- Tint to apply to the progress indicator. -->
<attr name="progressTint" format="color" />
@@ -4720,12 +4727,12 @@
<enum name="full" value="2" />
</attr>
<!-- Specify the type of auto-size. Note that this feature is not supported by EditText,
- works only for TextView -->
+ works only for TextView. -->
<attr name="autoSizeTextType" format="enum">
<!-- No auto-sizing (default). -->
<enum name="none" value="0" />
<!-- Uniform horizontal and vertical text size scaling to fit within the
- container -->
+ container. -->
<enum name="uniform" value="1" />
</attr>
<!-- Specify the auto-size step size if <code>autoSizeTextType</code> is set to
@@ -4736,9 +4743,9 @@
<code>autoSizeTextType</code> set to <code>uniform</code>. Overrides
<code>autoSizeStepGranularity</code> if set. -->
<attr name="autoSizePresetSizes"/>
- <!-- The minimum text size constraint to be used when auto-sizing text -->
+ <!-- The minimum text size constraint to be used when auto-sizing text. -->
<attr name="autoSizeMinTextSize" format="dimension" />
- <!-- The maximum text size constraint to be used when auto-sizing text -->
+ <!-- The maximum text size constraint to be used when auto-sizing text. -->
<attr name="autoSizeMaxTextSize" format="dimension" />
</declare-styleable>
<declare-styleable name="TextViewAppearance">
@@ -4840,7 +4847,7 @@
</declare-styleable>
<declare-styleable name="ViewFlipper">
<attr name="flipInterval" format="integer" min="0" />
- <!-- When true, automatically start animating -->
+ <!-- When true, automatically start animating. -->
<attr name="autoStart" format="boolean" />
</declare-styleable>
<declare-styleable name="AdapterViewAnimator">
@@ -4857,7 +4864,7 @@
</declare-styleable>
<declare-styleable name="AdapterViewFlipper">
<attr name="flipInterval" />
- <!-- When true, automatically start animating -->
+ <!-- When true, automatically start animating. -->
<attr name="autoStart" />
</declare-styleable>
<declare-styleable name="ViewSwitcher">
@@ -5624,7 +5631,7 @@
<!-- Indicates that the layer is opaque and contains no transparent
nor translucent pixels. -->
<enum name="opaque" value="-1" />
- <!-- The layer is completely transparent (no pixel will be drawn.) -->
+ <!-- The layer is completely transparent (no pixel will be drawn). -->
<enum name="transparent" value="-2" />
<!-- The layer has translucent pixels. -->
<enum name="translucent" value="-3" />
@@ -5649,10 +5656,10 @@
<!-- Explicit right padding. Overrides child padding. -->
<attr name="paddingRight" />
<!-- Explicit start padding. Overrides child padding. Takes precedence
- over absolute padding (e.g. left when layout direction is LTR). -->
+ over absolute padding (for example, left when layout direction is LTR). -->
<attr name="paddingStart" />
<!-- Explicit end padding. Overrides child padding. Takes precedence
- over absolute padding (e.g. right when layout direction is LTR). -->
+ over absolute padding (for example, right when layout direction is LTR). -->
<attr name="paddingEnd" />
</declare-styleable>
@@ -5674,7 +5681,7 @@
<attr name="end" format="dimension" />
<!-- Width of the layer. Defaults to the layer's intrinsic width. -->
<attr name="width" />
- <!-- Height of the layer. Defaults to the layer's intrinsic height -->
+ <!-- Height of the layer. Defaults to the layer's intrinsic height. -->
<attr name="height" />
<!-- Gravity used to align the layer within its container. If no value
is specified, the default behavior depends on whether an explicit
@@ -5995,7 +6002,7 @@
<attr name="viewportWidth" format="float"/>
<!-- The height of the canvas the drawing is on. -->
<attr name="viewportHeight" format="float"/>
- <!-- The name of this vector drawable -->
+ <!-- The name of this vector drawable. -->
<attr name="name" />
<!-- The opacity of the whole vector drawable, as a value between 0
(completely transparent) and 1 (completely opaque). -->
@@ -6016,64 +6023,64 @@
<!-- Defines the group used in VectorDrawables. -->
<declare-styleable name="VectorDrawableGroup">
- <!-- The name of this group -->
+ <!-- The name of this group. -->
<attr name="name" />
- <!-- The amount to rotate the group -->
+ <!-- The amount to rotate the group. -->
<attr name="rotation" />
- <!-- The X coordinate of the center of rotation of a group -->
+ <!-- The X coordinate of the center of rotation of a group. -->
<attr name="pivotX" />
- <!-- The Y coordinate of the center of rotation of a group -->
+ <!-- The Y coordinate of the center of rotation of a group. -->
<attr name="pivotY" />
- <!-- The amount to translate the group on X coordinate -->
+ <!-- The amount to translate the group on X coordinate. -->
<attr name="translateX" format="float"/>
- <!-- The amount to translate the group on Y coordinate -->
+ <!-- The amount to translate the group on Y coordinate. -->
<attr name="translateY" format="float"/>
- <!-- The amount to scale the group on X coordinate -->
+ <!-- The amount to scale the group on X coordinate. -->
<attr name="scaleX" />
- <!-- The amount to scale the group on X coordinate -->
+ <!-- The amount to scale the group on X coordinate. -->
<attr name="scaleY" />
</declare-styleable>
<!-- Defines the path used in VectorDrawables. -->
<declare-styleable name="VectorDrawablePath">
- <!-- The name of this path -->
+ <!-- The name of this path. -->
<attr name="name" />
- <!-- The width a path stroke -->
+ <!-- The width a path stroke. -->
<attr name="strokeWidth" format="float" />
- <!-- The color to stroke the path if not defined implies no stroke-->
+ <!-- The color to stroke the path if not defined implies no stroke. -->
<attr name="strokeColor" format="color" />
<!-- The opacity of a path stroke, as a value between 0 (completely transparent)
- and 1 (completely opaque) -->
+ and 1 (completely opaque). -->
<attr name="strokeAlpha" format="float" />
- <!-- The color to fill the path if not defined implies no fill-->
+ <!-- The color to fill the path if not defined implies no fill. -->
<attr name="fillColor" format="color" />
<!-- The alpha of the path fill, as a value between 0 (completely transparent)
- and 1 (completely opaque)-->
+ and 1 (completely opaque). -->
<attr name="fillAlpha" format="float" />
- <!-- The specification of the operations that define the path -->
+ <!-- The specification of the operations that define the path. -->
<attr name="pathData" format="string" />
- <!-- The fraction of the path to trim from the start from 0 to 1 -->
+ <!-- The fraction of the path to trim from the start from 0 to 1. -->
<attr name="trimPathStart" format="float" />
- <!-- The fraction of the path to trim from the end from 0 to 1 -->
+ <!-- The fraction of the path to trim from the end from 0 to 1 . -->
<attr name="trimPathEnd" format="float" />
- <!-- Shift trim region (allows visible region to include the start and end) from 0 to 1 -->
+ <!-- Shift trim region (allows visible region to include the start and end) from 0 to 1. -->
<attr name="trimPathOffset" format="float" />
- <!-- sets the linecap for a stroked path -->
+ <!-- sets the linecap for a stroked path. -->
<attr name="strokeLineCap" format="enum">
<enum name="butt" value="0"/>
<enum name="round" value="1"/>
<enum name="square" value="2"/>
</attr>
- <!-- sets the lineJoin for a stroked path -->
+ <!-- sets the lineJoin for a stroked path. -->
<attr name="strokeLineJoin" format="enum">
<enum name="miter" value="0"/>
<enum name="round" value="1"/>
<enum name="bevel" value="2"/>
</attr>
- <!-- sets the Miter limit for a stroked path -->
+ <!-- sets the Miter limit for a stroked path. -->
<attr name="strokeMiterLimit" format="float"/>
<!-- sets the fillType for a path. It is the same as SVG's "fill-rule" properties.
- For more details, see https://www.w3.org/TR/SVG/painting.html#FillRuleProperty -->
+ For more details, see https://www.w3.org/TR/SVG/painting.html#FillRuleProperty. -->
<attr name="fillType" format="enum">
<enum name="nonZero" value="0"/>
<enum name="evenOdd" value="1"/>
@@ -6082,9 +6089,9 @@
<!-- Defines the clip path used in VectorDrawables. -->
<declare-styleable name="VectorDrawableClipPath">
- <!-- The Name of this path -->
+ <!-- The Name of this path. -->
<attr name="name" />
- <!-- The specification of the operations that define the path -->
+ <!-- The specification of the operations that define the path. -->
<attr name="pathData"/>
</declare-styleable>
@@ -6101,9 +6108,9 @@
<!-- Defines the target used in the AnimatedVectorDrawable. -->
<declare-styleable name="AnimatedVectorDrawableTarget">
- <!-- The name of the target path, group or vector drawable -->
+ <!-- The name of the target path, group or vector drawable. -->
<attr name="name" />
- <!-- The animation for the target path, group or vector drawable -->
+ <!-- The animation for the target path, group or vector drawable. -->
<attr name="animation" />
</declare-styleable>
@@ -6282,13 +6289,13 @@
</declare-styleable>
<declare-styleable name="PathInterpolator">
- <!-- The x coordinate of the first control point of the cubic Bezier -->
+ <!-- The x coordinate of the first control point of the cubic Bezier. -->
<attr name="controlX1" format="float" />
- <!-- The y coordinate of the first control point of the cubic Bezier -->
+ <!-- The y coordinate of the first control point of the cubic Bezier. -->
<attr name="controlY1" format="float" />
- <!-- The x coordinate of the second control point of the cubic Bezier -->
+ <!-- The x coordinate of the second control point of the cubic Bezier. -->
<attr name="controlX2" format="float" />
- <!-- The y coordinate of the second control point of the cubic Bezier -->
+ <!-- The y coordinate of the second control point of the cubic Bezier. -->
<attr name="controlY2" format="float" />
<!-- The control points defined as a path.
When pathData is defined, then both of the control points of the
@@ -6526,7 +6533,7 @@
<attr name="value" />
<attr name="fraction" format="float" />
<!-- Defines a per-interval interpolator for this keyframe. This interpolator will be used
- to interpolate between this keyframe and the previous keyframe.-->
+ to interpolate between this keyframe and the previous keyframe. -->
<attr name="interpolator" />
</declare-styleable>
@@ -6542,7 +6549,7 @@
<attr name="propertyXName" format="string"/>
<!-- Name of the property being animated as the Y coordinate of the pathData. -->
<attr name="propertyYName" format="string"/>
- <!-- The path used to animate the properties in the ObjectAnimator -->
+ <!-- The path used to animate the properties in the ObjectAnimator. -->
<attr name="pathData"/>
</declare-styleable>
@@ -6787,8 +6794,8 @@
<!-- If provided, this is the trigger indicating that the searchable activity
provides suggestions as well. The value must be a fully-qualified content provider
- authority (e.g. "com.example.android.apis.SuggestionProvider") and should match the
- "android:authorities" tag in your content provider's manifest entry. <i>Optional
+ authority (for example, "com.example.android.apis.SuggestionProvider") and should match
+ the "android:authorities" tag in your content provider's manifest entry. <i>Optional
attribute.</i> -->
<attr name="searchSuggestAuthority" format="string" />
<!-- If provided, this will be inserted in the suggestions query Uri, after the authority
@@ -6996,12 +7003,12 @@
<flag name="FUNCTION" value="0x8" />
</attr>
- <!-- The numeric shortcut key. This is the shortcut when using a numeric (e.g., 12-key)
- keyboard. -->
+ <!-- The numeric shortcut key. This is the shortcut when using a numeric (for example,
+ 12-key) keyboard. -->
<attr name="numericShortcut" format="string" />
- <!-- The numeric modifier key. This is the modifier when using a numeric (e.g., 12-key)
- keyboard. The values should be kept in sync with KeyEvent -->
+ <!-- The numeric modifier key. This is the modifier when using a numeric (for example,
+ 12-key) keyboard. The values should be kept in sync with KeyEvent -->
<attr name="numericModifiers">
<flag name="META" value="0x10000" />
<flag name="CTRL" value="0x1000" />
@@ -7121,13 +7128,13 @@
</declare-styleable>
<!-- WARNING: If adding attributes to Preference, make sure it does not conflict
- with a View's attributes. Some subclasses (e.g., EditTextPreference)
+ with a View's attributes. Some subclasses (for example, EditTextPreference)
proxy all attributes to its EditText widget. -->
<eat-comment />
<!-- Base attributes available to Preference. -->
<declare-styleable name="Preference">
- <!-- The optional icon for the preference -->
+ <!-- The optional icon for the preference. -->
<attr name="icon" />
<!-- The key to store the Preference value. -->
<attr name="key" format="string" />
@@ -7549,16 +7556,19 @@
<!-- Reference to the wallpaper's thumbnail bitmap. -->
<attr name="thumbnail" format="reference" />
- <!-- Name of the author and/or source/collection of this component, e.g. Art Collection, Picasso. -->
+ <!-- Name of the author and/or source/collection of this component, for example,
+ Art Collection, Picasso. -->
<attr name="author" format="reference" />
<!-- Short description of the component's purpose or behavior. -->
<attr name="description" />
- <!-- Uri that specifies a link for further context of this wallpaper, e.g. http://www.picasso.org. -->
+ <!-- Uri that specifies a link for further context of this wallpaper, for example,
+ http://www.picasso.org. -->
<attr name="contextUri" format="reference" />
- <!-- Title of the uri that specifies a link for further context of this wallpaper, e.g. Explore collection. -->
+ <!-- Title of the uri that specifies a link for further context of this wallpaper,
+ for example, Explore collection. -->
<attr name="contextDescription" format="reference" />
<!-- Whether to show any metadata when previewing the wallpaper. If this value is
@@ -7703,7 +7713,7 @@
<attr name="detailColumn" format="string" />
<!-- Flag indicating that detail should be built from SocialProvider. -->
<attr name="detailSocialSummary" format="boolean" />
- <!-- Resource representing the term "All Contacts" (e.g. "All Friends" or
+ <!-- Resource representing the term "All Contacts" (for example, "All Friends" or
"All connections"). Optional (Default is "All Contacts"). -->
<attr name="allContactsName" format="string" />
</declare-styleable>
@@ -7728,7 +7738,7 @@
<attr name="targetDescriptions" format="reference" />
<!-- Reference to an array resource that be used to announce the directions with targets around the circle.
- {@deprecated Removed.}-->
+ {@deprecated Removed.} -->
<attr name="directionDescriptions" format="reference" />
</declare-styleable>
@@ -7828,7 +7838,7 @@
<declare-styleable name="ActionBar">
<!-- The type of navigation to use. -->
<attr name="navigationMode">
- <!-- Normal static title text -->
+ <!-- Normal static title text. -->
<enum name="normal" value="0" />
<!-- The action bar will use a selection list for navigation. -->
<enum name="listMode" value="1" />
@@ -7845,9 +7855,9 @@
<flag name="showCustom" value="0x10" />
<flag name="disableHome" value="0x20" />
</attr>
- <!-- Specifies title text used for navigationMode="normal" -->
+ <!-- Specifies title text used for navigationMode="normal". -->
<attr name="title" />
- <!-- Specifies subtitle text used for navigationMode="normal" -->
+ <!-- Specifies subtitle text used for navigationMode="normal". -->
<attr name="subtitle" format="string" />
<!-- Specifies a style to use for title text. -->
<attr name="titleTextStyle" format="reference" />
@@ -7877,7 +7887,7 @@
<attr name="indeterminateProgressStyle" format="reference" />
<!-- Specifies the horizontal padding on either end for an embedded progress bar. -->
<attr name="progressBarPadding" format="dimension" />
- <!-- Up navigation glyph -->
+ <!-- Up navigation glyph. -->
<attr name="homeAsUpIndicator" />
<!-- Specifies padding that should be applied to the left and right sides of
system-provided items in the bar. -->
@@ -7902,7 +7912,7 @@
<!-- Minimum inset for content views within a bar when actions from a menu
are present. Only valid for some themes and configurations. -->
<attr name="contentInsetEndWithActions" format="dimension" />
- <!-- Elevation for the action bar itself -->
+ <!-- Elevation for the action bar itself. -->
<attr name="elevation" />
<!-- Reference to a theme that should be used to inflate popups
shown by widgets in the action bar. -->
@@ -7942,23 +7952,23 @@
<attr name="imeOptions" />
<!-- The input type to set on the query text field. -->
<attr name="inputType" />
- <!-- Close button icon -->
+ <!-- Close button icon. -->
<attr name="closeIcon" format="reference" />
- <!-- Go button icon -->
+ <!-- Go button icon. -->
<attr name="goIcon" format="reference" />
- <!-- Search icon -->
+ <!-- Search icon. -->
<attr name="searchIcon" format="reference" />
- <!-- Search icon displayed as a text field hint -->
+ <!-- Search icon displayed as a text field hint. -->
<attr name="searchHintIcon" format="reference" />
- <!-- Voice button icon -->
+ <!-- Voice button icon. -->
<attr name="voiceIcon" format="reference" />
- <!-- Commit icon shown in the query suggestion row -->
+ <!-- Commit icon shown in the query suggestion row. -->
<attr name="commitIcon" format="reference" />
- <!-- Layout for query suggestion rows -->
+ <!-- Layout for query suggestion rows. -->
<attr name="suggestionRowLayout" format="reference" />
- <!-- Background for the section containing the search query -->
+ <!-- Background for the section containing the search query. -->
<attr name="queryBackground" format="reference" />
- <!-- Background for the section containing the action (e.g. voice search) -->
+ <!-- Background for the section containing the action (for example, voice search). -->
<attr name="submitBackground" format="reference" />
</declare-styleable>
@@ -8001,9 +8011,9 @@
<attr name="thumbTextPadding" format="dimension" />
<!-- TextAppearance style for text displayed on the switch thumb. -->
<attr name="switchTextAppearance" format="reference" />
- <!-- Minimum width for the switch component -->
+ <!-- Minimum width for the switch component. -->
<attr name="switchMinWidth" format="dimension" />
- <!-- Minimum space between the switch and caption text -->
+ <!-- Minimum space between the switch and caption text. -->
<attr name="switchPadding" format="dimension" />
<!-- Whether to split the track and leave a gap for the thumb drawable. -->
<attr name="splitTrack" />
@@ -8012,53 +8022,53 @@
</declare-styleable>
<declare-styleable name="Pointer">
- <!-- Reference to a pointer icon drawable with STYLE_ARROW -->
+ <!-- Reference to a pointer icon drawable with STYLE_ARROW. -->
<attr name="pointerIconArrow" format="reference" />
- <!-- Reference to a pointer icon drawable with STYLE_SPOT_HOVER -->
+ <!-- Reference to a pointer icon drawable with STYLE_SPOT_HOVER. -->
<attr name="pointerIconSpotHover" format="reference" />
- <!-- Reference to a pointer icon drawable with STYLE_SPOT_TOUCH -->
+ <!-- Reference to a pointer icon drawable with STYLE_SPOT_TOUCH. -->
<attr name="pointerIconSpotTouch" format="reference" />
- <!-- Reference to a pointer icon drawable with STYLE_SPOT_ANCHOR -->
+ <!-- Reference to a pointer icon drawable with STYLE_SPOT_ANCHOR. -->
<attr name="pointerIconSpotAnchor" format="reference" />
- <!-- Reference to a pointer drawable with STYLE_CONTEXT_MENU -->
+ <!-- Reference to a pointer drawable with STYLE_CONTEXT_MENU. -->
<attr name="pointerIconContextMenu" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_HAND -->
+ <!-- Reference to a pointer drawable with STYLE_HAND. -->
<attr name="pointerIconHand" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_HELP -->
+ <!-- Reference to a pointer drawable with STYLE_HELP. -->
<attr name="pointerIconHelp" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_WAIT -->
+ <!-- Reference to a pointer drawable with STYLE_WAIT. -->
<attr name="pointerIconWait" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_CELL -->
+ <!-- Reference to a pointer drawable with STYLE_CELL. -->
<attr name="pointerIconCell" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_CROSSHAIR -->
+ <!-- Reference to a pointer drawable with STYLE_CROSSHAIR. -->
<attr name="pointerIconCrosshair" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_TEXT -->
+ <!-- Reference to a pointer drawable with STYLE_TEXT. -->
<attr name="pointerIconText" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_VERTICAL_TEXT -->
+ <!-- Reference to a pointer drawable with STYLE_VERTICAL_TEXT. -->
<attr name="pointerIconVerticalText" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_ALIAS -->
+ <!-- Reference to a pointer drawable with STYLE_ALIAS. -->
<attr name="pointerIconAlias" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_COPY -->
+ <!-- Reference to a pointer drawable with STYLE_COPY. -->
<attr name="pointerIconCopy" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_NODROP -->
+ <!-- Reference to a pointer drawable with STYLE_NODROP. -->
<attr name="pointerIconNodrop" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_ALL_SCROLL -->
+ <!-- Reference to a pointer drawable with STYLE_ALL_SCROLL. -->
<attr name="pointerIconAllScroll" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_HORIZONTAL_DOUBLE_ARROW -->
+ <!-- Reference to a pointer drawable with STYLE_HORIZONTAL_DOUBLE_ARROW. -->
<attr name="pointerIconHorizontalDoubleArrow" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_VERTICAL_DOUBLE_ARROW -->
+ <!-- Reference to a pointer drawable with STYLE_VERTICAL_DOUBLE_ARROW. -->
<attr name="pointerIconVerticalDoubleArrow" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW -->
+ <!-- Reference to a pointer drawable with STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW. -->
<attr name="pointerIconTopRightDiagonalDoubleArrow" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW -->
+ <!-- Reference to a pointer drawable with STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW. -->
<attr name="pointerIconTopLeftDiagonalDoubleArrow" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_ZOOM_IN -->
+ <!-- Reference to a pointer drawable with STYLE_ZOOM_IN. -->
<attr name="pointerIconZoomIn" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_ZOOM_OUT -->
+ <!-- Reference to a pointer drawable with STYLE_ZOOM_OUT. -->
<attr name="pointerIconZoomOut" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_GRAB -->
+ <!-- Reference to a pointer drawable with STYLE_GRAB. -->
<attr name="pointerIconGrab" format="reference"/>
- <!-- Reference to a pointer drawable with STYLE_GRABBING -->
+ <!-- Reference to a pointer drawable with STYLE_GRABBING. -->
<attr name="pointerIconGrabbing" format="reference"/>
</declare-styleable>
@@ -8072,22 +8082,22 @@
</declare-styleable>
<declare-styleable name="Storage">
- <!-- path to mount point for the storage -->
+ <!-- path to mount point for the storage. -->
<attr name="mountPoint" format="string" />
- <!-- user visible description of the storage -->
+ <!-- user visible description of the storage. -->
<attr name="storageDescription" format="string" />
- <!-- true if the storage is the primary external storage -->
+ <!-- true if the storage is the primary external storage. -->
<attr name="primary" format="boolean" />
- <!-- true if the storage is removable -->
+ <!-- true if the storage is removable. -->
<attr name="removable" format="boolean" />
- <!-- true if the storage is emulated via the FUSE sdcard daemon -->
+ <!-- true if the storage is emulated via the FUSE sdcard daemon. -->
<attr name="emulated" format="boolean" />
<!-- number of megabytes of storage MTP should reserve for free storage
- (used for emulated storage that is shared with system's data partition) -->
+ (used for emulated storage that is shared with system's data partition). -->
<attr name="mtpReserve" format="integer" />
- <!-- true if the storage can be shared via USB mass storage -->
+ <!-- true if the storage can be shared via USB mass storage. -->
<attr name="allowMassStorage" format="boolean" />
- <!-- maximum file size for the volume in megabytes, zero or unspecified if it is unbounded -->
+ <!-- maximum file size for the volume in megabytes, zero or unspecified if it is unbounded. -->
<attr name="maxFileSize" format="integer" />
</declare-styleable>
@@ -8114,9 +8124,9 @@
<declare-styleable name="SeekBarPreference">
<attr name="layout" />
<!-- Attribute indicating whether the slider within this preference can be adjusted, that is
- pressing left/right keys when this preference is focused will move the slider accordingly (e.g.
- inline adjustable preferences). False, if the slider within the preference is read-only and
- cannot be adjusted. By default, the seekbar is adjustable. -->
+ pressing left/right keys when this preference is focused will move the slider accordingly
+ (for example, inline adjustable preferences). False, if the slider within the preference is
+ read-only and cannot be adjusted. By default, the seekbar is adjustable. -->
<attr name="adjustable" format="boolean" />
<!-- Flag indicating whether the TextView next to the seekbar that shows the current seekbar value will be
displayed. If true, the view is VISIBLE; if false, the view will be GONE. By default, this view is VISIBLE. -->
@@ -8208,7 +8218,7 @@
<declare-styleable name="PagedView">
<!-- The space between adjacent pages of the PagedView. -->
<attr name="pageSpacing" format="dimension" />
- <!-- The padding for the scroll indicator area -->
+ <!-- The padding for the scroll indicator area. -->
<attr name="scrollIndicatorPaddingLeft" format="dimension" />
<attr name="scrollIndicatorPaddingRight" format="dimension" />
</declare-styleable>
@@ -8473,7 +8483,7 @@
<!-- Describes an item of a GradientColor. Minimally need 2 items to define the gradient
Colors defined in <item> override the simple color attributes such as
- "startColor / centerColor / endColor" are ignored -->
+ "startColor / centerColor / endColor" are ignored. -->
<declare-styleable name="GradientColorItem">
<!-- The offset (or ratio) of this current color item inside the gradient.
The value is only meaningful when it is between 0 and 1. -->
@@ -8517,7 +8527,7 @@
<attr name="fontWeight" format="integer" />
</declare-styleable>
- <!-- Attributes that are read when parsing a <fontfamily> tag, -->
+ <!-- Attributes that are read when parsing a <fontfamily> tag. -->
<declare-styleable name="FontFamily">
<attr name="fontProviderAuthority" format="string" />
<attr name="fontProviderQuery" format="string" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 76f4a7654af7..deacc24be158 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1534,6 +1534,14 @@
of Android higher than the number given here, the permission will not
be requested. -->
<attr name="maxSdkVersion" format="integer" />
+ <!-- Optional: the system must support this feature for the permission to be
+ requested. If it doesn't support the feature, it will be as if the manifest didn't
+ request it at all. -->
+ <attr name="requiredFeature" format="string" />
+ <!-- Optional: the system must NOT support this feature for the permission to be
+ requested. If it does support the feature, it will be as if the manifest didn't
+ request it at all. -->
+ <attr name="requiredNotFeature" format="string" />
</declare-styleable>
<!-- The <code>uses-configuration</code> tag specifies
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2843f4615664..ab2e090b2869 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -239,6 +239,7 @@
<item>"mobile,0,0,0,-1,true"</item>
<item>"mobile_mms,2,0,2,60000,true"</item>
<item>"mobile_supl,3,0,2,60000,true"</item>
+ <item>"mobile_dun,4,0,2,60000,true"</item>
<item>"mobile_hipri,5,0,3,60000,true"</item>
<item>"mobile_fota,10,0,2,60000,true"</item>
<item>"mobile_ims,11,0,2,60000,true"</item>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 01737e73df93..15764a9ceeef 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2797,6 +2797,10 @@
<public name="fontProviderAuthority" />
<public name="fontProviderQuery" />
<public name="autoFillMode" />
+ <public name="primaryContentAlpha" />
+ <public name="secondaryContentAlpha" />
+ <public name="requiredFeature" />
+ <public name="requiredNotFeature" />
</public-group>
<public-group type="style" first-id="0x010302e0">
@@ -2806,9 +2810,6 @@
<public name="textAssist" />
</public-group>
- <public type="attr" name="primaryContentAlpha" />
- <public type="attr" name="secondaryContentAlpha" />
-
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b0c532ca72a9..ea0666413f88 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -587,6 +587,48 @@
<!-- Text shown in place of notification contents when the notification is hidden by policy on a secure lockscreen -->
<string name="notification_hidden_by_policy_text">Contents hidden by policy</string>
+ <!-- Text shown when viewing channel settings for notifications related to the virtual keyboard -->
+ <string name="notification_channel_virtual_keyboard">Virtual keyboard</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to the hardware keyboard -->
+ <string name="notification_channel_physical_keyboard">Physical keyboard</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to security -->
+ <string name="notification_channel_security">Security</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to car mode -->
+ <string name="notification_channel_car_mode">Car mode</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to account status -->
+ <string name="notification_channel_account">Account status</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to developers -->
+ <string name="notification_channel_developer">Developer messages</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to system updates -->
+ <string name="notification_channel_updates">Updates</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to network status -->
+ <string name="notification_channel_network_status">Network status</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to network alerts -->
+ <string name="notification_channel_network_alerts">Network alerts</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to vpn status -->
+ <string name="notification_channel_vpn">VPN status</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to remote device administration -->
+ <string name="notification_channel_device_admin">Device administration</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to important alerts -->
+ <string name="notification_channel_alerts">Alerts</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to being in retail mode -->
+ <string name="notification_channel_retail_mode">Retail demo</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to a usb connection -->
+ <string name="notification_channel_usb">USB connection</string>
+
<!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
<string name="safeMode">Safe mode</string>
@@ -728,6 +770,11 @@
the call to a different number or abort the call altogether.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_answerPhoneCalls">answer phone calls</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_answerPhoneCalls">Allows the app to answer an incoming phone call.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_receiveSms">receive text messages (SMS)</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_receiveSms">Allows the app to receive and process SMS
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 15abf74ef38c..3ba6a274ee8a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2887,4 +2887,21 @@
<!-- Colon separated list of package names that should be granted Notification Listener access -->
<java-symbol type="string" name="config_defaultListenerAccessPackages" />
+
+ <!-- system notification channels -->
+ <java-symbol type="string" name="notification_channel_virtual_keyboard" />
+ <java-symbol type="string" name="notification_channel_physical_keyboard" />
+ <java-symbol type="string" name="notification_channel_security" />
+ <java-symbol type="string" name="notification_channel_car_mode" />
+ <java-symbol type="string" name="notification_channel_account" />
+ <java-symbol type="string" name="notification_channel_developer" />
+ <java-symbol type="string" name="notification_channel_updates" />
+ <java-symbol type="string" name="notification_channel_network_status" />
+ <java-symbol type="string" name="notification_channel_network_alerts" />
+ <java-symbol type="string" name="notification_channel_vpn" />
+ <java-symbol type="string" name="notification_channel_device_admin" />
+ <java-symbol type="string" name="notification_channel_alerts" />
+ <java-symbol type="string" name="notification_channel_retail_mode" />
+ <java-symbol type="string" name="notification_channel_usb" />
+
</resources>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 91ce7a468484..7b8c22962bcc 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1357,6 +1357,9 @@
</intent-filter>
</service>
+ <service android:name="android.content.CrossUserContentService"
+ android:exported="true" />
+
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/graphics/tests/graphicstests/res/color/color1.xml b/core/tests/coretests/res/color/color1.xml
index 87034fa2aeb0..87034fa2aeb0 100644
--- a/graphics/tests/graphicstests/res/color/color1.xml
+++ b/core/tests/coretests/res/color/color1.xml
diff --git a/graphics/tests/graphicstests/res/color/color_no_default.xml b/core/tests/coretests/res/color/color_no_default.xml
index 41a9b5d83c86..41a9b5d83c86 100644
--- a/graphics/tests/graphicstests/res/color/color_no_default.xml
+++ b/core/tests/coretests/res/color/color_no_default.xml
diff --git a/graphics/tests/graphicstests/res/drawable-nodpi/landscape.png b/core/tests/coretests/res/drawable-nodpi/landscape.png
index ddb31806eca9..ddb31806eca9 100644
--- a/graphics/tests/graphicstests/res/drawable-nodpi/landscape.png
+++ b/core/tests/coretests/res/drawable-nodpi/landscape.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test128x96.png b/core/tests/coretests/res/drawable/test128x96.png
index 28dc925d266e..28dc925d266e 100644
--- a/graphics/tests/graphicstests/res/drawable/test128x96.png
+++ b/core/tests/coretests/res/drawable/test128x96.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test16x12.png b/core/tests/coretests/res/drawable/test16x12.png
index 1a3c7e5f9e97..1a3c7e5f9e97 100644
--- a/graphics/tests/graphicstests/res/drawable/test16x12.png
+++ b/core/tests/coretests/res/drawable/test16x12.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test256x192.png b/core/tests/coretests/res/drawable/test256x192.png
index ce8ee04b68be..ce8ee04b68be 100644
--- a/graphics/tests/graphicstests/res/drawable/test256x192.png
+++ b/core/tests/coretests/res/drawable/test256x192.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test320x240.png b/core/tests/coretests/res/drawable/test320x240.png
index 9b5800da243d..9b5800da243d 100644
--- a/graphics/tests/graphicstests/res/drawable/test320x240.png
+++ b/core/tests/coretests/res/drawable/test320x240.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test32x24.png b/core/tests/coretests/res/drawable/test32x24.png
index 76bab755c943..76bab755c943 100644
--- a/graphics/tests/graphicstests/res/drawable/test32x24.png
+++ b/core/tests/coretests/res/drawable/test32x24.png
Binary files differ
diff --git a/graphics/tests/graphicstests/res/drawable/test64x48.png b/core/tests/coretests/res/drawable/test64x48.png
index 91196130154c..91196130154c 100644
--- a/graphics/tests/graphicstests/res/drawable/test64x48.png
+++ b/core/tests/coretests/res/drawable/test64x48.png
Binary files differ
diff --git a/core/tests/coretests/res/values/colors.xml b/core/tests/coretests/res/values/colors.xml
index f881660249f2..f01af8421515 100644
--- a/core/tests/coretests/res/values/colors.xml
+++ b/core/tests/coretests/res/values/colors.xml
@@ -23,4 +23,7 @@
<drawable name="blue">#ff0000ff</drawable>
<drawable name="green">#ff00ff00</drawable>
<drawable name="yellow">#ffffff00</drawable>
+ <color name="testcolor1">#ff00ff00</color>
+ <color name="testcolor2">#ffff0000</color>
+ <color name="failColor">#ff0000ff</color>
</resources>
diff --git a/core/tests/coretests/src/android/app/activity/LocalProvider.java b/core/tests/coretests/src/android/app/activity/LocalProvider.java
index d6a10c2061b9..b7a63cec7d6f 100644
--- a/core/tests/coretests/src/android/app/activity/LocalProvider.java
+++ b/core/tests/coretests/src/android/app/activity/LocalProvider.java
@@ -29,6 +29,19 @@ import android.util.Log;
public class LocalProvider extends ContentProvider {
private static final String TAG = "LocalProvider";
+ private static final String AUTHORITY = "com.android.frameworks.coretests.LocalProvider";
+ private static final String TABLE_DATA_NAME = "data";
+ public static final Uri TABLE_DATA_URI =
+ Uri.parse("content://" + AUTHORITY + "/" + TABLE_DATA_NAME);
+
+ public static final String COLUMN_TEXT_NAME = "text";
+ public static final String COLUMN_INTEGER_NAME = "integer";
+
+ public static final String TEXT1 = "first data";
+ public static final String TEXT2 = "second data";
+ public static final int INTEGER1 = 100;
+ public static final int INTEGER2 = 101;
+
private SQLiteOpenHelper mOpenHelper;
private static final int DATA = 1;
@@ -51,13 +64,20 @@ public class LocalProvider extends ContentProvider {
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE data (" +
+ db.execSQL("CREATE TABLE " + TABLE_DATA_NAME + " (" +
"_id INTEGER PRIMARY KEY," +
- "text TEXT, " +
- "integer INTEGER);");
+ COLUMN_TEXT_NAME + " TEXT, " +
+ COLUMN_INTEGER_NAME + " INTEGER);");
// insert alarms
- db.execSQL("INSERT INTO data (text, integer) VALUES ('first data', 100);");
+ db.execSQL(getInsertCommand(TEXT1, INTEGER1));
+ db.execSQL(getInsertCommand(TEXT2, INTEGER2));
+ }
+
+ private String getInsertCommand(String textValue, int integerValue) {
+ return "INSERT INTO " + TABLE_DATA_NAME
+ + " (" + COLUMN_TEXT_NAME + ", " + COLUMN_INTEGER_NAME + ") "
+ + "VALUES ('" + textValue + "', " + integerValue + ");";
}
@Override
@@ -74,6 +94,10 @@ public class LocalProvider extends ContentProvider {
public LocalProvider() {
}
+ static public Uri getTableDataUriForRow(int rowId) {
+ return Uri.parse("content://" + AUTHORITY + "/" + TABLE_DATA_NAME + "/" + rowId);
+ }
+
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
new file mode 100644
index 000000000000..5f6f62a67b05
--- /dev/null
+++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2017 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.content;
+
+
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager;
+import android.app.activity.LocalProvider;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+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.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+abstract class AbstractCrossUserContentResolverTest {
+ private final static int TIMEOUT_SERVICE_CONNECTION_SEC = 4;
+ private final static int TIMEOUT_CONTENT_CHANGE_SEC = 4;
+
+ private Context mContext;
+ protected UserManager mUm;
+ private int mCrossUserId = -1;
+ private CrossUserContentServiceConnection mServiceConnection;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mUm = UserManager.get(mContext);
+ final UserInfo userInfo = createUser();
+ mCrossUserId = userInfo.id;
+ final PackageManager pm = mContext.getPackageManager();
+ pm.installExistingPackageAsUser(mContext.getPackageName(), mCrossUserId);
+ ActivityManager.getService().startUserInBackground(mCrossUserId);
+
+ final CountDownLatch connectionLatch = new CountDownLatch(1);
+ mServiceConnection = new CrossUserContentServiceConnection(connectionLatch);
+ mContext.bindServiceAsUser(
+ new Intent(mContext, CrossUserContentService.class),
+ mServiceConnection,
+ Context.BIND_AUTO_CREATE,
+ UserHandle.of(mCrossUserId));
+ if (!connectionLatch.await(TIMEOUT_SERVICE_CONNECTION_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for service connection to establish");
+ }
+ }
+
+ protected abstract UserInfo createUser() throws RemoteException ;
+
+ @After
+ public void tearDown() throws Exception {
+ if (mCrossUserId != -1) {
+ mUm.removeUser(mCrossUserId);
+ }
+ if (mServiceConnection != null) {
+ mContext.unbindService(mServiceConnection);
+ }
+ }
+
+ /**
+ * Register an observer for an URI in another user and verify that it receives
+ * onChange callback when data at the URI changes.
+ */
+ @Test
+ public void testRegisterContentObserver() throws Exception {
+ Context crossUserContext = null;
+ String packageName = null;
+ try {
+ packageName = InstrumentationRegistry.getContext().getPackageName();
+ crossUserContext =
+ InstrumentationRegistry.getContext().createPackageContextAsUser(
+ packageName, 0 /* flags */, UserHandle.of(mCrossUserId));
+ } catch (NameNotFoundException e) {
+ fail("Couldn't find package " + packageName + " in u" + mCrossUserId);
+ }
+
+ final CountDownLatch updateLatch = new CountDownLatch(1);
+ final Uri uriToUpdate = LocalProvider.getTableDataUriForRow(2);
+ final TestContentObserver observer = new TestContentObserver(updateLatch,
+ uriToUpdate, mCrossUserId);
+ crossUserContext.getContentResolver().registerContentObserver(
+ LocalProvider.TABLE_DATA_URI, true, observer, mCrossUserId);
+ mServiceConnection.getService().updateContent(uriToUpdate, "New Text", 42);
+ if (!updateLatch.await(TIMEOUT_CONTENT_CHANGE_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for the content change callback");
+ }
+ }
+
+ /**
+ * Register an observer for an URI in the current user and verify that another user can
+ * notify changes for this URI.
+ */
+ @Test
+ public void testNotifyChange() throws Exception {
+ final CountDownLatch notifyLatch = new CountDownLatch(1);
+ final Uri notifyUri = LocalProvider.TABLE_DATA_URI;
+ final TestContentObserver observer = new TestContentObserver(notifyLatch,
+ notifyUri, UserHandle.myUserId());
+ mContext.getContentResolver().registerContentObserver(notifyUri, true, observer);
+ mServiceConnection.getService().notifyForUriAsUser(notifyUri, UserHandle.myUserId());
+ if (!notifyLatch.await(TIMEOUT_CONTENT_CHANGE_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for the notify callback");
+ }
+ }
+
+ private static final class CrossUserContentServiceConnection implements ServiceConnection {
+ private ICrossUserContentService mService;
+ private final CountDownLatch mLatch;
+
+ public CrossUserContentServiceConnection(CountDownLatch latch) {
+ mLatch = latch;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mService = ICrossUserContentService.Stub.asInterface(service);
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+
+ public ICrossUserContentService getService() {
+ return mService;
+ }
+ }
+
+ private static final class TestContentObserver extends ContentObserver {
+ private final CountDownLatch mLatch;
+ private final Uri mExpectedUri;
+ private final int mExpectedUserId;
+
+ public TestContentObserver(CountDownLatch latch, Uri exptectedUri, int expectedUserId) {
+ super(null);
+ mLatch = latch;
+ mExpectedUri = exptectedUri;
+ mExpectedUserId = expectedUserId;
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri, int userId) {
+ if (mExpectedUri.equals(uri) && mExpectedUserId == userId) {
+ mLatch.countDown();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/CrossUserContentService.java b/core/tests/coretests/src/android/content/CrossUserContentService.java
new file mode 100644
index 000000000000..9cbe549ba112
--- /dev/null
+++ b/core/tests/coretests/src/android/content/CrossUserContentService.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 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.content;
+
+import android.app.Service;
+import android.app.activity.LocalProvider;
+import android.net.Uri;
+import android.os.IBinder;
+
+public class CrossUserContentService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mLocalService.asBinder();
+ }
+
+ private ICrossUserContentService mLocalService = new ICrossUserContentService.Stub() {
+ @Override
+ public void updateContent(Uri uri, String key, int value) {
+ final ContentValues values = new ContentValues();
+ values.put(LocalProvider.COLUMN_TEXT_NAME, key);
+ values.put(LocalProvider.COLUMN_INTEGER_NAME, value);
+ getContentResolver().update(uri, values, null, null);
+ }
+
+ @Override
+ public void notifyForUriAsUser(Uri uri, int userId) {
+ getContentResolver().notifyChange(uri, null, false, userId);
+ }
+ };
+} \ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/ICrossUserContentService.aidl b/core/tests/coretests/src/android/content/ICrossUserContentService.aidl
new file mode 100644
index 000000000000..2c5cde44a627
--- /dev/null
+++ b/core/tests/coretests/src/android/content/ICrossUserContentService.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 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.content;
+
+import android.net.Uri;
+
+interface ICrossUserContentService {
+ void updateContent(in Uri uri, String key, int value);
+ void notifyForUriAsUser(in Uri uri, int userId);
+} \ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
new file mode 100644
index 000000000000..4856ecd73dff
--- /dev/null
+++ b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 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.content;
+
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+/**
+ * To run the tests, use
+ *
+ * runtest -c android.content.ManagedUserContentResolverTest frameworks-core
+ *
+ * or the following steps:
+ *
+ * Build: m FrameworksCoreTests
+ * Install: adb install -r \
+ * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
+ * Run: adb shell am instrument -e class android.content.ManagedUserContentResolverTest -w \
+ * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ */
+public class ManagedUserContentResolverTest extends AbstractCrossUserContentResolverTest {
+ @Override
+ protected UserInfo createUser() throws RemoteException {
+ return mUm.createProfileForUser("Managed user",
+ UserInfo.FLAG_MANAGED_PROFILE, UserHandle.myUserId());
+ }
+}
diff --git a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
new file mode 100644
index 000000000000..7a6e614c2dfc
--- /dev/null
+++ b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 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.content;
+
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+
+/**
+ * To run the tests, use
+ *
+ * runtest -c android.content.SecondaryUserContentResolverTest frameworks-core
+ *
+ * or the following steps:
+ *
+ * Build: m FrameworksCoreTests
+ * Install: adb install -r \
+ * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
+ * Run: adb shell am instrument -e class android.content.SecondaryUserContentResolverTest -w \
+ * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ */
+public class SecondaryUserContentResolverTest extends AbstractCrossUserContentResolverTest {
+ @Override
+ protected UserInfo createUser() throws RemoteException {
+ return mUm.createUser("Secondary user", 0);
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
index e5a92bf23bdc..5dd3c2ce6b5d 100644
--- a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
+++ b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
@@ -91,6 +91,28 @@ public class ParceledListSliceTest extends TestCase {
}
}
+ public void testStringList() throws Exception {
+ final int objectCount = 400;
+ List<String> list = new ArrayList<String>();
+ for (long i = 0; i < objectCount; i++) {
+ list.add(Long.toString(i * (6 - i)));
+ }
+
+ StringParceledListSlice slice;
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.writeParcelable(new StringParceledListSlice(list), 0);
+ parcel.setDataPosition(0);
+ slice = parcel.readParcelable(getClass().getClassLoader());
+ } finally {
+ parcel.recycle();
+ }
+
+ assertNotNull(slice);
+ assertNotNull(slice.getList());
+ assertEquals(list, slice.getList());
+ }
+
/**
* Test that only homogeneous elements may be unparceled.
*/
diff --git a/graphics/tests/graphicstests/src/android/graphics/BitmapFactoryTest.java b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
index 09820efefeda..e9e2a4d098f0 100644
--- a/graphics/tests/graphicstests/src/android/graphics/BitmapFactoryTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
@@ -19,11 +19,11 @@ package android.graphics;
import android.os.ParcelFileDescriptor;
import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
-import junit.framework.TestCase;
-
public class BitmapFactoryTest extends TestCase {
diff --git a/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java
index 685a9980fdc4..3666dddb0782 100644
--- a/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapTest.java
@@ -17,6 +17,7 @@
package android.graphics;
import android.test.suitebuilder.annotation.SmallTest;
+
import junit.framework.TestCase;
@@ -38,11 +39,11 @@ public class BitmapTest extends TestCase {
assertEquals("rowbytes", 400, bm1.getRowBytes());
assertEquals("rowbytes", 200, bm2.getRowBytes());
- assertEquals("rowbytes", 200, bm3.getRowBytes());
-
+ assertEquals("rowbytes", 400, bm3.getRowBytes());
+
assertEquals("byteCount", 80000, bm1.getByteCount());
assertEquals("byteCount", 40000, bm2.getByteCount());
- assertEquals("byteCount", 40000, bm3.getByteCount());
+ assertEquals("byteCount", 80000, bm3.getByteCount());
assertEquals("height", 200, bm1.getHeight());
assertEquals("height", 200, bm2.getHeight());
@@ -51,10 +52,10 @@ public class BitmapTest extends TestCase {
assertTrue("hasAlpha", bm1.hasAlpha());
assertFalse("hasAlpha", bm2.hasAlpha());
assertTrue("hasAlpha", bm3.hasAlpha());
-
+
assertTrue("getConfig", bm1.getConfig() == Bitmap.Config.ARGB_8888);
assertTrue("getConfig", bm2.getConfig() == Bitmap.Config.RGB_565);
- assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_4444);
+ assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_8888);
}
@SmallTest
@@ -181,12 +182,12 @@ public class BitmapTest extends TestCase {
for (int i = 0; i < 256; i++) {
colors[i] = (i << 24) | (0xFF << 16) | (0x80 << 8) | 0;
}
-
+
Bitmap.Config config = Bitmap.Config.ARGB_8888;
// create a bitmap with the color array specified
Bitmap bm1 = Bitmap.createBitmap(colors, 16, 16, config);
-
+
// create a bitmap with no colors, but then call setPixels
Bitmap bm2 = Bitmap.createBitmap(16, 16, config);
bm2.setPixels(colors, 0, 16, 0, 0, 16, 16);
@@ -197,32 +198,32 @@ public class BitmapTest extends TestCase {
int c0 = colors[i];
int c1 = bm1.getPixel(i % 16, i / 16);
int c2 = bm2.getPixel(i % 16, i / 16);
-
+
// these two should always be identical
assertEquals("getPixel", c1, c2);
-
+
// comparing the original (c0) with the returned color is tricky,
// since it gets premultiplied during the set(), and unpremultiplied
// by the get().
int a0 = Color.alpha(c0);
int a1 = Color.alpha(c1);
assertEquals("alpha", a0, a1);
-
+
int r0 = Color.red(c0);
int r1 = Color.red(c1);
int rr = computePrePostMul(a0, r0);
assertTrue("red", Math.abs(rr - r1) <= tolerance);
-
+
int g0 = Color.green(c0);
int g1 = Color.green(c1);
int gg = computePrePostMul(a0, g0);
assertTrue("green", Math.abs(gg - g1) <= tolerance);
-
+
int b0 = Color.blue(c0);
int b1 = Color.blue(c1);
int bb = computePrePostMul(a0, b0);
assertTrue("blue", Math.abs(bb - b1) <= tolerance);
-
+
if (false) {
int cc = Color.argb(a0, rr, gg, bb);
android.util.Log.d("skia", "original " + Integer.toHexString(c0) +
@@ -231,4 +232,16 @@ public class BitmapTest extends TestCase {
}
}
}
+
+ @SmallTest
+ public void testCreateHardwareBitmapFromGraphicBuffer() {
+ GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888,
+ GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_SOFTWARE_MASK);
+ Canvas canvas = buffer.lockCanvas();
+ canvas.drawColor(Color.YELLOW);
+ buffer.unlockCanvasAndPost(canvas);
+ Bitmap hardwareBitmap = Bitmap.createHardwareBitmap(buffer);
+ assertTrue(hardwareBitmap.isPremultiplied());
+ assertFalse(hardwareBitmap.isMutable());
+ }
}
diff --git a/graphics/tests/graphicstests/src/android/graphics/ColorStateListTest.java b/core/tests/coretests/src/android/graphics/ColorStateListTest.java
index eb1025c36c18..374d1421bdbc 100644
--- a/graphics/tests/graphicstests/src/android/graphics/ColorStateListTest.java
+++ b/core/tests/coretests/src/android/graphics/ColorStateListTest.java
@@ -16,13 +16,13 @@
package android.graphics;
-import com.android.frameworks.graphicstests.R;
-
-import android.content.res.Resources;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.frameworks.coretests.R;
+
/**
* Tests of {@link android.graphics.ColorStateList}
*/
diff --git a/graphics/tests/graphicstests/src/android/graphics/GraphicsPerformanceTests.java b/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
index f60ac7bdb5e5..164c1aa770bd 100644
--- a/graphics/tests/graphicstests/src/android/graphics/GraphicsPerformanceTests.java
+++ b/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
@@ -16,19 +16,15 @@
package android.graphics;
-import junit.framework.Assert;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Paint;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
-import com.android.frameworks.graphicstests.R;
+import com.android.frameworks.coretests.R;
+
+import junit.framework.Assert;
/**
* Graphics Performance Tests
diff --git a/graphics/tests/graphicstests/src/android/graphics/GraphicsTests.java b/core/tests/coretests/src/android/graphics/GraphicsTests.java
index 70f5976843bc..70f5976843bc 100644
--- a/graphics/tests/graphicstests/src/android/graphics/GraphicsTests.java
+++ b/core/tests/coretests/src/android/graphics/GraphicsTests.java
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
index 2a3d463463c0..5811ca0fd266 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -156,4 +156,213 @@ public class PaintTest extends InstrumentationTestCase {
}
}
}
+
+ public void testGetTextRunAdvances() {
+ {
+ // LTR
+ String text = "abcdef";
+ assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), false, true);
+ assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), false, false);
+ }
+ {
+ // RTL
+ final String text =
+ "\u0645\u0627\u0020\u0647\u064A\u0020\u0627\u0644\u0634" +
+ "\u0641\u0631\u0629\u0020\u0627\u0644\u0645\u0648\u062D" +
+ "\u062F\u0629\u0020\u064A\u0648\u0646\u064A\u0643\u0648" +
+ "\u062F\u061F";
+ assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), true, true);
+ assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), true, false);
+ }
+ }
+
+ private void assertGetTextRunAdvances(String str, int start, int end,
+ int contextStart, int contextEnd, boolean isRtl, boolean compareWithOtherMethods) {
+ Paint p = new Paint();
+
+ final int count = end - start;
+ final float[][] advanceArrays = new float[4][count];
+
+ final float advance = p.getTextRunAdvances(str, start, end, contextStart, contextEnd,
+ isRtl, advanceArrays[0], 0);
+
+ char chars[] = str.toCharArray();
+ final float advance_c = p.getTextRunAdvances(chars, start, count, contextStart,
+ contextEnd - contextStart, isRtl, advanceArrays[1], 0);
+ assertEquals(advance, advance_c, 1.0f);
+
+ for (int c = 1; c < count; ++c) {
+ final float firstPartAdvance = p.getTextRunAdvances(str, start, start + c,
+ contextStart, contextEnd, isRtl, advanceArrays[2], 0);
+ final float secondPartAdvance = p.getTextRunAdvances(str, start + c, end,
+ contextStart, contextEnd, isRtl, advanceArrays[2], c);
+ assertEquals(advance, firstPartAdvance + secondPartAdvance, 1.0f);
+
+
+ final float firstPartAdvance_c = p.getTextRunAdvances(chars, start, c,
+ contextStart, contextEnd - contextStart, isRtl, advanceArrays[3], 0);
+ final float secondPartAdvance_c = p.getTextRunAdvances(chars, start + c,
+ count - c, contextStart, contextEnd - contextStart, isRtl,
+ advanceArrays[3], c);
+ assertEquals(advance, firstPartAdvance_c + secondPartAdvance_c, 1.0f);
+ assertEquals(firstPartAdvance, firstPartAdvance_c, 1.0f);
+ assertEquals(secondPartAdvance, secondPartAdvance_c, 1.0f);
+
+ for (int i = 1; i < advanceArrays.length; i++) {
+ for (int j = 0; j < count; j++) {
+ assertEquals(advanceArrays[0][j], advanceArrays[i][j], 1.0f);
+ }
+ }
+
+ // Compare results with measureText, getRunAdvance, and getTextWidths.
+ if (compareWithOtherMethods && start == contextStart && end == contextEnd) {
+ assertEquals(advance, p.measureText(str, start, end), 1.0f);
+ assertEquals(advance, p.getRunAdvance(
+ str, start, end, contextStart, contextEnd, isRtl, end), 1.0f);
+
+ final float[] widths = new float[count];
+ p.getTextWidths(str, start, end, widths);
+ for (int i = 0; i < count; i++) {
+ assertEquals(advanceArrays[0][i], widths[i], 1.0f);
+ }
+ }
+ }
+ }
+
+ public void testGetTextRunAdvances_invalid() {
+ Paint p = new Paint();
+ String text = "test";
+
+ try {
+ p.getTextRunAdvances((String)null, 0, 0, 0, 0, false, null, 0);
+ fail("Should throw an IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ p.getTextRunAdvances((CharSequence)null, 0, 0, 0, 0, false, null, 0);
+ fail("Should throw an IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ p.getTextRunAdvances((char[])null, 0, 0, 0, 0, false, null, 0);
+ fail("Should throw an IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
+ new float[text.length() - 1], 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
+ new float[text.length()], 1);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // 0 > contextStart
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), -1, text.length(), false, null, 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // contextStart > start
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), 1, text.length(), false, null, 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // start > end
+ try {
+ p.getTextRunAdvances(text, 1, 0, 0, text.length(), false, null, 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // end > contextEnd
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), 0, text.length() - 1, false, null, 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ // contextEnd > text.length
+ try {
+ p.getTextRunAdvances(text, 0, text.length(), 0, text.length() + 1, false, null, 0);
+ fail("Should throw an IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ public void testMeasureTextBidi() {
+ Paint p = new Paint();
+ {
+ String bidiText = "abc \u0644\u063A\u0629 def";
+ p.setBidiFlags(Paint.BIDI_LTR);
+ float width = p.measureText(bidiText, 0, 4);
+ p.setBidiFlags(Paint.BIDI_RTL);
+ width += p.measureText(bidiText, 4, 7);
+ p.setBidiFlags(Paint.BIDI_LTR);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ {
+ String bidiText = "abc \u0644\u063A\u0629 def";
+ p.setBidiFlags(Paint.BIDI_DEFAULT_LTR);
+ float width = p.measureText(bidiText, 0, 4);
+ width += p.measureText(bidiText, 4, 7);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ {
+ String bidiText = "abc \u0644\u063A\u0629 def";
+ p.setBidiFlags(Paint.BIDI_FORCE_LTR);
+ float width = p.measureText(bidiText, 0, 4);
+ width += p.measureText(bidiText, 4, 7);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ {
+ String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
+ p.setBidiFlags(Paint.BIDI_RTL);
+ float width = p.measureText(bidiText, 0, 4);
+ p.setBidiFlags(Paint.BIDI_LTR);
+ width += p.measureText(bidiText, 4, 7);
+ p.setBidiFlags(Paint.BIDI_RTL);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ {
+ String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
+ p.setBidiFlags(Paint.BIDI_DEFAULT_RTL);
+ float width = p.measureText(bidiText, 0, 4);
+ width += p.measureText(bidiText, 4, 7);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ {
+ String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
+ p.setBidiFlags(Paint.BIDI_FORCE_RTL);
+ float width = p.measureText(bidiText, 0, 4);
+ width += p.measureText(bidiText, 4, 7);
+ width += p.measureText(bidiText, 7, bidiText.length());
+ assertEquals(width, p.measureText(bidiText), 1.0f);
+ }
+ }
+
+ public void testSetGetWordSpacing() {
+ Paint p = new Paint();
+ assertEquals(0.0f, p.getWordSpacing()); // The default value should be 0.
+ p.setWordSpacing(1.0f);
+ assertEquals(1.0f, p.getWordSpacing());
+ p.setWordSpacing(-2.0f);
+ assertEquals(-2.0f, p.getWordSpacing());
+ }
}
diff --git a/graphics/tests/graphicstests/src/android/graphics/PathTest.java b/core/tests/coretests/src/android/graphics/PathTest.java
index 96200bc099f9..78e4959da92a 100644
--- a/graphics/tests/graphicstests/src/android/graphics/PathTest.java
+++ b/core/tests/coretests/src/android/graphics/PathTest.java
@@ -17,6 +17,7 @@
package android.graphics;
import android.test.suitebuilder.annotation.SmallTest;
+
import junit.framework.TestCase;
diff --git a/graphics/tests/graphicstests/src/android/graphics/ThreadBitmapTest.java b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
index 84bdc5683ac6..909a8d97df51 100644
--- a/graphics/tests/graphicstests/src/android/graphics/ThreadBitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
@@ -16,10 +16,10 @@
package android.graphics;
-import junit.framework.TestCase;
-import android.graphics.Bitmap;
import android.test.suitebuilder.annotation.LargeTest;
+import junit.framework.TestCase;
+
public class ThreadBitmapTest extends TestCase {
@Override
diff --git a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java b/core/tests/coretests/src/android/graphics/VariationParserTest.java
index c7a46a369772..a2ead405b1bc 100644
--- a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
+++ b/core/tests/coretests/src/android/graphics/VariationParserTest.java
@@ -18,9 +18,11 @@ package android.graphics;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.FontConfig;
-import java.util.List;
+
import junit.framework.TestCase;
+import java.util.List;
+
public class VariationParserTest extends TestCase {
diff --git a/graphics/tests/graphicstests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
index d3e1a431c309..b50955b82b36 100644
--- a/graphics/tests/graphicstests/src/android/graphics/drawable/IconTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
@@ -26,14 +26,13 @@ import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import com.android.frameworks.coretests.R;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
-import java.lang.Override;
-import java.util.Arrays;
import java.util.ArrayList;
-
-import com.android.frameworks.graphicstests.R;
+import java.util.Arrays;
public class IconTest extends AndroidTestCase {
public static final String TAG = IconTest.class.getSimpleName();
@@ -109,13 +108,13 @@ public class IconTest extends AndroidTestCase {
}
@SmallTest
- public void testWithMaskableBitmap() throws Exception {
+ public void testWithAdaptiveBitmap() throws Exception {
final Bitmap bm1 = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888);
final Canvas can1 = new Canvas(bm1);
can1.drawColor(0xFFFF0000);
- final Icon im1 = Icon.createWithMaskableBitmap(bm1);
+ final Icon im1 = Icon.createWithAdaptiveBitmap(bm1);
final AdaptiveIconDrawable draw1 = (AdaptiveIconDrawable) im1.loadDrawable(mContext);
@@ -133,12 +132,12 @@ public class IconTest extends AndroidTestCase {
L("writing temp bitmaps to %s...", dir);
bm1.compress(Bitmap.CompressFormat.PNG, 100,
- new FileOutputStream(new File(dir, "maskable-bitmap1-original.png")));
+ new FileOutputStream(new File(dir, "adaptive-bitmap1-original.png")));
test1.compress(Bitmap.CompressFormat.PNG, 100,
- new FileOutputStream(new File(dir, "maskable-bitmap1-test.png")));
+ new FileOutputStream(new File(dir, "adaptive-bitmap1-test.png")));
if (!equalBitmaps(bm1, test1, draw1.getSafeZone())) {
findBitmapDifferences(bm1, test1);
- fail("maskable bitmap1 differs, check " + dir);
+ fail("adaptive bitmap1 differs, check " + dir);
}
}
diff --git a/graphics/tests/graphicstests/src/android/graphics/drawable/StateListDrawableTest.java b/core/tests/coretests/src/android/graphics/drawable/StateListDrawableTest.java
index 0d9f72e87ceb..03a9c2522984 100644
--- a/graphics/tests/graphicstests/src/android/graphics/drawable/StateListDrawableTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/StateListDrawableTest.java
@@ -16,14 +16,14 @@
package android.graphics.drawable;
-import junit.framework.TestCase;
-
import android.R;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.util.StateSet;
import android.view.MockView;
+import junit.framework.TestCase;
+
/**
* Tests for StateListDrawable
*
diff --git a/graphics/tests/graphicstests/src/android/view/MockView.java b/core/tests/coretests/src/android/view/MockView.java
index 1d416bde50dd..1d416bde50dd 100644
--- a/graphics/tests/graphicstests/src/android/view/MockView.java
+++ b/core/tests/coretests/src/android/view/MockView.java
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index ff1312a4cd58..8ce7ed02de14 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -68,7 +68,7 @@ public final class Icon implements Parcelable {
/** @hide */
public static final int TYPE_URI = 4;
/** @hide */
- public static final int TYPE_BITMAP_MASKABLE = 5;
+ public static final int TYPE_ADAPTIVE_BITMAP = 5;
private static final int VERSION_STREAM_SERIALIZER = 1;
@@ -103,7 +103,7 @@ public final class Icon implements Parcelable {
* {@link #TYPE_RESOURCE},
* {@link #TYPE_DATA}, or
* {@link #TYPE_URI}.
- * {@link #TYPE_BITMAP_MASKABLE}
+ * {@link #TYPE_ADAPTIVE_BITMAP}
* @hide
*/
public int getType() {
@@ -115,7 +115,7 @@ public final class Icon implements Parcelable {
* @hide
*/
public Bitmap getBitmap() {
- if (mType != TYPE_BITMAP && mType != TYPE_BITMAP_MASKABLE) {
+ if (mType != TYPE_BITMAP && mType != TYPE_ADAPTIVE_BITMAP) {
throw new IllegalStateException("called getBitmap() on " + this);
}
return (Bitmap) mObj1;
@@ -221,7 +221,7 @@ public final class Icon implements Parcelable {
private static final String typeToString(int x) {
switch (x) {
case TYPE_BITMAP: return "BITMAP";
- case TYPE_BITMAP_MASKABLE: return "BITMAP_MASKABLE";
+ case TYPE_ADAPTIVE_BITMAP: return "BITMAP_MASKABLE";
case TYPE_DATA: return "DATA";
case TYPE_RESOURCE: return "RESOURCE";
case TYPE_URI: return "URI";
@@ -289,7 +289,7 @@ public final class Icon implements Parcelable {
switch (mType) {
case TYPE_BITMAP:
return new BitmapDrawable(context.getResources(), getBitmap());
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
return new AdaptiveIconDrawable(null,
new BitmapDrawable(context.getResources(), getBitmap()));
case TYPE_RESOURCE:
@@ -395,7 +395,7 @@ public final class Icon implements Parcelable {
* @hide
*/
public void convertToAshmem() {
- if ((mType == TYPE_BITMAP || mType == TYPE_BITMAP_MASKABLE) &&
+ if ((mType == TYPE_BITMAP || mType == TYPE_ADAPTIVE_BITMAP) &&
getBitmap().isMutable() &&
getBitmap().getAllocationByteCount() >= MIN_ASHMEM_ICON_SIZE) {
setBitmap(getBitmap().createAshmemBitmap());
@@ -416,7 +416,7 @@ public final class Icon implements Parcelable {
switch (mType) {
case TYPE_BITMAP:
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
getBitmap().compress(Bitmap.CompressFormat.PNG, 100, dataStream);
break;
case TYPE_DATA:
@@ -452,8 +452,8 @@ public final class Icon implements Parcelable {
switch (type) {
case TYPE_BITMAP:
return createWithBitmap(BitmapFactory.decodeStream(inputStream));
- case TYPE_BITMAP_MASKABLE:
- return createWithMaskableBitmap(BitmapFactory.decodeStream(inputStream));
+ case TYPE_ADAPTIVE_BITMAP:
+ return createWithAdaptiveBitmap(BitmapFactory.decodeStream(inputStream));
case TYPE_DATA:
final int length = inputStream.readInt();
final byte[] data = new byte[length];
@@ -488,7 +488,7 @@ public final class Icon implements Parcelable {
}
switch (mType) {
case TYPE_BITMAP:
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
return getBitmap() == otherIcon.getBitmap();
case TYPE_DATA:
return getDataLength() == otherIcon.getDataLength()
@@ -566,11 +566,11 @@ public final class Icon implements Parcelable {
* by {@link AdaptiveIconDrawable}.
* @param bits A valid {@link android.graphics.Bitmap} object
*/
- public static Icon createWithMaskableBitmap(Bitmap bits) {
+ public static Icon createWithAdaptiveBitmap(Bitmap bits) {
if (bits == null) {
throw new IllegalArgumentException("Bitmap must not be null.");
}
- final Icon rep = new Icon(TYPE_BITMAP_MASKABLE);
+ final Icon rep = new Icon(TYPE_ADAPTIVE_BITMAP);
rep.setBitmap(bits);
return rep;
}
@@ -679,7 +679,7 @@ public final class Icon implements Parcelable {
final StringBuilder sb = new StringBuilder("Icon(typ=").append(typeToString(mType));
switch (mType) {
case TYPE_BITMAP:
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
sb.append(" size=")
.append(getBitmap().getWidth())
.append("x")
@@ -718,7 +718,7 @@ public final class Icon implements Parcelable {
* Parcelable interface
*/
public int describeContents() {
- return (mType == TYPE_BITMAP || mType == TYPE_BITMAP_MASKABLE || mType == TYPE_DATA)
+ return (mType == TYPE_BITMAP || mType == TYPE_ADAPTIVE_BITMAP || mType == TYPE_DATA)
? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
}
@@ -728,7 +728,7 @@ public final class Icon implements Parcelable {
this(in.readInt());
switch (mType) {
case TYPE_BITMAP:
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
final Bitmap bits = Bitmap.CREATOR.createFromParcel(in);
mObj1 = bits;
break;
@@ -767,7 +767,7 @@ public final class Icon implements Parcelable {
dest.writeInt(mType);
switch (mType) {
case TYPE_BITMAP:
- case TYPE_BITMAP_MASKABLE:
+ case TYPE_ADAPTIVE_BITMAP:
final Bitmap bits = getBitmap();
getBitmap().writeToParcel(dest, flags);
break;
diff --git a/graphics/tests/graphicstests/Android.mk b/graphics/tests/graphicstests/Android.mk
deleted file mode 100644
index 8ea44bdb7966..000000000000
--- a/graphics/tests/graphicstests/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
-LOCAL_PACKAGE_NAME := FrameworksGraphicsTests
-
-include $(BUILD_PACKAGE)
-
diff --git a/graphics/tests/graphicstests/AndroidManifest.xml b/graphics/tests/graphicstests/AndroidManifest.xml
deleted file mode 100644
index e019e2806a94..000000000000
--- a/graphics/tests/graphicstests/AndroidManifest.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.graphicstests">
- <uses-permission android:name="android.permission.RECEIVE_SMS"/>
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- <uses-permission android:name="android.permission.WRITE_CONTACTS" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
- <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
- <uses-permission android:name="android.permission.BROADCAST_STICKY" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.frameworks.graphicstests"
- android:label="Frameworks Graphics Tests" />
-</manifest>
diff --git a/graphics/tests/graphicstests/res/values/colors.xml b/graphics/tests/graphicstests/res/values/colors.xml
deleted file mode 100644
index 7559e6580793..000000000000
--- a/graphics/tests/graphicstests/res/values/colors.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2006, 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>
- <color name="testcolor1">#ff00ff00</color>
- <color name="testcolor2">#ffff0000</color>
- <color name="failColor">#ff0000ff</color>
-</resources>
-
diff --git a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
deleted file mode 100644
index 318bfb6bfd39..000000000000
--- a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import android.test.AndroidTestCase;
-
-public class PaintTest extends AndroidTestCase {
- public void testGetTextRunAdvances() {
- {
- // LTR
- String text = "abcdef";
- assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), false, true);
- assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), false, false);
- }
- {
- // RTL
- final String text =
- "\u0645\u0627\u0020\u0647\u064A\u0020\u0627\u0644\u0634" +
- "\u0641\u0631\u0629\u0020\u0627\u0644\u0645\u0648\u062D" +
- "\u062F\u0629\u0020\u064A\u0648\u0646\u064A\u0643\u0648" +
- "\u062F\u061F";
- assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), true, true);
- assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), true, false);
- }
- }
-
- private void assertGetTextRunAdvances(String str, int start, int end,
- int contextStart, int contextEnd, boolean isRtl, boolean compareWithOtherMethods) {
- Paint p = new Paint();
-
- final int count = end - start;
- final float[][] advanceArrays = new float[4][count];
-
- final float advance = p.getTextRunAdvances(str, start, end, contextStart, contextEnd,
- isRtl, advanceArrays[0], 0);
-
- char chars[] = str.toCharArray();
- final float advance_c = p.getTextRunAdvances(chars, start, count, contextStart,
- contextEnd - contextStart, isRtl, advanceArrays[1], 0);
- assertEquals(advance, advance_c, 1.0f);
-
- for (int c = 1; c < count; ++c) {
- final float firstPartAdvance = p.getTextRunAdvances(str, start, start + c,
- contextStart, contextEnd, isRtl, advanceArrays[2], 0);
- final float secondPartAdvance = p.getTextRunAdvances(str, start + c, end,
- contextStart, contextEnd, isRtl, advanceArrays[2], c);
- assertEquals(advance, firstPartAdvance + secondPartAdvance, 1.0f);
-
-
- final float firstPartAdvance_c = p.getTextRunAdvances(chars, start, c,
- contextStart, contextEnd - contextStart, isRtl, advanceArrays[3], 0);
- final float secondPartAdvance_c = p.getTextRunAdvances(chars, start + c,
- count - c, contextStart, contextEnd - contextStart, isRtl,
- advanceArrays[3], c);
- assertEquals(advance, firstPartAdvance_c + secondPartAdvance_c, 1.0f);
- assertEquals(firstPartAdvance, firstPartAdvance_c, 1.0f);
- assertEquals(secondPartAdvance, secondPartAdvance_c, 1.0f);
-
- for (int i = 1; i < advanceArrays.length; i++) {
- for (int j = 0; j < count; j++) {
- assertEquals(advanceArrays[0][j], advanceArrays[i][j], 1.0f);
- }
- }
-
- // Compare results with measureText, getRunAdvance, and getTextWidths.
- if (compareWithOtherMethods && start == contextStart && end == contextEnd) {
- assertEquals(advance, p.measureText(str, start, end), 1.0f);
- assertEquals(advance, p.getRunAdvance(
- str, start, end, contextStart, contextEnd, isRtl, end), 1.0f);
-
- final float[] widths = new float[count];
- p.getTextWidths(str, start, end, widths);
- for (int i = 0; i < count; i++) {
- assertEquals(advanceArrays[0][i], widths[i], 1.0f);
- }
- }
- }
- }
-
- public void testGetTextRunAdvances_invalid() {
- Paint p = new Paint();
- String text = "test";
-
- try {
- p.getTextRunAdvances((String)null, 0, 0, 0, 0, false, null, 0);
- fail("Should throw an IllegalArgumentException.");
- } catch (IllegalArgumentException e) {
- }
-
- try {
- p.getTextRunAdvances((CharSequence)null, 0, 0, 0, 0, false, null, 0);
- fail("Should throw an IllegalArgumentException.");
- } catch (IllegalArgumentException e) {
- }
-
- try {
- p.getTextRunAdvances((char[])null, 0, 0, 0, 0, false, null, 0);
- fail("Should throw an IllegalArgumentException.");
- } catch (IllegalArgumentException e) {
- }
-
- try {
- p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
- new float[text.length() - 1], 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- try {
- p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
- new float[text.length()], 1);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- // 0 > contextStart
- try {
- p.getTextRunAdvances(text, 0, text.length(), -1, text.length(), false, null, 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- // contextStart > start
- try {
- p.getTextRunAdvances(text, 0, text.length(), 1, text.length(), false, null, 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- // start > end
- try {
- p.getTextRunAdvances(text, 1, 0, 0, text.length(), false, null, 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- // end > contextEnd
- try {
- p.getTextRunAdvances(text, 0, text.length(), 0, text.length() - 1, false, null, 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
-
- // contextEnd > text.length
- try {
- p.getTextRunAdvances(text, 0, text.length(), 0, text.length() + 1, false, null, 0);
- fail("Should throw an IndexOutOfBoundsException.");
- } catch (IndexOutOfBoundsException e) {
- }
- }
-
- public void testMeasureTextBidi() {
- Paint p = new Paint();
- {
- String bidiText = "abc \u0644\u063A\u0629 def";
- p.setBidiFlags(Paint.BIDI_LTR);
- float width = p.measureText(bidiText, 0, 4);
- p.setBidiFlags(Paint.BIDI_RTL);
- width += p.measureText(bidiText, 4, 7);
- p.setBidiFlags(Paint.BIDI_LTR);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- {
- String bidiText = "abc \u0644\u063A\u0629 def";
- p.setBidiFlags(Paint.BIDI_DEFAULT_LTR);
- float width = p.measureText(bidiText, 0, 4);
- width += p.measureText(bidiText, 4, 7);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- {
- String bidiText = "abc \u0644\u063A\u0629 def";
- p.setBidiFlags(Paint.BIDI_FORCE_LTR);
- float width = p.measureText(bidiText, 0, 4);
- width += p.measureText(bidiText, 4, 7);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- {
- String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
- p.setBidiFlags(Paint.BIDI_RTL);
- float width = p.measureText(bidiText, 0, 4);
- p.setBidiFlags(Paint.BIDI_LTR);
- width += p.measureText(bidiText, 4, 7);
- p.setBidiFlags(Paint.BIDI_RTL);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- {
- String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
- p.setBidiFlags(Paint.BIDI_DEFAULT_RTL);
- float width = p.measureText(bidiText, 0, 4);
- width += p.measureText(bidiText, 4, 7);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- {
- String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
- p.setBidiFlags(Paint.BIDI_FORCE_RTL);
- float width = p.measureText(bidiText, 0, 4);
- width += p.measureText(bidiText, 4, 7);
- width += p.measureText(bidiText, 7, bidiText.length());
- assertEquals(width, p.measureText(bidiText), 1.0f);
- }
- }
-
- public void testSetGetWordSpacing() {
- Paint p = new Paint();
- assertEquals(0.0f, p.getWordSpacing()); // The default value should be 0.
- p.setWordSpacing(1.0f);
- assertEquals(1.0f, p.getWordSpacing());
- p.setWordSpacing(-2.0f);
- assertEquals(-2.0f, p.getWordSpacing());
- }
-}
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index deea9726403f..b68543146a51 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -15,7 +15,7 @@
*/
package android.security;
-import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
/**
* Caller is required to ensure that {@link KeyStore#unlock
@@ -39,8 +39,8 @@ interface IKeyChainService {
// APIs used by Settings
boolean deleteCaCertificate(String alias);
boolean reset();
- ParceledListSlice getUserCaAliases();
- ParceledListSlice getSystemCaAliases();
+ StringParceledListSlice getUserCaAliases();
+ StringParceledListSlice getSystemCaAliases();
boolean containsCaAlias(String alias);
byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem);
List<String> getCaCertificateChainAliases(String rootAlias, boolean includeDeletedSystem);
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index bf7a779ace08..d6b1cf1da8a2 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -45,7 +45,6 @@ public abstract class KeyProperties {
PURPOSE_DECRYPT,
PURPOSE_SIGN,
PURPOSE_VERIFY,
- PURPOSE_WRAP_KEY,
})
public @interface PurposeEnum {}
@@ -70,12 +69,6 @@ public abstract class KeyProperties {
public static final int PURPOSE_VERIFY = 1 << 3;
/**
- * Purpose of key: wrapping key for secure key import.
- */
- public static final int PURPOSE_WRAP_KEY = 1 << 4;
-
-
- /**
* @hide
*/
public static abstract class Purpose {
@@ -91,8 +84,6 @@ public abstract class KeyProperties {
return KeymasterDefs.KM_PURPOSE_SIGN;
case PURPOSE_VERIFY:
return KeymasterDefs.KM_PURPOSE_VERIFY;
- case PURPOSE_WRAP_KEY:
- return KeymasterDefs.KM_PURPOSE_WRAP_KEY;
default:
throw new IllegalArgumentException("Unknown purpose: " + purpose);
}
@@ -108,8 +99,6 @@ public abstract class KeyProperties {
return PURPOSE_SIGN;
case KeymasterDefs.KM_PURPOSE_VERIFY:
return PURPOSE_VERIFY;
- case KeymasterDefs.KM_PURPOSE_WRAP_KEY:
- return PURPOSE_WRAP_KEY;
default:
throw new IllegalArgumentException("Unknown purpose: " + purpose);
}
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index c6fbe2bd55de..e39614b6a5ea 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -91,8 +91,6 @@ public:
LayerUpdateQueue* layerUpdateQueue = nullptr;
ErrorHandler* errorHandler = nullptr;
- int32_t windowInsetLeft = 0;
- int32_t windowInsetTop = 0;
bool updateWindowPositions = false;
struct Out {
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 19a2f615d823..6e15d8da0033 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -70,9 +70,79 @@ public final class TvContract {
private static final String PATH_PROGRAM = "program";
private static final String PATH_RECORDED_PROGRAM = "recorded_program";
private static final String PATH_PREVIEW_PROGRAM = "preview_program";
+ private static final String PATH_WATCH_NEXT_PROGRAM = "watch_next_program";
private static final String PATH_PASSTHROUGH = "passthrough";
/**
+ * Activity Action: sent by an application telling the system to set the given channel as
+ * browsable. This is only relevant to channels with {@link Channels#TYPE_PREVIEW} type.
+ *
+ * <p>The intent must contain the following bundle parameters:
+ * <ul>
+ * <li>{@link #EXTRA_CHANNEL_ID}: ID for the {@link Channels#TYPE_PREVIEW} channel as a long
+ * integer.</li>
+ * <li>{@link #EXTRA_PACKAGE_NAME}: the package name of the requesting application.</li>
+ * </ul>
+ */
+ public static final String ACTION_MAKE_CHANNEL_BROWSABLE =
+ "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+
+ /**
+ * Broadcast Action: sent by the system to tell the target TV input that one of its preview
+ * program's browsable state is disabled, i.e., it will no longer be shown to users, which, for
+ * example, might be a result of users' interaction with UI. The input is expected to delete the
+ * preview program from the content provider.
+ *
+ * <p>The intent must contain the following bundle parameter:
+ * <ul>
+ * <li>{@link #EXTRA_PREVIEW_PROGRAM_ID}: the disabled preview program ID.</li>
+ * </ul>
+ */
+ public static final String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED =
+ "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+
+ /**
+ * Broadcast Action: sent by the system to tell the target TV input that one of its "watch next"
+ * program's browsable state is disabled, i.e., it will no longer be shown to users, which, for
+ * example, might be a result of users' interaction with UI. The input is expected to delete the
+ * "watch next" program from the content provider.
+ *
+ * <p>The intent must contain the following bundle parameter:
+ * <ul>
+ * <li>{@link #EXTRA_WATCH_NEXT_PROGRAM_ID}: the disabled "watch next" program ID.</li>
+ * </ul>
+ */
+ public static final String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED =
+ "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
+
+ /**
+ * Broadcast Action: sent by the system to tell the target TV input that one of its existing
+ * preview programs is added to the watch next programs table by user.
+ *
+ * <p>The intent must contain the following bundle parameters:
+ * <ul>
+ * <li>{@link #EXTRA_PREVIEW_PROGRAM_ID}: the ID of the existing preview program.</li>
+ * <li>{@link #EXTRA_WATCH_NEXT_PROGRAM_ID}: the ID of the new watch next program.</li>
+ * </ul>
+ */
+ public static final String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT =
+ "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+
+ /** The key for a bundle parameter containing a channel ID as a long integer */
+ public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+
+ /** The key for a bundle parameter containing a package name as a string. */
+ public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+
+ /** The key for a bundle parameter containing a program ID as a long integer. */
+ public static final String EXTRA_PREVIEW_PROGRAM_ID =
+ "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+
+ /** The key for a bundle parameter containing a watch next program ID as a long integer. */
+ public static final String EXTRA_WATCH_NEXT_PROGRAM_ID =
+ "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+
+ /**
* The method name to get existing columns in the given table of the specified content provider.
*
* <p>The method caller must provide the following parameter:
@@ -421,6 +491,15 @@ public final class TvContract {
}
/**
+ * Builds a URI that points to a specific watch next program.
+ *
+ * @param watchNextProgramId The ID of the watch next program to point to.
+ */
+ public static final Uri buildWatchNextProgramUri(long watchNextProgramId) {
+ return ContentUris.withAppendedId(WatchNextPrograms.CONTENT_URI, watchNextProgramId);
+ }
+
+ /**
* Builds a URI that points to a specific program the user watched.
*
* @param watchedProgramId The ID of the watched program to point to.
@@ -492,17 +571,6 @@ public final class TvContract {
*/
public interface BaseProgramColumns extends BaseTvColumns {
/**
- * The ID of the TV channel that provides this TV program.
- *
- * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
- *
- * <p>This is a required field.
- *
- * <p>Type: INTEGER (long)
- */
- public static final String COLUMN_CHANNEL_ID = "channel_id";
-
- /**
* The title of this TV program.
*
* <p>If this program is an episodic TV show, it is recommended that the title is the series
@@ -766,6 +834,591 @@ public final class TvContract {
public static final String COLUMN_VERSION_NUMBER = "version_number";
}
+ /**
+ * Common base for the tables of preview programs.
+ */
+ public interface BasePreviewProgramColumns extends BaseProgramColumns {
+
+ /** @hide */
+ @StringDef({
+ TYPE_MOVIE,
+ TYPE_TV_SERIES,
+ TYPE_TV_SEASON,
+ TYPE_TV_EPISODE,
+ TYPE_CLIP,
+ TYPE_EVENT,
+ TYPE_CHANNEL,
+ TYPE_TRACK,
+ TYPE_ALBUM,
+ TYPE_ARTIST,
+ TYPE_PLAYLIST,
+ TYPE_STATION,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ /**
+ * The program type for movie.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_MOVIE = "TYPE_MOVIE";
+
+ /**
+ * The program type for TV series.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+
+ /**
+ * The program type for TV season.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+
+ /**
+ * The program type for TV episode.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+
+ /**
+ * The program type for clip.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_CLIP = "TYPE_CLIP";
+
+ /**
+ * The program type for event.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_EVENT = "TYPE_EVENT";
+
+ /**
+ * The program type for channel.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_CHANNEL = "TYPE_CHANNEL";
+
+ /**
+ * The program type for track.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TRACK = "TYPE_TRACK";
+
+ /**
+ * The program type for album.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_ALBUM = "TYPE_ALBUM";
+
+ /**
+ * The program type for artist.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_ARTIST = "TYPE_ARTIST";
+
+ /**
+ * The program type for playlist.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+
+ /**
+ * The program type for station.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_STATION = "TYPE_STATION";
+
+ /** @hide */
+ @StringDef({
+ ASPECT_RATIO_16_9,
+ ASPECT_RATIO_3_2,
+ ASPECT_RATIO_1_1,
+ ASPECT_RATIO_2_3,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AspectRatio {}
+
+ /**
+ * The aspect ratio for 16:9.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+
+ /**
+ * The aspect ratio for 3:2.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+
+ /**
+ * The aspect ratio for 1:1.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+
+ /**
+ * The aspect ratio for 2:3.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+
+ /** @hide */
+ @StringDef({
+ AVAILABILITY_AVAILABLE,
+ AVAILABILITY_FREE_WITH_SUBSCRIPTION,
+ AVAILABILITY_PAID_CONTENT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Availability {}
+
+ /**
+ * The availability for "available to this user".
+ *
+ * @see #COLUMN_AVAILABILITY
+ */
+ public static final String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+
+ /**
+ * The availability for "free with subscription".
+ *
+ * @see #COLUMN_AVAILABILITY
+ */
+ public static final String AVAILABILITY_FREE_WITH_SUBSCRIPTION =
+ "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+
+ /**
+ * The availability for "paid content, either to-own or rental
+ * (user has not purchased/rented).
+ *
+ * @see #COLUMN_AVAILABILITY
+ */
+ public static final String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+
+ /** @hide */
+ @StringDef({
+ INTERACTION_TYPE_LISTENS,
+ INTERACTION_TYPE_FOLLOWERS,
+ INTERACTION_TYPE_FANS,
+ INTERACTION_TYPE_LIKES,
+ INTERACTION_TYPE_THUMBS,
+ INTERACTION_TYPE_VIEWS,
+ INTERACTION_TYPE_VIEWERS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InteractionType {}
+
+ /**
+ * The interaction type for "listens".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+
+ /**
+ * The interaction type for "followers".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+
+ /**
+ * The interaction type for "fans".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+
+ /**
+ * The interaction type for "likes".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+
+ /**
+ * The interaction type for "thumbs".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+
+ /**
+ * The interaction type for "views".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+
+ /**
+ * The interaction type for "viewers".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+
+ /** @hide */
+ @StringDef({
+ REVIEW_RATING_STYLE_STARS,
+ REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
+ REVIEW_RATING_STYLE_PERCENTAGE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ReviewRatingStyle {}
+
+ /**
+ * The review rating style for five star rating.
+ *
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+
+ /**
+ * The review rating style for thumbs-up and thumbs-down rating.
+ *
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String REVIEW_RATING_STYLE_THUMBS_UP_DOWN =
+ "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+
+ /**
+ * The review rating style for 0 to 100 point system.
+ *
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String REVIEW_RATING_STYLE_PERCENTAGE =
+ "REVIEW_RATING_STYLE_PERCENTAGE";
+
+ /**
+ * The type of this program content.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #TYPE_MOVIE},
+ * {@link #TYPE_TV_SERIES},
+ * {@link #TYPE_TV_SEASON},
+ * {@link #TYPE_TV_EPISODE},
+ * {@link #TYPE_CLIP},
+ * {@link #TYPE_EVENT},
+ * {@link #TYPE_CHANNEL},
+ * {@link #TYPE_TRACK},
+ * {@link #TYPE_ALBUM},
+ * {@link #TYPE_ARTIST},
+ * {@link #TYPE_PLAYLIST}, and
+ * {@link #TYPE_STATION}.
+ *
+ * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW}
+ * channel.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_TYPE = "type";
+
+ /**
+ * The aspect ratio of the poster art for this TV program.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #ASPECT_RATIO_16_9},
+ * {@link #ASPECT_RATIO_3_2},
+ * {@link #ASPECT_RATIO_1_1}, and
+ * {@link #ASPECT_RATIO_2_3}.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+
+ /**
+ * The aspect ratio of the thumbnail for this TV program.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #ASPECT_RATIO_16_9},
+ * {@link #ASPECT_RATIO_3_2},
+ * {@link #ASPECT_RATIO_1_1}, and
+ * {@link #ASPECT_RATIO_2_3}.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+
+ /**
+ * The URI for the logo of this TV program.
+ *
+ * <p>This is a small badge shown on top of the poster art or thumbnail representing the
+ * source of the content.
+ *
+ * <p>The data in the column must be a URL, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_LOGO_URI = "logo_uri";
+
+ /**
+ * The availability of this TV program.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #AVAILABILITY_AVAILABLE},
+ * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
+ * {@link #AVAILABILITY_PAID_CONTENT}.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_AVAILABILITY = "availability";
+
+ /**
+ * The starting price of this TV program.
+ *
+ * <p>This indicates the lowest regular acquisition cost of the content. It is only used
+ * if the availability of the program is {@link #AVAILABILITY_PAID_CONTENT}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_OFFER_PRICE
+ */
+ public static final String COLUMN_STARTING_PRICE = "starting_price";
+
+ /**
+ * The offer price of this TV program.
+ *
+ * <p>This is the promotional cost of the content. It is only used if the availability of
+ * the program is {@link #AVAILABILITY_PAID_CONTENT}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_STARTING_PRICE
+ */
+ public static final String COLUMN_OFFER_PRICE = "offer_price";
+
+ /**
+ * The release date of this TV program.
+ *
+ * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_RELEASE_DATE = "release_date";
+
+ /**
+ * The count of the items included in this TV program.
+ *
+ * <p>This is only relevant if the program represents a collection of items such as series,
+ * episodes, or music tracks.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_ITEM_COUNT = "item_count";
+
+ /**
+ * The flag indicating whether this TV program is live or not.
+ *
+ * <p>A value of 1 indicates that the content is airing and should be consumed now, a value
+ * of 0 indicates that the content is off the air and does not need to be consumed at the
+ * present time. If not specified, the value is set to 0 (not live) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ public static final String COLUMN_LIVE = "live";
+
+ /**
+ * The internal ID used by individual TV input services.
+ *
+ * <p>This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+
+ /**
+ * The URI for the preview video.
+ *
+ * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}. The data in the column must be
+ * a URL, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+
+ /**
+ * The last playback position (in milliseconds) of the preview video.
+ *
+ * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS =
+ "last_playback_position_millis";
+
+ /**
+ * The duration (in milliseconds) of the preview video.
+ *
+ * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_DURATION_MILLIS = "duration_millis";
+
+ /**
+ * The intent URI which is launched when the preview video is selected.
+ *
+ * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
+ * and converted back to the original intent with {@link Intent#parseUri}. The intent is
+ * launched when the user selects the preview video item.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_APP_LINK_INTENT_URI =
+ "app_link_intent_uri";
+
+ /**
+ * The flag indicating whether this program is transient or not.
+ *
+ * <p>A value of 1 indicates that the channel will be automatically removed by the system on
+ * reboot, and a value of 0 indicates that the channel is persistent across reboot. If not
+ * specified, this value is set to 0 (not transient) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ * @see Channels#COLUMN_TRANSIENT
+ * @hide
+ */
+ @SystemApi
+ public static final String COLUMN_TRANSIENT = "transient";
+
+ /**
+ * The type of interaction for this TV program.
+ *
+ * <p> The value should match one of the followings:
+ * {@link #INTERACTION_TYPE_LISTENS},
+ * {@link #INTERACTION_TYPE_FOLLOWERS},
+ * {@link #INTERACTION_TYPE_FANS},
+ * {@link #INTERACTION_TYPE_LIKES},
+ * {@link #INTERACTION_TYPE_THUMBS},
+ * {@link #INTERACTION_TYPE_VIEWS}, and
+ * {@link #INTERACTION_TYPE_VIEWERS}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_INTERACTION_COUNT
+ */
+ public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
+
+ /**
+ * The interaction count for this program.
+ *
+ * <p>This indicates the number of times interaction has happened.
+ *
+ * <p>Type: INTEGER (long)
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
+
+ /**
+ * The author or artist of this content.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_AUTHOR = "author";
+
+ /**
+ * The review rating score style used for {@link #COLUMN_REVIEW_RATING}.
+ *
+ * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS},
+ * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_REVIEW_RATING
+ */
+ public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+
+ /**
+ * The review rating score for this program.
+ *
+ * <p>The format of the value is dependent on {@link #COLUMN_REVIEW_RATING_STYLE}. If the
+ * style is {@link #REVIEW_RATING_STYLE_STARS}, the value should be a real number between
+ * 0.0 and 5.0. (e.g. "4.5") If the style is {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN},
+ * the value should be two integers, one for thumbs-up count and the other for thumbs-down
+ * count, with a comma between them. (e.g. "200,40") If the style is
+ * {@link #REVIEW_RATING_STYLE_PERCENTAGE}, the value shoule be a real number between 0 and
+ * 100. (e.g. "99.9")
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String COLUMN_REVIEW_RATING = "review_rating";
+
+ /**
+ * The flag indicating whether this TV program is browsable or not.
+ *
+ * <p>This column can only be set by applications having proper system permission. For
+ * other applications, this is a read-only column.
+ *
+ * <p>A value of 1 indicates that the program is browsable and can be shown to users in
+ * the UI. A value of 0 indicates that the program should be hidden from users and the
+ * application who changes this value to 0 should send
+ * {@link #ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED} to the owner of the program
+ * to notify this change.
+ *
+ * <p>This value is set to 1 (browsable) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ public static final String COLUMN_BROWSABLE = "browsable";
+
+ /**
+ * The content ID of this TV program.
+ *
+ * <p>A public ID of the content which allows the application to apply the same operation to
+ * all the program copies in different channels.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_CONTENT_ID = "content_id";
+
+ }
+
/** Column definitions for the TV channels table. */
public static final class Channels implements BaseTvColumns {
@@ -1588,6 +2241,17 @@ public final class TvContract {
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
/**
+ * The ID of the TV channel that provides this TV program.
+ *
+ * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
+
+ /**
* The season number of this TV program for episodic TV shows.
*
* <p>Can be empty.
@@ -1891,6 +2555,17 @@ public final class TvContract {
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
/**
+ * The ID of the TV channel that provides this recorded program.
+ *
+ * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
+
+ /**
* The ID of the TV input service that is associated with this recorded program.
*
* <p>Use {@link #buildInputId} to build the ID.
@@ -1989,7 +2664,7 @@ public final class TvContract {
/**
* Column definitions for the preview TV programs table.
*/
- public static final class PreviewPrograms implements BaseProgramColumns {
+ public static final class PreviewPrograms implements BasePreviewProgramColumns {
/** The content:// style URI for this table. */
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -2001,631 +2676,132 @@ public final class TvContract {
/** The MIME type of a single preview TV program. */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
- /** @hide */
- @StringDef({
- TYPE_MOVIE,
- TYPE_TV_SERIES,
- TYPE_TV_SEASON,
- TYPE_TV_EPISODE,
- TYPE_CLIP,
- TYPE_EVENT,
- TYPE_CHANNEL,
- TYPE_TRACK,
- TYPE_ALBUM,
- TYPE_ARTIST,
- TYPE_PLAYLIST,
- TYPE_STATION,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
- /**
- * The program type for movie.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_MOVIE = "TYPE_MOVIE";
-
/**
- * The program type for TV series.
+ * The ID of the TV channel that provides this TV program.
*
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_TV_SERIES = "TYPE_TV_SERIES";
-
- /**
- * The program type for TV season.
+ * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
*
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_TV_SEASON = "TYPE_TV_SEASON";
-
- /**
- * The program type for TV episode.
+ * <p>This is a required field.
*
- * @see #COLUMN_TYPE
+ * <p>Type: INTEGER (long)
*/
- public static final String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
/**
- * The program type for clip.
+ * The weight of the preview program within the channel.
*
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_CLIP = "TYPE_CLIP";
-
- /**
- * The program type for event.
+ * <p>The UI may choose to show this item in a different position in the channel row.
+ * A larger weight value means the program is more important than other programs having
+ * smaller weight values. The value is relevant for the preview programs in the same
+ * channel. This is only relevant to {@link Channels#TYPE_PREVIEW}.
*
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_EVENT = "TYPE_EVENT";
-
- /**
- * The program type for channel.
+ * <p>Can be empty.
*
- * @see #COLUMN_TYPE
+ * <p>Type: INTEGER
*/
- public static final String TYPE_CHANNEL = "TYPE_CHANNEL";
+ public static final String COLUMN_WEIGHT = "weight";
- /**
- * The program type for track.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_TRACK = "TYPE_TRACK";
+ private PreviewPrograms() {}
+ }
- /**
- * The program type for album.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_ALBUM = "TYPE_ALBUM";
+ /**
+ * Column definitions for the "watch next" TV programs table.
+ */
+ public static final class WatchNextPrograms implements BasePreviewProgramColumns {
- /**
- * The program type for artist.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_ARTIST = "TYPE_ARTIST";
+ /** The content:// style URI for this table. */
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
+ + PATH_WATCH_NEXT_PROGRAM);
- /**
- * The program type for playlist.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ /** The MIME type of a directory of "watch next" TV programs. */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
- /**
- * The program type for station.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_STATION = "TYPE_STATION";
+ /** The MIME type of a single preview TV program. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
/** @hide */
@StringDef({
WATCH_NEXT_TYPE_CONTINUE,
WATCH_NEXT_TYPE_NEXT,
WATCH_NEXT_TYPE_NEW,
+ WATCH_NEXT_TYPE_WATCHLIST,
})
@Retention(RetentionPolicy.SOURCE)
public @interface WatchNextType {}
/**
- * The watch next type for CONTINUE.
+ * The watch next type for CONTINUE. Use this type when the user has already watched more
+ * than 1 minute of this content.
*
* @see #COLUMN_WATCH_NEXT_TYPE
*/
public static final String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
/**
- * The watch next type for NEXT.
+ * The watch next type for NEXT. Use this type when the user has watched one or more
+ * complete episodes from some episodic content, but there remains more than one episode
+ * remaining or there is one last episode remaining, but it is not “new” in that it was
+ * released before the user started watching the show.
*
* @see #COLUMN_WATCH_NEXT_TYPE
*/
public static final String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
/**
- * The watch next type for NEW.
+ * The watch next type for NEW. Use this type when the user had watched all of the available
+ * episodes from some episodic content, but a new episode became available since the user
+ * started watching the first episode and now there is exactly one unwatched episode. This
+ * could also work for recorded events in a series e.g. soccer matches or football games.
*
* @see #COLUMN_WATCH_NEXT_TYPE
*/
public static final String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- /** @hide */
- @StringDef({
- ASPECT_RATIO_16_9,
- ASPECT_RATIO_3_2,
- ASPECT_RATIO_1_1,
- ASPECT_RATIO_2_3,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AspectRatio {}
-
/**
- * The aspect ratio for 16:9.
+ * The watch next type for WATCHLIST. Use this type when the user has elected to explicitly
+ * add a movie, event or series to a “watchlist” as a manual way of curating what they
+ * want to watch next.
*
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
-
- /**
- * The aspect ratio for 3:2.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
-
- /**
- * The aspect ratio for 1:1.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
-
- /**
- * The aspect ratio for 2:3.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
-
- /** @hide */
- @StringDef({
- AVAILABILITY_AVAILABLE,
- AVAILABILITY_FREE_WITH_SUBSCRIPTION,
- AVAILABILITY_PAID_CONTENT,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Availability {}
-
- /**
- * The availability for "available to this user".
- *
- * @see #COLUMN_AVAILABILITY
- */
- public static final String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
-
- /**
- * The availability for "free with subscription".
- *
- * @see #COLUMN_AVAILABILITY
- */
- public static final String AVAILABILITY_FREE_WITH_SUBSCRIPTION =
- "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
-
- /**
- * The availability for "paid content, either to-own or rental
- * (user has not purchased/rented).
- *
- * @see #COLUMN_AVAILABILITY
- */
- public static final String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
-
- /** @hide */
- @StringDef({
- INTERACTION_TYPE_LISTENS,
- INTERACTION_TYPE_FOLLOWERS,
- INTERACTION_TYPE_FANS,
- INTERACTION_TYPE_LIKES,
- INTERACTION_TYPE_THUMBS,
- INTERACTION_TYPE_VIEWS,
- INTERACTION_TYPE_VIEWERS,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface InteractionType {}
-
- /**
- * The interaction type for "listens".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
-
- /**
- * The interaction type for "followers".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
-
- /**
- * The interaction type for "fans".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
-
- /**
- * The interaction type for "likes".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
-
- /**
- * The interaction type for "thumbs".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
-
- /**
- * The interaction type for "views".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
-
- /**
- * The interaction type for "viewers".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
-
- /** @hide */
- @StringDef({
- REVIEW_RATING_STYLE_STARS,
- REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
- REVIEW_RATING_STYLE_PERCENTAGE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ReviewRatingStyle {}
-
- /**
- * The review rating style for five star rating.
- *
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
-
- /**
- * The review rating style for thumbs-up and thumbs-down rating.
- *
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String REVIEW_RATING_STYLE_THUMBS_UP_DOWN =
- "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
-
- /**
- * The review rating style for 0 to 100 point system.
- *
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String REVIEW_RATING_STYLE_PERCENTAGE =
- "REVIEW_RATING_STYLE_PERCENTAGE";
-
- /**
- * The type of this program content.
- *
- * <p>The value should match one of the followings:
- * {@link #TYPE_MOVIE},
- * {@link #TYPE_TV_SERIES},
- * {@link #TYPE_TV_SEASON},
- * {@link #TYPE_TV_EPISODE},
- * {@link #TYPE_CLIP},
- * {@link #TYPE_EVENT},
- * {@link #TYPE_CHANNEL},
- * {@link #TYPE_TRACK},
- * {@link #TYPE_ALBUM},
- * {@link #TYPE_ARTIST},
- * {@link #TYPE_PLAYLIST}, and
- * {@link #TYPE_STATION}.
- *
- * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW}
- * channel.
- *
- * <p>Type: TEXT
+ * @see #COLUMN_WATCH_NEXT_TYPE
*/
- public static final String COLUMN_TYPE = "type";
+ public static final String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
/**
* The "watch next" type of this program content.
*
* <p>The value should match one of the followings:
* {@link #WATCH_NEXT_TYPE_CONTINUE},
- * {@link #WATCH_NEXT_TYPE_NEXT}, and
- * {@link #WATCH_NEXT_TYPE_NEW}.
+ * {@link #WATCH_NEXT_TYPE_NEXT},
+ * {@link #WATCH_NEXT_TYPE_NEW}, and
+ * {@link #WATCH_NEXT_TYPE_WATCHLIST}.
*
- * <p>Can be empty.
+ * <p>This is a required field.
*
* <p>Type: TEXT
*/
public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
/**
- * The aspect ratio of the poster art for this TV program.
- *
- * <p>The value should match one of the followings:
- * {@link #ASPECT_RATIO_16_9},
- * {@link #ASPECT_RATIO_3_2},
- * {@link #ASPECT_RATIO_1_1}, and
- * {@link #ASPECT_RATIO_2_3}.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-
- /**
- * The aspect ratio of the thumbnail for this TV program.
- *
- * <p>The value should match one of the followings:
- * {@link #ASPECT_RATIO_16_9},
- * {@link #ASPECT_RATIO_3_2},
- * {@link #ASPECT_RATIO_1_1}, and
- * {@link #ASPECT_RATIO_2_3}.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
-
- /**
- * The URI for the logo of this TV program.
- *
- * <p>This is a small badge shown on top of the poster art or thumbnail representing the
- * source of the content.
- *
- * <p>The data in the column must be a URL, or a URI in one of the following formats:
- *
- * <ul>
- * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
- * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
- * </li>
- * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
- * </ul>
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_LOGO_URI = "logo_uri";
-
- /**
- * The availability of this TV program.
- *
- * <p>The value should match one of the followings:
- * {@link #AVAILABILITY_AVAILABLE},
- * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
- * {@link #AVAILABILITY_PAID_CONTENT}.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_AVAILABILITY = "availability";
-
- /**
- * The starting price of this TV program.
- *
- * <p>This indicates the lowest regular acquisition cost of the content. It is only used
- * if the availability of the program is {@link #AVAILABILITY_PAID_CONTENT}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_OFFER_PRICE
- */
- public static final String COLUMN_STARTING_PRICE = "starting_price";
-
- /**
- * The offer price of this TV program.
- *
- * <p>This is the promotional cost of the content. It is only used if the availability of
- * the program is {@link #AVAILABILITY_PAID_CONTENT}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_STARTING_PRICE
- */
- public static final String COLUMN_OFFER_PRICE = "offer_price";
-
- /**
- * The release date of this TV program.
- *
- * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_RELEASE_DATE = "release_date";
-
- /**
- * The count of the items included in this TV program.
- *
- * <p>This is only relevant if the program represents a collection of items such as series,
- * episodes, or music tracks.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_ITEM_COUNT = "item_count";
-
- /**
- * The flag indicating whether this TV program is live or not.
- *
- * <p>A value of 1 indicates that the content is airing and should be consumed now, a value
- * of 0 indicates that the content is off the air and does not need to be consumed at the
- * present time. If not specified, the value is set to 0 (not live) by default.
- *
- * <p>Type: INTEGER (boolean)
- */
- public static final String COLUMN_LIVE = "live";
-
- /**
- * The internal ID used by individual TV input services.
- *
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
-
- /**
- * The URI for the preview video.
- *
- * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}. The data in the column must be
- * a URL, or a URI in one of the following formats:
+ * The last UTC time that the user engaged in this TV program, in milliseconds since the
+ * epoch. This is a hint for the application that is used for ordering of "watch next"
+ * programs.
*
+ * <p>The meaning of the value varies depending on the {@link #COLUMN_WATCH_NEXT_TYPE}:
* <ul>
- * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
- * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
- * </li>
- * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * <li>{@link #WATCH_NEXT_TYPE_CONTINUE}: the date that the user was last watching the
+ * content.</li>
+ * <li>{@link #WATCH_NEXT_TYPE_NEXT}: the date of the last episode watched.</li>
+ * <li>{@link #WATCH_NEXT_TYPE_NEW}: the release date of the new episode.</li>
+ * <li>{@link #WATCH_NEXT_TYPE_WATCHLIST}: the date the item was added to the Watchlist.
+ * </li>
* </ul>
*
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
-
- /**
- * The last playback position (in milliseconds) of the preview video.
- *
- * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
- *
- * <p>Can be empty.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS =
- "last_playback_position_millis";
-
- /**
- * The duration (in milliseconds) of the preview video.
- *
- * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
- *
- * <p>Can be empty.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_DURATION_MILLIS = "duration_millis";
-
- /**
- * The intent URI which is launched when the preview video is selected.
- *
- * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
- * and converted back to the original intent with {@link Intent#parseUri}. The intent is
- * launched when the user selects the preview video item.
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_APP_LINK_INTENT_URI =
- "app_link_intent_uri";
-
- /**
- * The weight of the preview program within the channel.
- *
- * <p>The UI may choose to show this item in a different position in the channel row.
- * A larger weight value means the program is more important than other programs having
- * smaller weight values. The value is relevant for the preview programs in the same
- * channel. This is only relevant to {@link Channels#TYPE_PREVIEW}.
- *
- * <p>Can be empty.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_WEIGHT = "weight";
-
- /**
- * The flag indicating whether this program is transient or not.
- *
- * <p>A value of 1 indicates that the channel will be automatically removed by the system on
- * reboot, and a value of 0 indicates that the channel is persistent across reboot. If not
- * specified, this value is set to 0 (not transient) by default.
- *
- * <p>Type: INTEGER (boolean)
- * @see Channels#COLUMN_TRANSIENT
- * @hide
- */
- @SystemApi
- public static final String COLUMN_TRANSIENT = "transient";
-
- /**
- * The type of interaction for this TV program.
- *
- * <p> The value should match one of the followings:
- * {@link #INTERACTION_TYPE_LISTENS},
- * {@link #INTERACTION_TYPE_FOLLOWERS},
- * {@link #INTERACTION_TYPE_FANS},
- * {@link #INTERACTION_TYPE_LIKES},
- * {@link #INTERACTION_TYPE_THUMBS},
- * {@link #INTERACTION_TYPE_VIEWS}, and
- * {@link #INTERACTION_TYPE_VIEWERS}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_INTERACTION_COUNT
- */
- public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
-
- /**
- * The interaction count for this program.
- *
- * <p>This indicates the number of times interaction has happened.
+ * <p>This is a required field.
*
* <p>Type: INTEGER (long)
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
-
- /**
- * The author or artist of this content.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_AUTHOR = "author";
-
- /**
- * The review rating score style used for {@link #COLUMN_REVIEW_RATING}.
- *
- * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS},
- * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_REVIEW_RATING
- */
- public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-
- /**
- * The review rating score for this program.
- *
- * <p>The format of the value is dependent on {@link #COLUMN_REVIEW_RATING_STYLE}. If the
- * style is {@link #REVIEW_RATING_STYLE_STARS}, the value should be a real number between
- * 0.0 and 5.0. (e.g. "4.5") If the style is {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN},
- * the value should be two integers, one for thumbs-up count and the other for thumbs-down
- * count, with a comma between them. (e.g. "200,40") If the style is
- * {@link #REVIEW_RATING_STYLE_PERCENTAGE}, the value shoule be a real number between 0 and
- * 100. (e.g. "99.9")
- *
- * <p>Type: TEXT
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String COLUMN_REVIEW_RATING = "review_rating";
-
- /**
- * The flag indicating whether this TV program is browsable or not.
- *
- * <p>This column can only be set by applications having proper system permission. For
- * other applications, this is a read-only column.
- *
- * <p>A value of 1 indicates that the program is browsable and can be shown to users in
- * the UI. A value of 0 indicates that the program should be hidden from users and the
- * application who changes this value to 0 should send
- * {@link TvInputManager#ACTION_PROGRAM_BROWSABLE_DISABLED} to the owner of the program
- * to notify this change.
- *
- * <p>This value is set to 1 (browsable) by default.
- *
- * <p>Type: INTEGER (boolean)
*/
- public static final String COLUMN_BROWSABLE = "browsable";
-
- private PreviewPrograms() {}
+ public static final String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS =
+ "last_engagement_time_utc_millis";
}
/**
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 4c2b031d8f04..1eae8db60833 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -324,40 +324,6 @@ public final class TvInputManager {
public static final String ACTION_VIEW_RECORDING_SCHEDULES =
"android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- /**
- * Action sent by the system to tell the target TV input that one of its program's browsable
- * state is disabled, i.e., it will no longer be shown to users, which, for example, might
- * be a result of users' interaction with UI.
- *
- * <p>The intent must contain the following bundle parameter:
- * <ul>
- * <li>{@link #EXTRA_PROGRAM_ID} the program ID as a long integer.
- * </ul>
- */
- public static final String ACTION_PROGRAM_BROWSABLE_DISABLED =
- "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
-
- /**
- * Action sent by an application telling the system to set the given channel as browsable.
- *
- * <p>The intent must contain the following bundle parameters:
- * <ul>
- * <li>{@link #EXTRA_CHANNEL_ID} the channel ID as a long integer.
- * <li>{@link #EXTRA_PACKAGE_NAME} the package name of the requesting application.
- * </ul>
- */
- public static final String ACTION_MAKE_CHANNEL_BROWSABLE
- = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
-
- /** The key for a bundle parameter containing a channel ID as a long integer */
- public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
-
- /** The key for a bundle parameter containing a package name as a string. */
- public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
-
- /** The key for a bundle parameter containing a program ID as a long integer */
- public static final String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
-
private final ITvInputManager mService;
private final Object mLock = new Object();
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index aee9d38e0a27..e5af35711311 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -776,8 +776,8 @@ public class TvView extends ViewGroup {
mSurface = null;
mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) {
@Override
- protected void updateWindow() {
- super.updateWindow();
+ protected void updateSurface() {
+ super.updateSurface();
relayoutSessionOverlayView();
}};
// The surface view's content should be treated as secure all the time.
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index e2623d4fd9ee..3ede2ee639bf 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -139,27 +139,16 @@ LIBANDROID {
ANativeActivity_setWindowFlags;
ANativeActivity_setWindowFormat;
ANativeActivity_showSoftInput;
- AHardwareBuffer_acquire; # introduced=26
- AHardwareBuffer_allocate; # introduced=26
- AHardwareBuffer_describe; # introduced=26
- AHardwareBuffer_fromHardwareBuffer; # introduced=26
- AHardwareBuffer_getNativeHandle; # introduced=26
- AHardwareBuffer_lock; # introduced=26
- AHardwareBuffer_recvHandleFromUnixSocket; # introduced=26
- AHardwareBuffer_release; # introduced=26
- AHardwareBuffer_sendHandleToUnixSocket; # introduced=26
- AHardwareBuffer_toHardwareBuffer; # introduced=26
- AHardwareBuffer_unlock; # introduced=26
- ANativeWindow_acquire;
- ANativeWindow_fromSurface;
- ANativeWindow_fromSurfaceTexture; # introduced-arm=13 introduced-mips=13 introduced-x86=13
- ANativeWindow_getFormat;
- ANativeWindow_getHeight;
- ANativeWindow_getWidth;
- ANativeWindow_lock;
- ANativeWindow_release;
- ANativeWindow_setBuffersGeometry;
- ANativeWindow_unlockAndPost;
+ ANativeWindow_acquire; # removed=26
+ ANativeWindow_fromSurface; # removed=26
+ ANativeWindow_fromSurfaceTexture; # removed=26
+ ANativeWindow_getFormat; # removed=26
+ ANativeWindow_getHeight; # removed=26
+ ANativeWindow_getWidth; # removed=26
+ ANativeWindow_lock; # removed=26
+ ANativeWindow_release; # removed=26
+ ANativeWindow_setBuffersGeometry; # removed=26
+ ANativeWindow_unlockAndPost; # removed=26
AObbInfo_delete;
AObbInfo_getFlags;
AObbInfo_getPackageName;
@@ -170,14 +159,20 @@ LIBANDROID {
ASensorEventQueue_getEvents;
ASensorEventQueue_hasEvents;
ASensorEventQueue_setEventRate;
+ ASensorManager_configureDirectReport; # introduced=26
ASensorManager_createEventQueue;
+ ASensorManager_createHardwareBufferDirectChannel; # introduced=26
+ ASensorManager_createSharedMemoryDirectChannel; # introduced=26
+ ASensorManager_destroyDirectChannel; # introduced=26
ASensorManager_destroyEventQueue;
ASensorManager_getDefaultSensor;
ASensorManager_getDefaultSensorEx; # introduced=21
ASensorManager_getInstance;
+ ASensorManager_getInstanceForPackage; # introduced=26
ASensorManager_getSensorList;
ASensor_getFifoMaxEventCount; # introduced=21
ASensor_getFifoReservedEventCount; # introduced=21
+ ASensor_getHighestDirectReportRateLevel; # introduced=26
ASensor_getMinDelay;
ASensor_getName;
ASensor_getReportingMode; # introduced=21
@@ -185,6 +180,7 @@ LIBANDROID {
ASensor_getStringType; # introduced=21
ASensor_getType;
ASensor_getVendor;
+ ASensor_isDirectChannelTypeSupported; # introduced=26
ASensor_isWakeUpSensor; # introduced=21
ASharedMemory_create; # introduced=26
ASharedMemory_getSize; # introduced=26
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 5cfe3004514c..c7bc885ea4b0 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -17,16 +17,17 @@
#define LOG_TAG "sensor"
#include <utils/Log.h>
+#include <android/hardware_buffer.h>
#include <android/looper.h>
#include <android/sensor.h>
-
-#include <utils/RefBase.h>
-#include <utils/Looper.h>
-#include <utils/Timers.h>
-
+#include <android/sharedmem.h>
+#include <cutils/native_handle.h>
#include <gui/Sensor.h>
#include <gui/SensorManager.h>
#include <gui/SensorEventQueue.h>
+#include <utils/Looper.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
#include <poll.h>
@@ -38,6 +39,22 @@ using android::String8;
using android::String16;
/*****************************************************************************/
+#define ERROR_INVALID_PARAMETER(message) ALOGE("%s: " message, __func__)
+
+// frequently used check
+#define RETURN_IF_MANAGER_IS_NULL(retval) do {\
+ if (manager == nullptr) { \
+ ERROR_INVALID_PARAMETER("manager cannot be NULL"); \
+ return retval; \
+ } \
+ } while (false)
+#define RETURN_IF_SENSOR_IS_NULL(retval) do {\
+ if (sensor == nullptr) { \
+ ERROR_INVALID_PARAMETER("sensor cannot be NULL"); \
+ return retval; \
+ } \
+ } while (false)
+
ASensorManager* ASensorManager_getInstance()
{
return ASensorManager_getInstanceForPackage(NULL);
@@ -103,6 +120,78 @@ int ASensorManager_destroyEventQueue(ASensorManager* manager,
return 0;
}
+int ASensorManager_createSharedMemoryDirectChannel(
+ ASensorManager *manager, int fd, size_t size) {
+ RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+
+ if (fd < 0) {
+ ERROR_INVALID_PARAMETER("fd is invalid.");
+ return android::BAD_VALUE;
+ }
+
+ if (size < sizeof(ASensorEvent)) {
+ ERROR_INVALID_PARAMETER("size has to be greater or equal to sizeof(ASensorEvent).");
+ }
+
+ native_handle_t *resourceHandle = native_handle_create(1 /* nFd */, 0 /* nInt */);
+ if (!resourceHandle) {
+ return android::NO_MEMORY;
+ }
+
+ resourceHandle->data[0] = fd;
+ int ret = static_cast<SensorManager *>(manager)->createDirectChannel(
+ size, ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, resourceHandle);
+ native_handle_delete(resourceHandle);
+ return ret;
+}
+
+int ASensorManager_createHardwareBufferDirectChannel(
+ ASensorManager *manager, AHardwareBuffer const *buffer, size_t size) {
+ RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+
+ if (buffer == nullptr) {
+ ERROR_INVALID_PARAMETER("buffer cannot be NULL");
+ return android::BAD_VALUE;
+ }
+
+ if (size < sizeof(ASensorEvent)) {
+ ERROR_INVALID_PARAMETER("size has to be greater or equal to sizeof(ASensorEvent).");
+ }
+
+ const native_handle_t *resourceHandle = AHardwareBuffer_getNativeHandle(buffer);
+ if (!resourceHandle) {
+ return android::NO_MEMORY;
+ }
+
+ return static_cast<SensorManager *>(manager)->createDirectChannel(
+ size, ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER, resourceHandle);
+}
+
+void ASensorManager_destroyDirectChannel(ASensorManager *manager, int channelId) {
+ RETURN_IF_MANAGER_IS_NULL(void());
+
+ static_cast<SensorManager *>(manager)->destroyDirectChannel(channelId);
+}
+
+int ASensorManager_configureDirectReport(
+ ASensorManager *manager, ASensor const *sensor, int channelId, int rate) {
+ RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+
+ int sensorHandle;
+ if (sensor == nullptr) {
+ if (rate != ASENSOR_DIRECT_RATE_STOP) {
+ ERROR_INVALID_PARAMETER(
+ "sensor cannot be null when rate is not ASENSOR_DIRECT_RATE_STOP");
+ return android::BAD_VALUE;
+ }
+ sensorHandle = -1;
+ } else {
+ sensorHandle = static_cast<Sensor const *>(sensor)->getHandle();
+ }
+ return static_cast<SensorManager *>(manager)->configureDirectChannel(
+ channelId, sensorHandle, rate);
+}
+
/*****************************************************************************/
int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
@@ -211,3 +300,13 @@ bool ASensor_isWakeUpSensor(ASensor const* sensor)
{
return static_cast<Sensor const*>(sensor)->isWakeUpSensor();
}
+
+bool ASensor_isDirectChannelTypeSupported(ASensor const *sensor, int channelType) {
+ RETURN_IF_SENSOR_IS_NULL(false);
+ return static_cast<Sensor const *>(sensor)->isDirectChannelTypeSupported(channelType);
+}
+
+int ASensor_getHighestDirectReportRateLevel(ASensor const *sensor) {
+ RETURN_IF_SENSOR_IS_NULL(ASENSOR_DIRECT_RATE_STOP);
+ return static_cast<Sensor const *>(sensor)->getHighestDirectReportRateLevel();
+}
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
index 6d2de98759c8..bf5cabbe4bc2 100644
--- a/native/graphics/jni/bitmap.cpp
+++ b/native/graphics/jni/bitmap.cpp
@@ -15,11 +15,7 @@
*/
#include <android/bitmap.h>
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#include <GraphicsJNI.h>
-#pragma GCC diagnostic pop
+#include <Bitmap.h>
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
AndroidBitmapInfo* info) {
@@ -27,32 +23,8 @@ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
}
- SkBitmap bm;
- GraphicsJNI::getSkBitmap(env, jbitmap, &bm);
-
if (info) {
- info->width = bm.width();
- info->height = bm.height();
- info->stride = bm.rowBytes();
- info->flags = 0;
-
- switch (bm.colorType()) {
- case kN32_SkColorType:
- info->format = ANDROID_BITMAP_FORMAT_RGBA_8888;
- break;
- case kRGB_565_SkColorType:
- info->format = ANDROID_BITMAP_FORMAT_RGB_565;
- break;
- case kARGB_4444_SkColorType:
- info->format = ANDROID_BITMAP_FORMAT_RGBA_4444;
- break;
- case kAlpha_8_SkColorType:
- info->format = ANDROID_BITMAP_FORMAT_A_8;
- break;
- default:
- info->format = ANDROID_BITMAP_FORMAT_NONE;
- break;
- }
+ android::bitmap::imageInfo(env, jbitmap, info);
}
return ANDROID_BITMAP_RESULT_SUCCESS;
}
@@ -62,19 +34,11 @@ int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) {
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
}
- SkPixelRef* pixelRef = GraphicsJNI::refSkPixelRef(env, jbitmap);
- if (!pixelRef) {
+ void* addr = android::bitmap::lockPixels(env, jbitmap);
+ if (!addr) {
return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
}
- pixelRef->lockPixels();
- void* addr = pixelRef->pixels();
- if (NULL == addr) {
- pixelRef->unlockPixels();
- pixelRef->unref();
- return ANDROID_BITMAP_RESULT_ALLOCATION_FAILED;
- }
-
if (addrPtr) {
*addrPtr = addr;
}
@@ -86,26 +50,10 @@ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) {
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
}
- SkPixelRef* pixelRef = GraphicsJNI::refSkPixelRef(env, jbitmap);
- if (!pixelRef) {
+ bool unlocked = android::bitmap::unlockPixels(env, jbitmap);
+ if (!unlocked) {
return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
}
-
- // notifyPixelsChanged() needs be called to apply writes to GL-backed
- // bitmaps. Note that this will slow down read-only accesses to the
- // bitmaps, but the NDK methods are primarily intended to be used for
- // writes.
- pixelRef->notifyPixelsChanged();
-
- pixelRef->unlockPixels();
- // Awkward in that we need to double-unref as the call to get the SkPixelRef
- // did a ref(), so we need to unref() for the local ref and for the previous
- // AndroidBitmap_lockPixels(). However this keeps GraphicsJNI a bit safer
- // if others start using it without knowing about android::Bitmap's "fun"
- // ref counting mechanism(s).
- pixelRef->unref();
- pixelRef->unref();
-
return ANDROID_BITMAP_RESULT_SUCCESS;
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java b/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
index 84745b29e428..19c2c14478f1 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
@@ -46,8 +46,8 @@ public class ReceiverActivity extends Activity {
final Uri uri = DocumentsContract.buildRootUri(
MtpDocumentsProvider.AUTHORITY, deviceRootId);
- final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
- intent.setData(uri);
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setDataAndType(uri, DocumentsContract.Root.MIME_TYPE_ITEM);
intent.addCategory(Intent.CATEGORY_DEFAULT);
this.startActivity(intent);
} catch (IOException exception) {
diff --git a/packages/SettingsLib/res/layout/drawer_category.xml b/packages/SettingsLib/res/layout/drawer_category.xml
deleted file mode 100644
index 72cfddb1a431..000000000000
--- a/packages/SettingsLib/res/layout/drawer_category.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:orientation="vertical">
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/listDivider" />
-
- <TextView
- style="@style/TextAppearanceSmall"
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
- android:paddingStart="16dp" />
-
-</LinearLayout>
diff --git a/packages/SettingsLib/res/layout/drawer_item.xml b/packages/SettingsLib/res/layout/drawer_item.xml
deleted file mode 100644
index d492ddfee0fe..000000000000
--- a/packages/SettingsLib/res/layout/drawer_item.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/tile_item"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="@dimen/drawer_icon_size"
- android:layout_height="@dimen/drawer_icon_size"
- android:layout_marginStart="@dimen/drawer_icon_margin"
- android:layout_marginEnd="@dimen/drawer_icon_margin"
- android:layout_marginTop="@dimen/drawer_item_top_bottom_margin"
- android:layout_marginBottom="@dimen/drawer_item_top_bottom_margin"
- android:scaleType="fitCenter"
- android:layout_gravity="center_vertical"
- android:tint="?android:attr/colorAccent"/>
-
- <TextView
- android:textAppearance="@style/TextAppearanceMedium"
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:textColor="?android:attr/colorControlNormal" />
-
-</LinearLayout>
diff --git a/packages/SettingsLib/res/layout/drawer_spacer.xml b/packages/SettingsLib/res/layout/drawer_spacer.xml
deleted file mode 100644
index 98120cf904d0..000000000000
--- a/packages/SettingsLib/res/layout/drawer_spacer.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
- Copyright (C) 2016 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.
--->
-<Space
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/spacer"
- android:layout_width="match_parent"
- android:layout_height="@dimen/drawer_spacer_height" />
diff --git a/packages/SettingsLib/res/layout/settings_with_drawer.xml b/packages/SettingsLib/res/layout/settings_with_drawer.xml
index b659cee03780..e9c175f6fed0 100644
--- a/packages/SettingsLib/res/layout/settings_with_drawer.xml
+++ b/packages/SettingsLib/res/layout/settings_with_drawer.xml
@@ -47,13 +47,4 @@
android:layout_height="fill_parent"
android:background="?android:attr/windowBackground" />
</LinearLayout>
- <!-- The navigation drawer -->
- <ListView android:id="@+id/left_drawer"
- android:layout_width="@dimen/drawer_width"
- android:layout_height="match_parent"
- android:layout_gravity="start"
- android:choiceMode="singleChoice"
- android:divider="@android:color/transparent"
- android:dividerHeight="0dp"
- android:background="?android:attr/colorBackground" />
</android.support.v4.widget.DrawerLayout>
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
index ee69b56ef472..64f21b50c0bc 100755
--- a/packages/SettingsLib/res/values/config.xml
+++ b/packages/SettingsLib/res/values/config.xml
@@ -26,9 +26,6 @@
<!-- Whether to send a custom package name with the PSD.-->
<bool name="config_sendPackageName">false</bool>
- <!-- Whether to enable the left nav drawer in all Settings UI.-->
- <bool name="config_enable_nav_drawer">false</bool>
-
<!-- Name for the set of keys associating package names -->
<string name="config_helpPackageNameKey" translatable="false"></string>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index aa3661707130..3322839ee213 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -51,12 +51,6 @@
<dimen name="usage_graph_dot_size">.75dp</dimen>
<dimen name="usage_graph_dot_interval">7dp</dimen>
- <dimen name="drawer_icon_size">24dp</dimen>
- <dimen name="normal_icon_size">24dp</dimen>
- <dimen name="drawer_icon_margin">24dp</dimen>
- <dimen name="drawer_width">300dp</dimen>
- <dimen name="drawer_item_top_bottom_margin">4dp</dimen>
- <dimen name="drawer_spacer_height">32dp</dimen>
<dimen name="battery_height">14.5dp</dimen>
<dimen name="battery_width">9.5dp</dimen>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index 7f7249f0f908..b06b0328f8fd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -28,6 +28,7 @@ import android.os.UserHandle;
import android.util.Log;
import com.android.settingslib.R;
+import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
import java.util.ArrayList;
import java.util.List;
@@ -35,6 +36,13 @@ import java.util.List;
public class AppUtils {
private static final String TAG = "AppUtils";
+ /**
+ * This should normally only be set in robolectric tests, to avoid getting a method not found
+ * exception when calling the isInstantApp method of the ApplicationInfo class, because
+ * robolectric does not yet have an implementation of it.
+ */
+ private static InstantAppDataProvider sInstantAppDataProvider = null;
+
public static CharSequence getLaunchByDefaultSummary(ApplicationsState.AppEntry appEntry,
IUsbManager usbManager, PackageManager pm, Context context) {
String packageName = appEntry.info.packageName;
@@ -74,7 +82,11 @@ public class AppUtils {
* Returns a boolean indicating whether the given package should be considered an instant app
*/
public static boolean isInstant(ApplicationInfo info) {
- if (info.isInstantApp()) {
+ if (sInstantAppDataProvider != null) {
+ if (sInstantAppDataProvider.isInstantApp(info)) {
+ return true;
+ }
+ } else if (info.isInstantApp()) {
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
index acb0650ff71e..21835738fd69 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
@@ -20,6 +20,7 @@ import android.app.usage.StorageStats;
import android.app.usage.StorageStatsManager;
import android.content.Context;
import android.os.UserHandle;
+import android.support.annotation.VisibleForTesting;
/**
* StorageStatsSource wraps the StorageStatsManager for testability purposes.
@@ -40,6 +41,12 @@ public class StorageStatsSource {
return new StorageStatsSource.AppStorageStatsImpl(mStorageStatsManager.queryStatsForUid(volumeUuid, uid));
}
+ public StorageStatsSource.AppStorageStats getStatsForPackage(
+ String volumeUuid, String packageName, UserHandle user) {
+ return new StorageStatsSource.AppStorageStatsImpl(
+ mStorageStatsManager.queryStatsForPackage(volumeUuid, packageName, user));
+ }
+
/**
* Static class that provides methods for querying the amount of external storage available as
* well as breaking it up into several media types.
@@ -50,11 +57,10 @@ public class StorageStatsSource {
public long videoBytes;
public long imageBytes;
- /**
- * Convenience method for testing.
- */
- public ExternalStorageStats(long totalBytes, long audioBytes, long videoBytes,
- long imageBytes) {
+ /** Convenience method for testing. */
+ @VisibleForTesting
+ public ExternalStorageStats(
+ long totalBytes, long audioBytes, long videoBytes, long imageBytes) {
this.totalBytes = totalBytes;
this.audioBytes = audioBytes;
this.videoBytes = videoBytes;
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/instantapps/InstantAppDataProvider.java b/packages/SettingsLib/src/com/android/settingslib/applications/instantapps/InstantAppDataProvider.java
new file mode 100644
index 000000000000..8b15715f5a6f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/instantapps/InstantAppDataProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 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.settingslib.applications.instantapps;
+
+import android.content.pm.ApplicationInfo;
+
+/**
+ * This helps deal with the fact that robolectric does not yet have an implementation of the
+ * isInstantApp method of ApplicationInfo, so we get a method not found exception when running tests
+ * if we try to call it directly.
+ */
+public interface InstantAppDataProvider {
+ public boolean isInstantApp(ApplicationInfo info);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index a8cab17b0fac..457ce76d79ac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -18,7 +18,6 @@ package com.android.settingslib.drawer;
import android.annotation.LayoutRes;
import android.annotation.Nullable;
import android.app.Activity;
-import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -29,20 +28,15 @@ import android.content.res.TypedArray;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
-import android.support.v4.widget.DrawerLayout;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
-import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
-import android.widget.AdapterView;
import android.widget.FrameLayout;
-import android.widget.ListView;
import android.widget.Toolbar;
import com.android.settingslib.R;
@@ -67,10 +61,7 @@ public class SettingsDrawerActivity extends Activity {
private final PackageReceiver mPackageReceiver = new PackageReceiver();
private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
- private SettingsDrawerAdapter mDrawerAdapter;
private FrameLayout mContentHeaderContainer;
- private DrawerLayout mDrawerLayout;
- private boolean mShowingMenu;
// Remove below after new IA
@Deprecated
@@ -94,122 +85,50 @@ public class SettingsDrawerActivity extends Activity {
}
super.setContentView(R.layout.settings_with_drawer);
mContentHeaderContainer = (FrameLayout) findViewById(R.id.content_header_container);
- mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- if (mDrawerLayout == null) {
- return;
- }
+
Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
toolbar.setVisibility(View.GONE);
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- mDrawerLayout = null;
return;
}
- if (!isNavDrawerEnabled()) {
- setIsDrawerPresent(false);
- }
- if (!isDashboardFeatureEnabled()) {
- getDashboardCategories();
- }
setActionBar(toolbar);
- mDrawerAdapter = new SettingsDrawerAdapter(this);
- ListView listView = (ListView) findViewById(R.id.left_drawer);
- listView.setAdapter(mDrawerAdapter);
- listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- public void onItemClick(android.widget.AdapterView<?> parent, View view, int position,
- long id) {
- onTileClicked(mDrawerAdapter.getTile(position));
- }
- });
- if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
- + " ms");
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (mShowingMenu && mDrawerLayout != null && item.getItemId() == android.R.id.home
- && mDrawerAdapter.getCount() != 0) {
- openDrawer();
- return true;
+ if (DEBUG_TIMING) {
+ Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
+ + " ms");
}
- return super.onOptionsItemSelected(item);
}
@Override
public boolean onNavigateUp() {
- if (!isNavDrawerEnabled()) {
- finish();
- return true;
- }
- return super.onNavigateUp();
+ finish();
+ return true;
}
@Override
protected void onResume() {
super.onResume();
-
- if (mDrawerLayout != null) {
- final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
- filter.addDataScheme("package");
- registerReceiver(mPackageReceiver, filter);
-
- if (isDashboardFeatureEnabled()) {
- new CategoriesUpdateTask().execute();
- } else {
- new CategoriesUpdater().execute();
- }
- }
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addDataScheme("package");
+ registerReceiver(mPackageReceiver, filter);
+
+ new CategoriesUpdateTask().execute();
final Intent intent = getIntent();
- if (intent != null) {
- if (intent.hasExtra(EXTRA_SHOW_MENU)) {
- if (intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
- // Intent explicitly set to show menu.
- showMenuIcon();
- }
- } else if (isNavDrawerEnabled() && isTopLevelTile(intent)) {
- showMenuIcon();
- }
+ if (intent != null && intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
+ // Intent explicitly set to show menu.
+ showMenuIcon();
}
}
@Override
protected void onPause() {
- if (mDrawerLayout != null) {
- unregisterReceiver(mPackageReceiver);
- }
-
+ unregisterReceiver(mPackageReceiver);
super.onPause();
}
- private boolean isTopLevelTile(Intent intent) {
- final ComponentName componentName = intent.getComponent();
- if (componentName == null) {
- return false;
- }
- if (isDashboardFeatureEnabled()) {
- final DashboardCategory homepageCategories = CategoryManager.get(this)
- .getTilesByCategory(this, CategoryKey.CATEGORY_HOMEPAGE, getSettingPkg());
- return homepageCategories ==
- null ? false : homepageCategories.containsComponent(componentName);
- } else {
- // Look for a tile that has the same component as incoming intent
- final List<DashboardCategory> categories = getDashboardCategories();
- for (DashboardCategory category : categories) {
- if (category.containsComponent(componentName)) {
- return true;
- }
- }
- if (DEBUG) {
- Log.d(TAG, "Intent is not for top level settings " + intent);
- }
- return false;
- }
- }
-
/**
* Gets the name of the intent action of the default setting app. Used to launch setting app
* when Settings Home is clicked.
@@ -226,30 +145,6 @@ public class SettingsDrawerActivity extends Activity {
mCategoryListeners.remove(listener);
}
- public void setIsDrawerPresent(boolean isPresent) {
- if (isPresent) {
- mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- updateDrawer();
- } else {
- if (mDrawerLayout != null) {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- mDrawerLayout = null;
- }
- }
- }
-
- public void openDrawer() {
- if (mDrawerLayout != null) {
- mDrawerLayout.openDrawer(Gravity.START);
- }
- }
-
- public void closeDrawer() {
- if (mDrawerLayout != null) {
- mDrawerLayout.closeDrawers();
- }
- }
-
public void setContentHeaderView(View headerView) {
mContentHeaderContainer.removeAllViews();
if (headerView != null) {
@@ -276,31 +171,8 @@ public class SettingsDrawerActivity extends Activity {
((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
}
- public void updateDrawer() {
- if (mDrawerLayout == null) {
- return;
- }
- // TODO: Do this in the background with some loading.
- if (isDashboardFeatureEnabled()) {
- mDrawerAdapter.updateHomepageCategories(getSettingPkg());
- } else {
- mDrawerAdapter.updateCategories();
- }
- if (mDrawerAdapter.getCount() != 0) {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
- } else {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- }
- }
-
public void showMenuIcon() {
getActionBar().setDisplayHomeAsUpEnabled(true);
- if (isNavDrawerEnabled()) {
- mShowingMenu = true;
- getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
- getActionBar().setHomeActionContentDescription(
- R.string.content_description_menu_button);
- }
}
public List<DashboardCategory> getDashboardCategories() {
@@ -315,51 +187,12 @@ public class SettingsDrawerActivity extends Activity {
}
protected void onCategoriesChanged() {
- updateDrawer();
final int N = mCategoryListeners.size();
for (int i = 0; i < N; i++) {
mCategoryListeners.get(i).onCategoriesChanged();
}
}
- @Deprecated
- public boolean openTile(Tile tile) {
- closeDrawer();
- if (tile == null) {
- Intent intent = new Intent(getSettingAction()).addFlags(
- Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(intent);
- return true;
- }
- try {
- ProfileSelectDialog.updateUserHandlesIfNeeded(this /* context */, tile);
- int numUserHandles = tile.userHandle.size();
- if (numUserHandles > 1) {
- ProfileSelectDialog.show(getFragmentManager(), tile);
- return false;
- } else if (numUserHandles == 1) {
- // Show menu on top level items.
- tile.intent.putExtra(EXTRA_SHOW_MENU, true);
- tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivityAsUser(tile.intent, tile.userHandle.get(0));
- } else {
- // Show menu on top level items.
- tile.intent.putExtra(EXTRA_SHOW_MENU, true);
- tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(tile.intent);
- }
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "Couldn't find tile " + tile.intent, e);
- }
- return true;
- }
-
- protected void onTileClicked(Tile tile) {
- if (openTile(tile)) {
- finish();
- }
- }
-
public void onProfileTileOpen() {
finish();
}
@@ -375,8 +208,8 @@ public class SettingsDrawerActivity extends Activity {
sTileBlacklist.add(component);
}
pm.setComponentEnabledSetting(component, enabled
- ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
@@ -385,11 +218,7 @@ public class SettingsDrawerActivity extends Activity {
* Updates dashboard categories. Only necessary to call this after setTileEnabled
*/
public void updateCategories() {
- if (isDashboardFeatureEnabled()) {
- new CategoriesUpdateTask().execute();
- } else {
- new CategoriesUpdater().execute();
- }
+ new CategoriesUpdateTask().execute();
}
public String getSettingPkg() {
@@ -400,42 +229,6 @@ public class SettingsDrawerActivity extends Activity {
void onCategoriesChanged();
}
- /**
- * @deprecated remove after new IA
- */
- @Deprecated
- private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
- @Override
- protected List<DashboardCategory> doInBackground(Void... params) {
- if (sConfigTracker.applyNewConfig(getResources())) {
- sTileCache.clear();
- }
- return TileUtils.getCategories(SettingsDrawerActivity.this, sTileCache);
- }
-
- @Override
- protected void onPreExecute() {
- if (sConfigTracker == null || sTileCache == null) {
- getDashboardCategories();
- }
- }
-
- @Override
- protected void onPostExecute(List<DashboardCategory> dashboardCategories) {
- for (int i = 0; i < dashboardCategories.size(); i++) {
- DashboardCategory category = dashboardCategories.get(i);
- for (int j = 0; j < category.tiles.size(); j++) {
- Tile tile = category.tiles.get(j);
- if (sTileBlacklist.contains(tile.intent.getComponent())) {
- category.tiles.remove(j--);
- }
- }
- }
- sDashboardCategories = dashboardCategories;
- onCategoriesChanged();
- }
- }
-
private class CategoriesUpdateTask extends AsyncTask<Void, Void, Void> {
private final CategoryManager mCategoryManager;
@@ -457,25 +250,10 @@ public class SettingsDrawerActivity extends Activity {
}
}
- /**
- * @return {@code true} if IA (Information Architecture) is enabled.
- */
- protected boolean isDashboardFeatureEnabled() {
- return false;
- }
-
- boolean isNavDrawerEnabled() {
- return getResources().getBoolean(R.bool.config_enable_nav_drawer);
- }
-
private class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (isDashboardFeatureEnabled()) {
- new CategoriesUpdateTask().execute();
- } else {
- new CategoriesUpdater().execute();
- }
+ new CategoriesUpdateTask().execute();
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
deleted file mode 100644
index 75942f93b67b..000000000000
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.drawer;
-
-import android.graphics.drawable.Icon;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.settingslib.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SettingsDrawerAdapter extends BaseAdapter {
-
- private final ArrayList<Item> mItems = new ArrayList<>();
- private final SettingsDrawerActivity mActivity;
-
- public SettingsDrawerAdapter(SettingsDrawerActivity activity) {
- mActivity = activity;
- }
-
- /**
- * @deprecated Remove after new IA
- */
- @Deprecated
- void updateCategories() {
- List<DashboardCategory> categories = mActivity.getDashboardCategories();
- mItems.clear();
- // Spacer.
- mItems.add(null);
- Item tile = new Item();
- tile.label = mActivity.getString(R.string.home);
- tile.icon = Icon.createWithResource(mActivity, R.drawable.home);
- mItems.add(tile);
- for (int i = 0; i < categories.size(); i++) {
- Item category = new Item();
- category.icon = null;
- DashboardCategory dashboardCategory = categories.get(i);
- category.label = dashboardCategory.title;
- mItems.add(category);
- for (int j = 0; j < dashboardCategory.tiles.size(); j++) {
- tile = new Item();
- Tile dashboardTile = dashboardCategory.tiles.get(j);
- tile.label = dashboardTile.title;
- tile.icon = dashboardTile.icon;
- tile.tile = dashboardTile;
- mItems.add(tile);
- }
- }
- notifyDataSetChanged();
- }
-
- public void updateHomepageCategories(String settingPkg) {
- final DashboardCategory category = CategoryManager.get(mActivity)
- .getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE, settingPkg);
- mItems.clear();
- // Spacer.
- mItems.add(null);
- Item tile = new Item();
- tile.label = mActivity.getString(R.string.home);
- tile.icon = Icon.createWithResource(mActivity, R.drawable.home);
- mItems.add(tile);
- for (int j = 0; j < category.tiles.size(); j++) {
- tile = new Item();
- Tile dashboardTile = category.tiles.get(j);
- tile.label = dashboardTile.title;
- tile.icon = dashboardTile.icon;
- tile.tile = dashboardTile;
- mItems.add(tile);
- }
- notifyDataSetChanged();
- }
-
- public Tile getTile(int position) {
- return mItems.get(position) != null ? mItems.get(position).tile : null;
- }
-
- @Override
- public int getCount() {
- return mItems.size();
- }
-
- @Override
- public Object getItem(int position) {
- return mItems.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public boolean isEnabled(int position) {
- return mItems.get(position) != null && mItems.get(position).icon != null;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Item item = mItems.get(position);
- if (item == null) {
- if (convertView == null || convertView.getId() != R.id.spacer) {
- convertView = LayoutInflater.from(mActivity).inflate(R.layout.drawer_spacer,
- parent, false);
- }
- return convertView;
- }
- if (convertView != null && convertView.getId() == R.id.spacer) {
- convertView = null;
- }
- boolean isTile = item.icon != null;
- if (convertView == null || (isTile != (convertView.getId() == R.id.tile_item))) {
- convertView = LayoutInflater.from(mActivity).inflate(isTile ? R.layout.drawer_item
- : R.layout.drawer_category,
- parent, false);
- }
- if (isTile) {
- ((ImageView) convertView.findViewById(android.R.id.icon)).setImageIcon(item.icon);
- }
- ((TextView) convertView.findViewById(android.R.id.title)).setText(item.label);
- return convertView;
- }
-
- private static class Item {
- public Icon icon;
- public CharSequence label;
- public Tile tile;
- }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java
index 3f6f5b5fc841..55be13761a97 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java
@@ -396,7 +396,7 @@ public class InputMethodAndSubtypeUtil {
.applicationInfo);
}
return LocaleHelper.toSentenceCase(
- ListFormatter.getInstance(locale).format(subtypeNames), locale);
+ ListFormatter.getInstance(locale).format((Object[]) subtypeNames), locale);
}
@NonNull
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index 69da5483fe18..50972c709863 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -23,6 +23,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.net.NetworkBadging;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
import android.os.Looper;
import android.os.UserHandle;
import android.support.v7.preference.Preference;
@@ -222,7 +223,8 @@ public class AccessPointPreference extends Preference {
}
final Context context = getContext();
- int level = mAccessPoint.getLevel();
+ int level = WifiManager.calculateSignalLevel(
+ mAccessPoint.getRssi(), WifiManager.RSSI_LEVELS);
int wifiBadge = mAccessPoint.getBadge();
if (level != mLevel || wifiBadge != mWifiBadge) {
mLevel = level;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
index c3f2f736b441..752b5b0e152c 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
@@ -86,16 +86,6 @@ public class SettingsDrawerActivityTest {
.check(matches(isDisplayed()));
}
- @Test
- public void startActivity_shouldNotHaveNavDrawer() {
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- Activity activity = instrumentation.startActivitySync(
- new Intent(instrumentation.getTargetContext(), TestActivity.class));
-
- assertThat(((SettingsDrawerActivity) activity).isNavDrawerEnabled())
- .isFalse();
- }
-
/**
* Test Activity in this test.
*
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index a4d8a1003f98..b58ea00997ef 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -12,17 +12,21 @@
* permissions and limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.plugins;
import android.app.PendingIntent;
import android.content.Intent;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
/**
* An interface to start activities. This is used as a callback from the views to
* {@link PhoneStatusBar} to allow custom handling for starting the activity, i.e. dismissing the
* Keyguard.
*/
+@ProvidesInterface(version = ActivityStarter.VERSION)
public interface ActivityStarter {
+ int VERSION = 1;
void startPendingIntentDismissingKeyguard(PendingIntent intent);
void startActivity(Intent intent, boolean dismissShade);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
new file mode 100644
index 000000000000..25ce3ddf8169
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+@ProvidesInterface(version = PluginDependency.VERSION)
+public class PluginDependency {
+ public static final int VERSION = 1;
+ static DependencyProvider sProvider;
+
+ public static <T> T get(Plugin p, Class<T> cls) {
+ return sProvider.get(p, cls);
+ }
+
+ static abstract class DependencyProvider {
+ abstract <T> T get(Plugin p, Class<T> cls);
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
index ddee89ed74ec..674ed5a3a480 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
@@ -19,7 +19,7 @@ import android.view.MotionEvent;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.annotations.ProvidesInterface;
-@ProvidesInterface(action = NavGesture.ACTION, version = NavBarButtonProvider.VERSION)
+@ProvidesInterface(action = NavGesture.ACTION, version = NavGesture.VERSION)
public interface NavGesture extends Plugin {
public static final String ACTION = "com.android.systemui.action.PLUGIN_NAV_GESTURE";
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 14c67fe8a9ad..e58538db9cea 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -17,6 +17,8 @@ package com.android.systemui;
import android.app.PendingIntent;
import android.content.Intent;
+import com.android.systemui.plugins.ActivityStarter;
+
/**
* Single common instance of ActivityStarter that can be gotten and referenced from anywhere, but
* delegates to an actual implementation such as StatusBar, assuming it exists.
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index ac7ab9de7f11..bb7e19de0689 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -23,10 +23,12 @@ import android.os.Process;
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.NightDisplayController;
import com.android.internal.util.Preconditions;
import com.android.systemui.assist.AssistManager;
-import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
@@ -179,6 +181,9 @@ public class Dependency extends SystemUI {
mProviders.put(BatteryController.class, () ->
new BatteryControllerImpl(mContext));
+ mProviders.put(NightDisplayController.class, () ->
+ new NightDisplayController(mContext));
+
mProviders.put(ManagedProfileController.class, () ->
new ManagedProfileControllerImpl(mContext));
@@ -238,6 +243,9 @@ public class Dependency extends SystemUI {
mProviders.put(ExtensionController.class, () ->
new ExtensionControllerImpl());
+ mProviders.put(PluginDependencyProvider.class, () ->
+ new PluginDependencyProvider(get(PluginManager.class)));
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index b9ae585c339c..e1aaaa36d77a 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -47,6 +47,7 @@ public final class Prefs {
Key.QS_DATA_SAVER_DIALOG_SHOWN,
Key.QS_INVERT_COLORS_ADDED,
Key.QS_WORK_ADDED,
+ Key.QS_NIGHTDISPLAY_ADDED,
})
public @interface Key {
@Deprecated
@@ -67,6 +68,7 @@ public final class Prefs {
String QS_DATA_SAVER_DIALOG_SHOWN = "QsDataSaverDialogShown";
String QS_INVERT_COLORS_ADDED = "QsInvertColorsAdded";
String QS_WORK_ADDED = "QsWorkAdded";
+ String QS_NIGHTDISPLAY_ADDED = "QsNightDisplayAdded";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
new file mode 100644
index 000000000000..59f6d56ac1be
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.plugins;
+
+import android.util.ArrayMap;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.PluginDependency.DependencyProvider;
+
+public class PluginDependencyProvider extends DependencyProvider {
+
+ private final ArrayMap<Class<?>, Object> mDependencies = new ArrayMap<>();
+ private final PluginManager mManager;
+
+ public PluginDependencyProvider(PluginManager manager) {
+ mManager = manager;
+ PluginDependency.sProvider = this;
+ }
+
+ public <T> void allowPluginDependency(Class<T> cls) {
+ allowPluginDependency(cls, Dependency.get(cls));
+ }
+
+ public <T> void allowPluginDependency(Class<T> cls, T obj) {
+ mDependencies.put(cls, obj);
+ }
+
+ @Override
+ <T> T get(Plugin p, Class<T> cls) {
+ if (!mManager.dependsOn(p, cls)) {
+ throw new IllegalArgumentException(p.getClass() + " does not depend on " + cls);
+ }
+ if (!mDependencies.containsKey(cls)) {
+ throw new IllegalArgumentException("Unknown dependency " + cls);
+ }
+ return (T) mDependencies.get(cls);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index e895fa226cf3..58670da88f4b 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -161,6 +161,16 @@ public class PluginInstanceManager<T extends Plugin> {
mContext.sendBroadcast(intent);
}
+ public <T> boolean dependsOn(Plugin p, Class<T> cls) {
+ ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins);
+ for (PluginInfo info : plugins) {
+ if (info.mPlugin.getClass().getName().equals(p.getClass().getName())) {
+ return info.mVersion != null && info.mVersion.hasClass(cls);
+ }
+ }
+ return false;
+ }
+
private class MainHandler extends Handler {
private static final int PLUGIN_CONNECTED = 1;
private static final int PLUGIN_DISCONNECTED = 2;
@@ -304,9 +314,9 @@ public class PluginInstanceManager<T extends Plugin> {
// legacy version check.
T plugin = (T) pluginClass.newInstance();
try {
- checkVersion(pluginClass, plugin, mVersion);
+ VersionInfo version = checkVersion(pluginClass, plugin, mVersion);
if (DEBUG) Log.d(TAG, "createPlugin");
- return new PluginInfo(pkg, cls, plugin, pluginContext);
+ return new PluginInfo(pkg, cls, plugin, pluginContext, version);
} catch (InvalidVersionException e) {
final int icon = mContext.getResources().getIdentifier("tuner", "drawable",
mContext.getPackageName());
@@ -354,7 +364,7 @@ public class PluginInstanceManager<T extends Plugin> {
}
}
- private void checkVersion(Class<?> pluginClass, T plugin, VersionInfo version)
+ private VersionInfo checkVersion(Class<?> pluginClass, T plugin, VersionInfo version)
throws InvalidVersionException {
VersionInfo pv = new VersionInfo().addClass(pluginClass);
if (pv.hasVersionInfo()) {
@@ -364,7 +374,9 @@ public class PluginInstanceManager<T extends Plugin> {
if (fallbackVersion != version.getDefaultVersion()) {
throw new InvalidVersionException("Invalid legacy version", false);
}
+ return null;
}
+ return pv;
}
}
@@ -396,15 +408,18 @@ public class PluginInstanceManager<T extends Plugin> {
static class PluginInfo<T> {
private final Context mPluginContext;
+ private final VersionInfo mVersion;
private String mClass;
T mPlugin;
String mPackage;
- public PluginInfo(String pkg, String cls, T plugin, Context pluginContext) {
+ public PluginInfo(String pkg, String cls, T plugin, Context pluginContext,
+ VersionInfo info) {
mPlugin = plugin;
mClass = cls;
mPackage = pkg;
mPluginContext = pluginContext;
+ mVersion = info;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
index 0c3e40c7d891..9ad862d4c33a 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
@@ -29,6 +29,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
+import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.SystemProperties;
@@ -39,6 +40,7 @@ import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.systemui.Dependency;
import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -93,6 +95,14 @@ public class PluginManager extends BroadcastReceiver {
PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
defaultHandler);
Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
+ if (isDebuggable) {
+ new Handler(mBackgroundThread.getLooper()).post(() -> {
+ // Plugin dependencies that don't have another good home can go here, but
+ // dependencies that have better places to init can happen elsewhere.
+ Dependency.get(PluginDependencyProvider.class)
+ .allowPluginDependency(ActivityStarter.class);
+ });
+ }
}
public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
@@ -268,11 +278,6 @@ public class PluginManager extends BroadcastReceiver {
return mParentClassLoader;
}
- public Context getAllPluginContext(Context context) {
- return new PluginContextWrapper(context,
- new AllPluginClassLoader(context.getClassLoader()));
- }
-
public Context getContext(ApplicationInfo info, String pkg) throws NameNotFoundException {
ClassLoader classLoader = getClassLoader(info.sourceDir, pkg);
return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
@@ -289,26 +294,13 @@ public class PluginManager extends BroadcastReceiver {
return info.action();
}
- private class AllPluginClassLoader extends ClassLoader {
- public AllPluginClassLoader(ClassLoader classLoader) {
- super(classLoader);
- }
-
- @Override
- public Class<?> loadClass(String s) throws ClassNotFoundException {
- try {
- return super.loadClass(s);
- } catch (ClassNotFoundException e) {
- for (ClassLoader classLoader : mClassLoaders.values()) {
- try {
- return classLoader.loadClass(s);
- } catch (ClassNotFoundException e1) {
- // Will re-throw e if all fail.
- }
- }
- throw e;
+ public <T> boolean dependsOn(Plugin p, Class<T> cls) {
+ for (int i = 0; i < mPluginMap.size(); i++) {
+ if (mPluginMap.valueAt(i).dependsOn(p, cls)) {
+ return true;
}
}
+ return false;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java b/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java
index 84f7761a8043..b69a7b4d77d9 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java
@@ -103,6 +103,10 @@ public class VersionInfo {
return null;
}
+ public <T> boolean hasClass(Class<T> cls) {
+ return mVersions.containsKey(cls);
+ }
+
public static class InvalidVersionException extends RuntimeException {
private final boolean mTooNew;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index a20b7baa0261..7df124a1ec03 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -37,7 +37,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
import com.android.systemui.plugins.qs.QS.Callback;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 1835afd937c1..d6c2447467da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -37,7 +37,7 @@ import android.widget.TextView;
import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.SecurityController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 0829ae5f597c..c02067e698e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -32,7 +32,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.Dependency;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSTile.State;
import com.android.systemui.qs.external.TileServices;
@@ -45,8 +45,6 @@ import com.android.settingslib.Utils;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.systemui.R;
-
/**
* Base quick-settings tile, extend this to create a new tile.
*
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index cdde6ea0e85a..b28b0e70ceb5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -30,17 +30,13 @@ import android.provider.Settings;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
-import android.text.SpannableStringBuilder;
-import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.IWindowManager;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
import com.android.systemui.Dependency;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
import com.android.systemui.statusbar.phone.QSTileHost;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 4b56ecdfade7..5d7508b5747b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -34,7 +34,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 3c28f7602c18..c501c914eb32 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -30,7 +30,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index bae163fc1451..1a04a51f93ea 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -31,7 +31,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSIconView;
import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 4072b4442377..d554a1788627 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -39,7 +39,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SysUIToast;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.ZenModeController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index fcc959601dab..aeea75d179f7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -32,7 +32,7 @@ import android.util.Log;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSTile;
import java.util.Arrays;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 423a1df703e1..e61a953aaa82 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -26,7 +26,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.LocationController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 796967c877c7..83dc1c2e69af 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -33,7 +33,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.wifi.AccessPoint;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 98787f7c6ec0..d4997ead8292 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -923,12 +923,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mOnActivatedListener = onActivatedListener;
}
- public void reset() {
- setTintColor(0);
- resetBackgroundAlpha();
- setBelowSpeedBump(false);
- }
-
public boolean hasSameBgColor(ActivatableNotificationView otherView) {
return calculateBgColor() == otherView.calculateBgColor();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index bfe4bb266684..602c3dfde73e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.statusbar.notification.NotificationInflater.InflationExceptionHandler;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -42,6 +44,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Chronometer;
import android.widget.ImageView;
+import android.widget.RemoteViews;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -52,6 +55,8 @@ import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
import com.android.systemui.statusbar.notification.HybridNotificationView;
+import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -70,6 +75,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
private static final int COLORED_DIVIDER_ALPHA = 0x7B;
+ private final NotificationInflater mNotificationInflater;
private int mIconTransformContentShift;
private int mIconTransformContentShiftNoIcon;
private int mNotificationMinHeightLegacy;
@@ -152,14 +158,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private OnClickListener mExpandClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
- if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
+ if (!mShowingPublic && (!mIsLowPriority || isExpanded())
+ && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
mGroupExpansionChanging = true;
final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
nowExpanded);
- logExpansionEvent(true /* userAction */, wasExpanded);
+ onExpansionChanged(true /* userAction */, wasExpanded);
} else {
if (v.isAccessibilityFocused()) {
mPrivateLayout.setFocusOnVisibilityChange();
@@ -246,6 +253,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
if (mIsSummaryWithChildren) {
setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
+ setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
List<ExpandableNotificationRow> notificationChildren =
mChildrenContainer.getNotificationChildren();
for (int i = 0; i < notificationChildren.size(); i++) {
@@ -298,17 +306,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
- public void onNotificationUpdated(NotificationData.Entry entry) {
+ public void updateNotification(NotificationData.Entry entry) throws InflationException {
mEntry = entry;
mStatusBarNotification = entry.notification;
+ mNotificationInflater.inflateNotificationViews();
+ onNotificationUpdated();
+ }
+
+ private void onNotificationUpdated() {
for (NotificationContentView l : mLayouts) {
- l.onNotificationUpdated(entry);
+ l.onNotificationUpdated(mEntry);
}
mIsColorized = mStatusBarNotification.getNotification().isColorized();
mShowingPublicInitialized = false;
updateNotificationColor();
if (mIsSummaryWithChildren) {
- mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
+ mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
mChildrenContainer.onNotificationUpdated();
}
if (mIconAnimationRunning) {
@@ -458,6 +471,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
mNotificationParent = childInGroup ? parent : null;
mPrivateLayout.setIsChildInGroup(childInGroup);
+ if (mNotificationInflater.setIsChildInGroup(childInGroup)) {
+ onNotificationUpdated();
+ }
resetBackgroundAlpha();
updateBackgroundForGroupState();
updateClickAndFocus();
@@ -671,9 +687,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return mPrivateLayout.getNotificationHeader();
}
- private NotificationHeaderView getVisibleNotificationHeader() {
+ /**
+ * @return the currently visible notification header. This can be different from
+ * {@link #getNotificationHeader()} in case it is a low-priority group.
+ */
+ public NotificationHeaderView getVisibleNotificationHeader() {
if (mIsSummaryWithChildren && !mShowingPublic) {
- return mChildrenContainer.getHeaderView();
+ return mChildrenContainer.getVisibleHeader();
}
return getShowingLayout().getVisibleNotificationHeader();
}
@@ -711,7 +731,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
- public void reInflateViews() {
+ public void onDensityOrFontScaleChanged() {
initDimens();
if (mIsSummaryWithChildren) {
if (mChildrenContainer != null) {
@@ -742,6 +762,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
for (NotificationContentView l : mLayouts) {
l.reInflateViews();
}
+ mNotificationInflater.onDensityOrFontScaleChanged();
+ onNotificationUpdated();
}
public void setContentBackground(int customBackgroundColor, boolean animate,
@@ -891,7 +913,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
public View getNotificationIcon() {
- NotificationHeaderView notificationHeader = getNotificationHeader();
+ NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
if (notificationHeader != null) {
return notificationHeader.getIcon();
}
@@ -1008,17 +1030,32 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void setIsLowPriority(boolean isLowPriority) {
mIsLowPriority = isLowPriority;
mPrivateLayout.setIsLowPriority(isLowPriority);
+ mNotificationInflater.setIsLowPriority(mIsLowPriority);
if (mChildrenContainer != null) {
mChildrenContainer.setIsLowPriority(isLowPriority);
}
}
+ public boolean isLowPriority() {
+ return mIsLowPriority;
+ }
+
public void setUseIncreasedCollapsedHeight(boolean use) {
mUseIncreasedCollapsedHeight = use;
+ mNotificationInflater.setUsesIncreasedHeight(use);
}
public void setUseIncreasedHeadsUpHeight(boolean use) {
mUseIncreasedHeadsUpHeight = use;
+ mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
+ }
+
+ public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
+ mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
+ }
+
+ public void setInflateExceptionHandler(InflationExceptionHandler inflateExceptionHandler) {
+ mNotificationInflater.setInflateExceptionHandler(inflateExceptionHandler);
}
public interface ExpansionLogger {
@@ -1028,6 +1065,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
mFalsingManager = FalsingManager.getInstance(context);
+ mNotificationInflater = new NotificationInflater(this);
initDimens();
}
@@ -1063,26 +1101,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
/**
* Resets this view so it can be re-used for an updated notification.
*/
- @Override
public void reset() {
- super.reset();
- final boolean wasExpanded = isExpanded();
- mExpandable = false;
- mHasUserChangedExpansion = false;
- mUserLocked = false;
- mShowingPublic = false;
- mSensitive = false;
mShowingPublicInitialized = false;
- mIsSystemExpanded = false;
- mOnKeyguard = false;
- mPublicLayout.reset();
- mPrivateLayout.reset();
- resetHeight();
- resetTranslation();
- logExpansionEvent(false, wasExpanded);
- }
-
- public void resetHeight() {
onHeightReset();
requestLayout();
}
@@ -1124,7 +1144,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void onInflate(ViewStub stub, View inflated) {
mChildrenContainer = (NotificationChildrenContainer) inflated;
mChildrenContainer.setIsLowPriority(mIsLowPriority);
- mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
+ mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
mChildrenContainer.onNotificationUpdated();
mTranslateableViews.add(mChildrenContainer);
}
@@ -1253,9 +1273,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (mChildrenContainer != null) {
mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
: INVISIBLE);
- mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
- ? VISIBLE
- : INVISIBLE);
+ mChildrenContainer.setHeaderVisible(!mShowingPublic && mIsSummaryWithChildren);
}
// The limits might have changed if the view suddenly became a group or vice versa
updateLimits();
@@ -1323,7 +1341,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
*/
public void setUserExpanded(boolean userExpanded) {
setUserExpanded(userExpanded, false /* allowChildExpansion */);
- updateShelfIconColor();
}
/**
@@ -1334,22 +1351,28 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
*/
public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
mFalsingManager.setNotificationExpanded();
- if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
+ if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion
+ && !mChildrenContainer.showingAsLowPriority()) {
final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
- logExpansionEvent(true /* userAction */, wasExpanded);
+ onExpansionChanged(true /* userAction */, wasExpanded);
return;
}
if (userExpanded && !mExpandable) return;
final boolean wasExpanded = isExpanded();
mHasUserChangedExpansion = true;
mUserExpanded = userExpanded;
- logExpansionEvent(true, wasExpanded);
+ onExpansionChanged(true /* userAction */, wasExpanded);
}
public void resetUserExpansion() {
+ boolean changed = mUserExpanded;
mHasUserChangedExpansion = false;
mUserExpanded = false;
+ if (changed && mIsSummaryWithChildren) {
+ mChildrenContainer.onExpansionChanged();
+ }
+ updateShelfIconColor();
}
public boolean isUserLocked() {
@@ -1383,9 +1406,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (expand != mIsSystemExpanded) {
final boolean wasExpanded = isExpanded();
mIsSystemExpanded = expand;
- updateShelfIconColor();
notifyHeightChanged(false /* needsAnimation */);
- logExpansionEvent(false, wasExpanded);
+ onExpansionChanged(false /* userAction */, wasExpanded);
if (mIsSummaryWithChildren) {
mChildrenContainer.updateGroupOverflow();
}
@@ -1399,7 +1421,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (onKeyguard != mOnKeyguard) {
final boolean wasExpanded = isExpanded();
mOnKeyguard = onKeyguard;
- logExpansionEvent(false, wasExpanded);
+ onExpansionChanged(false /* userAction */, wasExpanded);
if (wasExpanded != isExpanded()) {
if (mIsSummaryWithChildren) {
mChildrenContainer.updateGroupOverflow();
@@ -1470,8 +1492,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
&& mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
- mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
- mEntry.notification);
+ mChildrenContainer.recreateNotificationHeader(mExpandClickListener
+ );
}
getShowingLayout().updateBackgroundColor(false /* animate */);
mPrivateLayout.updateExpandButtons(isExpandable());
@@ -1526,7 +1548,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
* the top.
*/
private void updateContentShiftHeight() {
- NotificationHeaderView notificationHeader = getNotificationHeader();
+ NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
if (notificationHeader != null) {
CachingIconView icon = notificationHeader.getIcon();
mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
@@ -1737,7 +1759,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override
public void setActualHeight(int height, boolean notifyListeners) {
+ boolean changed = height != getActualHeight();
super.setActualHeight(height, notifyListeners);
+ if (changed && isRemoved()) {
+ // TODO: remove this once we found the gfx bug for this.
+ // This is a hack since a removed view sometimes would just stay blank. it occured
+ // when sending yourself a message and then clicking on it.
+ ViewGroup parent = (ViewGroup) getParent();
+ if (parent != null) {
+ parent.invalidate();
+ }
+ }
if (mGuts != null && mGuts.isExposed()) {
mGuts.setActualHeight(height);
return;
@@ -1828,9 +1860,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return mShowingPublic ? mPublicLayout : mPrivateLayout;
}
- public void setShowingLegacyBackground(boolean showing) {
+ public void setLegacy(boolean legacy) {
for (NotificationContentView l : mLayouts) {
- l.setShowingLegacyBackground(showing);
+ l.setLegacy(legacy);
}
}
@@ -1910,7 +1942,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (isGroupExpanded()) {
return 1.0f;
} else if (isUserLocked()) {
- return mChildrenContainer.getGroupExpandFraction();
+ return mChildrenContainer.getIncreasedPaddingAmount();
}
} else if (isColorized() && (!mIsLowPriority || isExpanded())) {
return -1.0f;
@@ -1933,13 +1965,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return super.disallowSingleClick(event);
}
- private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
+ private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
boolean nowExpanded = isExpanded();
- if (mIsSummaryWithChildren) {
+ if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
}
- if (wasExpanded != nowExpanded && mLogger != null) {
- mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
+ if (nowExpanded != wasExpanded) {
+ updateShelfIconColor();
+ if (mLogger != null) {
+ mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
+ }
+ if (mIsSummaryWithChildren) {
+ mChildrenContainer.onExpansionChanged();
+ }
}
}
@@ -1980,7 +2018,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override
public boolean isAboveShelf() {
- return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
+ return !isOnKeyguard()
+ && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf));
}
public void setShowAmbient(boolean showAmbient) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 57d2e1c84115..74e65fbd2432 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -80,7 +80,7 @@ public class NotificationContentView extends FrameLayout {
private boolean mDark;
private boolean mAnimate;
private boolean mIsHeadsUp;
- private boolean mShowingLegacyBackground;
+ private boolean mLegacy;
private boolean mIsChildInGroup;
private int mSmallHeight;
private int mHeadsUpHeight;
@@ -140,7 +140,6 @@ public class NotificationContentView extends FrameLayout {
R.dimen.min_notification_layout_height);
mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_end);
- reset();
}
public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight,
@@ -329,41 +328,6 @@ public class NotificationContentView extends FrameLayout {
updateVisibility();
}
- public void reset() {
- mPreviousExpandedRemoteInputIntent = null;
- if (mExpandedRemoteInput != null) {
- mExpandedRemoteInput.onNotificationUpdateOrReset();
- if (mExpandedRemoteInput.isActive()) {
- mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
- mCachedExpandedRemoteInput = mExpandedRemoteInput;
- mExpandedRemoteInput.dispatchStartTemporaryDetach();
- ((ViewGroup)mExpandedRemoteInput.getParent()).removeView(mExpandedRemoteInput);
- }
- }
- if (mExpandedChild != null) {
- mExpandedChild.animate().cancel();
- removeView(mExpandedChild);
- mExpandedRemoteInput = null;
- }
- mPreviousHeadsUpRemoteInputIntent = null;
- if (mHeadsUpRemoteInput != null) {
- mHeadsUpRemoteInput.onNotificationUpdateOrReset();
- if (mHeadsUpRemoteInput.isActive()) {
- mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
- mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
- mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
- ((ViewGroup)mHeadsUpRemoteInput.getParent()).removeView(mHeadsUpRemoteInput);
- }
- }
- if (mHeadsUpChild != null) {
- mHeadsUpChild.animate().cancel();
- removeView(mHeadsUpChild);
- mHeadsUpRemoteInput = null;
- }
- mExpandedChild = null;
- mHeadsUpChild = null;
- }
-
public View getContractedChild() {
return mContractedChild;
}
@@ -394,8 +358,30 @@ public class NotificationContentView extends FrameLayout {
public void setExpandedChild(View child) {
if (mExpandedChild != null) {
+ mPreviousExpandedRemoteInputIntent = null;
+ if (mExpandedRemoteInput != null) {
+ mExpandedRemoteInput.onNotificationUpdateOrReset();
+ if (mExpandedRemoteInput.isActive()) {
+ mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
+ mCachedExpandedRemoteInput = mExpandedRemoteInput;
+ mExpandedRemoteInput.dispatchStartTemporaryDetach();
+ ((ViewGroup)mExpandedRemoteInput.getParent()).removeView(mExpandedRemoteInput);
+ }
+ }
mExpandedChild.animate().cancel();
removeView(mExpandedChild);
+ mExpandedRemoteInput = null;
+ }
+ if (child == null) {
+ mExpandedChild = null;
+ mExpandedWrapper = null;
+ if (mVisibleType == VISIBLE_TYPE_EXPANDED) {
+ mVisibleType = VISIBLE_TYPE_CONTRACTED;
+ }
+ if (mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED) {
+ mTransformationStartVisibleType = UNDEFINED;
+ }
+ return;
}
addView(child);
mExpandedChild = child;
@@ -405,8 +391,30 @@ public class NotificationContentView extends FrameLayout {
public void setHeadsUpChild(View child) {
if (mHeadsUpChild != null) {
+ mPreviousHeadsUpRemoteInputIntent = null;
+ if (mHeadsUpRemoteInput != null) {
+ mHeadsUpRemoteInput.onNotificationUpdateOrReset();
+ if (mHeadsUpRemoteInput.isActive()) {
+ mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
+ mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
+ mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
+ ((ViewGroup)mHeadsUpRemoteInput.getParent()).removeView(mHeadsUpRemoteInput);
+ }
+ }
mHeadsUpChild.animate().cancel();
removeView(mHeadsUpChild);
+ mHeadsUpRemoteInput = null;
+ }
+ if (child == null) {
+ mHeadsUpChild = null;
+ mHeadsUpWrapper = null;
+ if (mVisibleType == VISIBLE_TYPE_HEADSUP) {
+ mVisibleType = VISIBLE_TYPE_CONTRACTED;
+ }
+ if (mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP) {
+ mTransformationStartVisibleType = UNDEFINED;
+ }
+ return;
}
addView(child);
mHeadsUpChild = child;
@@ -623,7 +631,7 @@ public class NotificationContentView extends FrameLayout {
}
public int getMinHeight(boolean likeGroupExpanded) {
- if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded() || mIsLowPriority) {
+ if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
return mContractedChild.getHeight();
} else {
return mSingleLineView.getHeight();
@@ -897,7 +905,7 @@ public class NotificationContentView extends FrameLayout {
height = mContentHeight;
}
int expandedVisualType = getVisualTypeForHeight(height);
- int collapsedVisualType = mIsChildInGroup && !isGroupExpanded() && !mIsLowPriority
+ int collapsedVisualType = mIsChildInGroup && !isGroupExpanded()
? VISIBLE_TYPE_SINGLELINE
: getVisualTypeForHeight(mContainingNotification.getCollapsedHeight());
return mTransformationStartVisibleType == collapsedVisualType
@@ -918,7 +926,7 @@ public class NotificationContentView extends FrameLayout {
if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
return VISIBLE_TYPE_EXPANDED;
}
- if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded() && !mIsLowPriority) {
+ if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
return VISIBLE_TYPE_SINGLELINE;
}
@@ -978,25 +986,37 @@ public class NotificationContentView extends FrameLayout {
return false;
}
- public void setShowingLegacyBackground(boolean showing) {
- mShowingLegacyBackground = showing;
- updateShowingLegacyBackground();
+ public void setLegacy(boolean legacy) {
+ mLegacy = legacy;
+ updateLegacy();
}
- private void updateShowingLegacyBackground() {
+ private void updateLegacy() {
if (mContractedChild != null) {
- mContractedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+ mContractedWrapper.setLegacy(mLegacy);
}
if (mExpandedChild != null) {
- mExpandedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+ mExpandedWrapper.setLegacy(mLegacy);
}
if (mHeadsUpChild != null) {
- mHeadsUpWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+ mHeadsUpWrapper.setLegacy(mLegacy);
}
}
public void setIsChildInGroup(boolean isChildInGroup) {
mIsChildInGroup = isChildInGroup;
+ if (mContractedChild != null) {
+ mContractedWrapper.setIsChildInGroup(mIsChildInGroup);
+ }
+ if (mExpandedChild != null) {
+ mExpandedWrapper.setIsChildInGroup(mIsChildInGroup);
+ }
+ if (mHeadsUpChild != null) {
+ mHeadsUpWrapper.setIsChildInGroup(mIsChildInGroup);
+ }
+ if (mAmbientChild != null) {
+ mAmbientWrapper.setIsChildInGroup(mIsChildInGroup);
+ }
updateSingleLineView();
}
@@ -1005,19 +1025,19 @@ public class NotificationContentView extends FrameLayout {
mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
updateSingleLineView();
if (mContractedChild != null) {
- mContractedWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
+ mContractedWrapper.notifyContentUpdated(entry.row);
}
if (mExpandedChild != null) {
- mExpandedWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
+ mExpandedWrapper.notifyContentUpdated(entry.row);
}
if (mHeadsUpChild != null) {
- mHeadsUpWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
+ mHeadsUpWrapper.notifyContentUpdated(entry.row);
}
if (mAmbientChild != null) {
- mAmbientWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
+ mAmbientWrapper.notifyContentUpdated(entry.row);
}
applyRemoteInput(entry);
- updateShowingLegacyBackground();
+ updateLegacy();
mForceSelectNextLayout = true;
setDark(mDark, false /* animate */, 0 /* delay */);
mPreviousExpandedRemoteInputIntent = null;
@@ -1176,7 +1196,8 @@ public class NotificationContentView extends FrameLayout {
mExpandable = expandable;
// if the expanded child has the same height as the collapsed one we hide it.
if (mExpandedChild != null && mExpandedChild.getHeight() != 0) {
- if (!mIsHeadsUp || mHeadsUpChild == null || mContainingNotification.isOnKeyguard()) {
+ if ((!mIsHeadsUp && !mHeadsUpAnimatingAway)
+ || mHeadsUpChild == null || mContainingNotification.isOnKeyguard()) {
if (mExpandedChild.getHeight() == mContractedChild.getHeight()) {
expandable = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 81db42927682..8f8d966ffff5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -34,6 +34,7 @@ import android.widget.RemoteViews;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -65,7 +66,6 @@ public class NotificationData {
public ExpandableNotificationRow row; // the outer expanded view
private boolean interruption;
public boolean autoRedacted; // whether the redacted notification was generated by us
- public boolean legacy; // whether the notification has a legacy, dark background
public int targetSdk;
private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
public RemoteViews cachedContentView;
@@ -95,118 +95,20 @@ public class NotificationData {
* Resets the notification entry to be re-used.
*/
public void reset() {
- // NOTE: Icon needs to be preserved for now.
- // We should fix this at some point.
- autoRedacted = false;
- legacy = false;
lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
if (row != null) {
row.reset();
}
}
- public View getContentView() {
- return row.getPrivateLayout().getContractedChild();
- }
-
public View getExpandedContentView() {
return row.getPrivateLayout().getExpandedChild();
}
- public View getHeadsUpContentView() {
- return row.getPrivateLayout().getHeadsUpChild();
- }
-
public View getPublicContentView() {
return row.getPublicLayout().getContractedChild();
}
- public View getAmbientContentView() {
- return row.getPrivateLayout().getAmbientChild();
- }
-
- public boolean cacheContentViews(Context ctx, Notification updatedNotification,
- boolean isLowPriority, boolean useIncreasedCollapsedView,
- boolean useIncreasedHeadsUp) {
- boolean applyInPlace = false;
- if (updatedNotification != null) {
- final Notification.Builder updatedNotificationBuilder
- = Notification.Builder.recoverBuilder(ctx, updatedNotification);
- final RemoteViews newContentView = createContentView(updatedNotificationBuilder,
- isLowPriority, useIncreasedCollapsedView);
- final RemoteViews newBigContentView = createBigContentView(
- updatedNotificationBuilder, isLowPriority);
- final RemoteViews newHeadsUpContentView =
- updatedNotificationBuilder.createHeadsUpContentView(useIncreasedHeadsUp);
- final RemoteViews newPublicNotification
- = updatedNotificationBuilder.makePublicContentView();
- final RemoteViews newAmbientNotification
- = updatedNotificationBuilder.makeAmbientNotification();
-
- boolean sameCustomView = Objects.equals(
- notification.getNotification().extras.getBoolean(
- Notification.EXTRA_CONTAINS_CUSTOM_VIEW),
- updatedNotification.extras.getBoolean(
- Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
- applyInPlace = compareRemoteViews(cachedContentView, newContentView)
- && compareRemoteViews(cachedBigContentView, newBigContentView)
- && compareRemoteViews(cachedHeadsUpContentView, newHeadsUpContentView)
- && compareRemoteViews(cachedPublicContentView, newPublicNotification)
- && compareRemoteViews(cachedAmbientContentView, newAmbientNotification)
- && sameCustomView;
- cachedPublicContentView = newPublicNotification;
- cachedHeadsUpContentView = newHeadsUpContentView;
- cachedBigContentView = newBigContentView;
- cachedContentView = newContentView;
- cachedAmbientContentView = newAmbientNotification;
- } else {
- final Notification.Builder builder
- = Notification.Builder.recoverBuilder(ctx, notification.getNotification());
-
- cachedContentView = createContentView(builder, isLowPriority,
- useIncreasedCollapsedView);
- cachedBigContentView = createBigContentView(builder, isLowPriority);
- cachedHeadsUpContentView = builder.createHeadsUpContentView(useIncreasedHeadsUp);
- cachedPublicContentView = builder.makePublicContentView();
- cachedAmbientContentView = builder.makeAmbientNotification();
-
- applyInPlace = false;
- }
- return applyInPlace;
- }
-
- private RemoteViews createBigContentView(Notification.Builder builder,
- boolean isLowPriority) {
- RemoteViews bigContentView = builder.createBigContentView();
- if (bigContentView != null) {
- return bigContentView;
- }
- if (isLowPriority) {
- RemoteViews contentView = builder.createContentView();
- Notification.Builder.makeHeaderExpanded(contentView);
- return contentView;
- }
- return null;
- }
-
- private RemoteViews createContentView(Notification.Builder builder,
- boolean isLowPriority, boolean useLarge) {
- if (isLowPriority) {
- return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
- }
- return builder.createContentView(useLarge);
- }
-
- // Returns true if the RemoteViews are the same.
- private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
- return (a == null && b == null) ||
- (a != null && b != null
- && b.getPackage() != null
- && a.getPackage() != null
- && a.getPackage().equals(b.getPackage())
- && a.getLayoutId() == b.getLayoutId());
- }
-
public void notifyFullScreenIntentLaunched() {
lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
}
@@ -219,13 +121,14 @@ public class NotificationData {
* Create the icons for a notification
* @param context the context to create the icons with
* @param sbn the notification
- * @throws IconException
+ * @throws InflationException
*/
- public void createIcons(Context context, StatusBarNotification sbn) throws IconException {
+ public void createIcons(Context context, StatusBarNotification sbn)
+ throws InflationException {
Notification n = sbn.getNotification();
final Icon smallIcon = n.getSmallIcon();
if (smallIcon == null) {
- throw new IconException("No small icon in notification from "
+ throw new InflationException("No small icon in notification from "
+ sbn.getPackageName());
}
@@ -248,7 +151,7 @@ public class NotificationData {
if (!icon.set(ic) || !expandedIcon.set(ic)) {
icon = null;
expandedIcon = null;
- throw new IconException("Couldn't create icon: " + ic);
+ throw new InflationException("Couldn't create icon: " + ic);
}
expandedIcon.setVisibility(View.INVISIBLE);
expandedIcon.setOnVisibilityChangedListener(
@@ -270,9 +173,9 @@ public class NotificationData {
* Update the notification icons.
* @param context the context to create the icons with.
* @param n the notification to read the icon from.
- * @throws IconException
+ * @throws InflationException
*/
- public void updateIcons(Context context, Notification n) throws IconException {
+ public void updateIcons(Context context, Notification n) throws InflationException {
if (icon != null) {
// Update the icon
final StatusBarIcon ic = new StatusBarIcon(
@@ -285,7 +188,7 @@ public class NotificationData {
icon.setNotification(n);
expandedIcon.setNotification(n);
if (!icon.set(ic) || !expandedIcon.set(ic)) {
- throw new IconException("Couldn't update icon: " + ic);
+ throw new InflationException("Couldn't update icon: " + ic);
}
}
}
@@ -612,10 +515,4 @@ public class NotificationData {
public String getCurrentMediaNotificationKey();
public NotificationGroupManager getGroupManager();
}
-
- public static class IconException extends Exception {
- IconException(String error) {
- super(error);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 970323523904..807d902e4eaf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -72,11 +72,6 @@ public class NotificationInfo extends LinearLayout implements GutsContent {
private StatusBarNotification mStatusBarNotification;
private NotificationChannel mNotificationChannel;
- private ImageView mAutoButton;
- private TextView mImportanceSummary;
- private TextView mImportanceTitle;
- private boolean mAuto;
-
private TextView mNumChannelsView;
private View mChannelDisabledView;
private Switch mChannelEnabledSwitch;
@@ -105,8 +100,10 @@ public class NotificationInfo extends LinearLayout implements GutsContent {
int appUid = -1;
String appName = pkg;
Drawable pkgicon = null;
+ CharSequence channelNameText = "";
+ ApplicationInfo info = null;
try {
- final ApplicationInfo info = pm.getApplicationInfo(pkg,
+ info = pm.getApplicationInfo(pkg,
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
@@ -115,6 +112,7 @@ public class NotificationInfo extends LinearLayout implements GutsContent {
appUid = info.uid;
appName = String.valueOf(pm.getApplicationLabel(info));
pkgicon = pm.getApplicationIcon(info);
+
}
} catch (PackageManager.NameNotFoundException e) {
// app is gone, just show package name and generic icon
@@ -135,11 +133,15 @@ public class NotificationInfo extends LinearLayout implements GutsContent {
R.plurals.notification_num_channels_desc, numChannels), numChannels));
// If this is the placeholder channel, don't use our channel-specific text.
- CharSequence channelNameText;
if (channel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
channelNameText = mContext.getString(R.string.notification_header_default_channel);
} else {
- channelNameText = channel.getName();
+ if (info != null && channel.getNameResId() != 0) {
+ channelNameText = pm.getText(pkg, channel.getNameResId(), info);
+ }
+ if (channel.getName() != null) {
+ channelNameText = channel.getName();
+ }
}
((TextView) findViewById(R.id.pkgname)).setText(appName);
((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
@@ -171,8 +173,8 @@ public class NotificationInfo extends LinearLayout implements GutsContent {
boolean nonBlockable = false;
try {
- final PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
- nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
+ final PackageInfo pkgInfo = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
+ nonBlockable = Utils.isSystemPackage(getResources(), pm, pkgInfo);
} catch (PackageManager.NameNotFoundException e) {
// unlikely.
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 1cd909eaf4be..36ed551ec4bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -443,7 +443,8 @@ public class NotificationShelf extends ActivatableNotificationView {
}
int shelfColor = icon.getStaticDrawableColor();
if (!noIcon && shelfColor != StatusBarIconView.NO_COLOR) {
- int notificationColor = row.getNotificationHeader().getOriginalNotificationColor();
+ int notificationColor
+ = row.getVisibleNotificationHeader().getOriginalNotificationColor();
shelfColor = NotificationUtils.interpolateColors(notificationColor, shelfColor,
iconState.iconAppearAmount);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InflationException.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InflationException.java
new file mode 100644
index 000000000000..b484138d7a66
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InflationException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 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;
+
+/**
+ * An exception that something went wrong during the inflation
+ */
+public class InflationException extends Exception {
+ public InflationException(String error) {
+ super(error);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
index 78b967a35b42..7a34b6e3d2e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
@@ -36,9 +36,9 @@ public class NotificationBigPictureTemplateViewWrapper extends NotificationTempl
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
- super.notifyContentUpdated(notification, isLowPriority);
- updateImageTag(notification);
+ public void notifyContentUpdated(ExpandableNotificationRow row) {
+ super.notifyContentUpdated(row);
+ updateImageTag(row.getStatusBarNotification());
}
private void updateImageTag(StatusBarNotification notification) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
index 39db2434af5f..9476eed8f3f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
@@ -41,11 +41,11 @@ public class NotificationBigTextTemplateViewWrapper extends NotificationTemplate
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
+ public void notifyContentUpdated(ExpandableNotificationRow row) {
// Reinspect the notification. Before the super call, because the super call also updates
// the transformation types and we need to have our values set by then.
- resolveViews(notification);
- super.notifyContentUpdated(notification, isLowPriority);
+ resolveViews(row.getStatusBarNotification());
+ super.notifyContentUpdated(row);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index e5f32df8af7b..3efa29f87450 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -19,13 +19,8 @@ package com.android.systemui.statusbar.notification;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
-import android.graphics.Color;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.service.notification.StatusBarNotification;
-import android.support.v4.graphics.ColorUtils;
import android.view.View;
import com.android.systemui.R;
@@ -40,7 +35,7 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
private final ViewInvertHelper mInvertHelper;
private final Paint mGreyPaint = new Paint();
- private boolean mShowingLegacyBackground;
+ private boolean mIsLegacy;
private int mLegacyColor;
protected NotificationCustomViewWrapper(View view, ExpandableNotificationRow row) {
@@ -55,7 +50,7 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
return;
}
super.setDark(dark, fade, delay);
- if (!mShowingLegacyBackground && mShouldInvertDark) {
+ if (!mIsLegacy && mShouldInvertDark) {
if (fade) {
mInvertHelper.fade(dark, delay);
} else {
@@ -112,15 +107,14 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
@Override
public int getCustomBackgroundColor() {
int customBackgroundColor = super.getCustomBackgroundColor();
- if (customBackgroundColor == 0 && mShowingLegacyBackground) {
+ if (customBackgroundColor == 0 && mIsLegacy) {
return mLegacyColor;
}
return customBackgroundColor;
}
- @Override
- public void setShowingLegacyBackground(boolean showing) {
- super.setShowingLegacyBackground(showing);
- mShowingLegacyBackground = showing;
+ public void setLegacy(boolean legacy) {
+ super.setLegacy(legacy);
+ mIsLegacy = legacy;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index 8eab2e914d86..38e4ec1a4d7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.app.Notification;
import android.content.Context;
import android.graphics.Color;
import android.graphics.ColorFilter;
@@ -26,7 +27,6 @@ import android.graphics.ColorMatrixColorFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
-import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.view.NotificationHeaderView;
import android.view.View;
@@ -71,6 +71,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
private TextView mHeaderText;
private ImageView mWorkProfileImage;
private boolean mIsLowPriority;
+ private boolean mTransformLowPriorityTitle;
protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
super(view, row);
@@ -100,7 +101,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
@Override
protected boolean hasCustomTransformation() {
- return mIsLowPriority;
+ return mIsLowPriority && mTransformLowPriorityTitle;
}
}, TRANSFORMING_VIEW_TITLE);
resolveHeaderViews();
@@ -128,9 +129,10 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
- super.notifyContentUpdated(notification, isLowPriority);
- mIsLowPriority = isLowPriority;
+ public void notifyContentUpdated(ExpandableNotificationRow row) {
+ super.notifyContentUpdated(row);
+ mIsLowPriority = row.isLowPriority();
+ mTransformLowPriorityTitle = !row.isChildInGroup() && !row.isSummaryWithChildren();
ArraySet<View> previousViews = mTransformationHelper.getAllTransformingViews();
// Reinspect the notification.
@@ -139,11 +141,11 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
updateTransformedTypes();
addRemainingTransformTypes();
updateCropToPaddingForImageViews();
- mIcon.setTag(ImageTransformState.ICON_TAG, notification.getNotification().getSmallIcon());
+ Notification notification = row.getStatusBarNotification().getNotification();
+ mIcon.setTag(ImageTransformState.ICON_TAG, notification.getSmallIcon());
// The work profile image is always the same lets just set the icon tag for it not to
// animate
- mWorkProfileImage.setTag(ImageTransformState.ICON_TAG,
- notification.getNotification().getSmallIcon());
+ mWorkProfileImage.setTag(ImageTransformState.ICON_TAG, notification.getSmallIcon());
// We need to reset all views that are no longer transforming in case a view was previously
// transformed, but now we decided to transform its container instead.
@@ -361,6 +363,12 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
}
@Override
+ public void setIsChildInGroup(boolean isChildInGroup) {
+ super.setIsChildInGroup(isChildInGroup);
+ mTransformLowPriorityTitle = !isChildInGroup;
+ }
+
+ @Override
public void setVisible(boolean visible) {
super.setVisible(visible);
mTransformationHelper.setVisible(visible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
new file mode 100644
index 000000000000..66703ee63219
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2017 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;
+
+import android.app.Notification;
+import android.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationContentView;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import java.util.Objects;
+
+/**
+ * A utility that inflates the right kind of contentView based on the state
+ */
+public class NotificationInflater {
+
+ private static final int FLAG_REINFLATE_ALL = ~0;
+ private static final int FLAG_REINFLATE_CONTENT_VIEW = 1<<0;
+ private static final int FLAG_REINFLATE_EXPANDED_VIEW = 1<<1;
+ private static final int FLAG_REINFLATE_HEADS_UP_VIEW = 1<<2;
+ private static final int FLAG_REINFLATE_PUBLIC_VIEW = 1<<3;
+ private static final int FLAG_REINFLATE_AMBIENT_VIEW = 1<<4;
+
+ private final ExpandableNotificationRow mRow;
+ private boolean mIsLowPriority;
+ private boolean mUsesIncreasedHeight;
+ private boolean mUsesIncreasedHeadsUpHeight;
+ private RemoteViews.OnClickHandler mRemoteViewClickHandler;
+ private boolean mIsChildInGroup;
+ private InflationExceptionHandler mInflateExceptionHandler;
+
+ public NotificationInflater(ExpandableNotificationRow row) {
+ mRow = row;
+ }
+
+ public void setIsLowPriority(boolean isLowPriority) {
+ mIsLowPriority = isLowPriority;
+ }
+
+ /**
+ * Set whether the notification is a child in a group
+ *
+ * @return whether the view was re-inflated
+ */
+ public boolean setIsChildInGroup(boolean childInGroup) {
+ if (childInGroup != mIsChildInGroup) {
+ mIsChildInGroup = childInGroup;
+ if (mIsLowPriority) {
+ try {
+ int flags = FLAG_REINFLATE_CONTENT_VIEW | FLAG_REINFLATE_EXPANDED_VIEW;
+ inflateNotificationViews(flags);
+ } catch (InflationException e) {
+ mInflateExceptionHandler.handleInflationException(
+ mRow.getStatusBarNotification(), e);
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public void setUsesIncreasedHeight(boolean usesIncreasedHeight) {
+ mUsesIncreasedHeight = usesIncreasedHeight;
+ }
+
+ public void setUsesIncreasedHeadsUpHeight(boolean usesIncreasedHeight) {
+ mUsesIncreasedHeadsUpHeight = usesIncreasedHeight;
+ }
+
+ public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
+ mRemoteViewClickHandler = remoteViewClickHandler;
+ }
+
+ public void inflateNotificationViews() throws InflationException {
+ inflateNotificationViews(FLAG_REINFLATE_ALL);
+ }
+
+ /**
+ * reinflate all views for the specified flags
+ * @param reInflateFlags flags which views should be reinflated. Use {@link #FLAG_REINFLATE_ALL}
+ * to reinflate all of views.
+ * @throws InflationException
+ */
+ private void inflateNotificationViews(int reInflateFlags)
+ throws InflationException {
+ NotificationData.Entry entry = mRow.getEntry();
+ StatusBarNotification sbn = entry.notification;
+ Context context = mRow.getContext();
+ NotificationContentView privateLayout = mRow.getPrivateLayout();
+ try {
+ final Notification.Builder recoveredBuilder
+ = Notification.Builder.recoverBuilder(context, sbn.getNotification());
+ boolean isLowPriority = mIsLowPriority && !mIsChildInGroup;
+ if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
+ final RemoteViews newContentView = createContentView(recoveredBuilder,
+ isLowPriority, mUsesIncreasedHeadsUpHeight);
+ if (!compareRemoteViews(newContentView,
+ entry.cachedContentView)) {
+ View contentViewLocal = newContentView.apply(
+ sbn.getPackageContext(context),
+ privateLayout,
+ mRemoteViewClickHandler);
+ contentViewLocal.setIsRootNamespace(true);
+ privateLayout.setContractedChild(contentViewLocal);
+ } else {
+ newContentView.reapply(sbn.getPackageContext(context),
+ privateLayout.getContractedChild(),
+ mRemoteViewClickHandler);
+ }
+ entry.cachedContentView = newContentView;
+ }
+
+ if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
+ final RemoteViews newBigContentView = createBigContentView(
+ recoveredBuilder, isLowPriority);
+ if (newBigContentView != null) {
+ if (!compareRemoteViews(newBigContentView, entry.cachedBigContentView)) {
+ View bigContentViewLocal = newBigContentView.apply(
+ sbn.getPackageContext(context),
+ privateLayout,
+ mRemoteViewClickHandler);
+ bigContentViewLocal.setIsRootNamespace(true);
+ privateLayout.setExpandedChild(bigContentViewLocal);
+ } else {
+ newBigContentView.reapply(sbn.getPackageContext(context),
+ privateLayout.getExpandedChild(),
+ mRemoteViewClickHandler);
+ }
+ } else if (entry.cachedBigContentView != null) {
+ privateLayout.setExpandedChild(null);
+ }
+ entry.cachedBigContentView = newBigContentView;
+ mRow.setExpandable(newBigContentView != null);
+ }
+
+ if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
+ final RemoteViews newHeadsUpContentView =
+ recoveredBuilder.createHeadsUpContentView(mUsesIncreasedHeight);
+ if (newHeadsUpContentView != null) {
+ if (!compareRemoteViews(newHeadsUpContentView,
+ entry.cachedHeadsUpContentView)) {
+ View headsUpContentViewLocal = newHeadsUpContentView.apply(
+ sbn.getPackageContext(context),
+ privateLayout,
+ mRemoteViewClickHandler);
+ headsUpContentViewLocal.setIsRootNamespace(true);
+ privateLayout.setHeadsUpChild(headsUpContentViewLocal);
+ } else {
+ newHeadsUpContentView.reapply(sbn.getPackageContext(context),
+ privateLayout.getHeadsUpChild(),
+ mRemoteViewClickHandler);
+ }
+ } else if (entry.cachedHeadsUpContentView != null) {
+ privateLayout.setHeadsUpChild(null);
+ }
+ entry.cachedHeadsUpContentView = newHeadsUpContentView;
+ }
+
+ if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
+ NotificationContentView publicLayout = mRow.getPublicLayout();
+ final RemoteViews newPublicNotification
+ = recoveredBuilder.makePublicContentView();
+ if (!compareRemoteViews(newPublicNotification, entry.cachedPublicContentView)) {
+ View publicContentView = newPublicNotification.apply(
+ sbn.getPackageContext(context),
+ publicLayout,
+ mRemoteViewClickHandler);
+ publicContentView.setIsRootNamespace(true);
+ publicLayout.setContractedChild(publicContentView);
+ } else {
+ newPublicNotification.reapply(sbn.getPackageContext(context),
+ publicLayout.getContractedChild(),
+ mRemoteViewClickHandler);
+ }
+ entry.cachedPublicContentView = newPublicNotification;
+ }
+
+ if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
+ final RemoteViews newAmbientNotification
+ = recoveredBuilder.makeAmbientNotification();
+ if (!compareRemoteViews(newAmbientNotification, entry.cachedAmbientContentView)) {
+ View ambientContentView = newAmbientNotification.apply(
+ sbn.getPackageContext(context),
+ privateLayout,
+ mRemoteViewClickHandler);
+ ambientContentView.setIsRootNamespace(true);
+ privateLayout.setAmbientChild(ambientContentView);
+ } else {
+ newAmbientNotification.reapply(sbn.getPackageContext(context),
+ privateLayout.getAmbientChild(),
+ mRemoteViewClickHandler);
+ }
+ entry.cachedAmbientContentView = newAmbientNotification;
+ }
+
+ } catch (RuntimeException e) {
+ final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
+ Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
+ throw new InflationException("Couldn't inflate contentViews");
+ }
+ }
+
+ private RemoteViews createBigContentView(Notification.Builder builder,
+ boolean isLowPriority) {
+ RemoteViews bigContentView = builder.createBigContentView();
+ if (bigContentView != null) {
+ return bigContentView;
+ }
+ if (isLowPriority) {
+ RemoteViews contentView = builder.createContentView();
+ Notification.Builder.makeHeaderExpanded(contentView);
+ return contentView;
+ }
+ return null;
+ }
+
+ private RemoteViews createContentView(Notification.Builder builder,
+ boolean isLowPriority, boolean useLarge) {
+ if (isLowPriority) {
+ return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
+ }
+ return builder.createContentView(useLarge);
+ }
+
+ // Returns true if the RemoteViews are the same.
+ private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
+ return (a == null && b == null) ||
+ (a != null && b != null
+ && b.getPackage() != null
+ && a.getPackage() != null
+ && a.getPackage().equals(b.getPackage())
+ && a.getLayoutId() == b.getLayoutId());
+ }
+
+ public void setInflateExceptionHandler(InflationExceptionHandler inflateExceptionHandler) {
+ mInflateExceptionHandler = inflateExceptionHandler;
+ }
+
+ public interface InflationExceptionHandler {
+ void handleInflationException(StatusBarNotification notification, InflationException e);
+ }
+ public void onDensityOrFontScaleChanged() {
+ NotificationData.Entry entry = mRow.getEntry();
+ entry.cachedAmbientContentView = null;
+ entry.cachedBigContentView = null;
+ entry.cachedContentView = null;
+ entry.cachedHeadsUpContentView = null;
+ entry.cachedPublicContentView = null;
+ try {
+ inflateNotificationViews();
+ } catch (InflationException e) {
+ mInflateExceptionHandler.handleInflationException(
+ mRow.getStatusBarNotification(), e);
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index 04ee6aa18b37..ef5a25ca5262 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -35,16 +35,16 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
View mActions;
- private void resolveViews(StatusBarNotification notification) {
+ private void resolveViews() {
mActions = mView.findViewById(com.android.internal.R.id.media_actions);
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
+ public void notifyContentUpdated(ExpandableNotificationRow row) {
// Reinspect the notification. Before the super call, because the super call also updates
// the transformation types and we need to have our values set by then.
- resolveViews(notification);
- super.notifyContentUpdated(notification, isLowPriority);
+ resolveViews();
+ super.notifyContentUpdated(row);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
index defeab2c1cc8..9631556e4267 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
@@ -21,7 +21,6 @@ import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.TransformableView;
import android.content.Context;
-import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
@@ -71,11 +70,11 @@ public class NotificationMessagingTemplateViewWrapper extends NotificationTempla
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
+ public void notifyContentUpdated(ExpandableNotificationRow row) {
// Reinspect the notification. Before the super call, because the super call also updates
// the transformation types and we need to have our values set by then.
resolveViews();
- super.notifyContentUpdated(notification, isLowPriority);
+ super.notifyContentUpdated(row);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index e9956ff9f109..846d03ac74dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -133,11 +133,11 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
}
@Override
- public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
+ public void notifyContentUpdated(ExpandableNotificationRow row) {
// Reinspect the notification. Before the super call, because the super call also updates
// the transformation types and we need to have our values set by then.
- resolveTemplateViews(notification);
- super.notifyContentUpdated(notification, isLowPriority);
+ resolveTemplateViews(row.getStatusBarNotification());
+ super.notifyContentUpdated(row);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 5f5e1e46e9d2..c85e8d853b0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -48,6 +48,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
private int mBackgroundColor = 0;
protected boolean mShouldInvertDark;
protected boolean mDarkInitialized = false;
+ private boolean mForcedInvisible;
public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -87,10 +88,9 @@ public abstract class NotificationViewWrapper implements TransformableView {
/**
* Notifies this wrapper that the content of the view might have changed.
- * @param notification the notification this is wrapped around
- * @param isLowPriority is this notification low priority
+ * @param row the row this wrapper is attached to
*/
- public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
+ public void notifyContentUpdated(ExpandableNotificationRow row) {
mDarkInitialized = false;
Drawable background = mView.getBackground();
if (shouldClearBackgroundOnReapply()) {
@@ -185,7 +185,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor;
}
- public void setShowingLegacyBackground(boolean showing) {
+ public void setLegacy(boolean legacy) {
}
public void setContentHeight(int contentHeight, int minHeightHint) {
@@ -193,4 +193,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
public void setRemoteInputVisible(boolean visible) {
}
+
+ public void setIsChildInGroup(boolean isChildInGroup) {
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 31cfa66db689..cd9a49dabbbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -19,6 +19,8 @@ import android.os.Handler;
import android.os.Looper;
import android.provider.Settings.Secure;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.NightDisplayController;
import com.android.systemui.Dependency;
import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
@@ -64,6 +66,11 @@ public class AutoTileManager {
if (!Prefs.getBoolean(context, Key.QS_WORK_ADDED, false)) {
Dependency.get(ManagedProfileController.class).addCallback(mProfileCallback);
}
+
+ if (!Prefs.getBoolean(context, Key.QS_NIGHTDISPLAY_ADDED, false)
+ && NightDisplayController.isAvailable(mContext)) {
+ Dependency.get(NightDisplayController.class).setListener(mNightDisplayCallback);
+ }
}
public void destroy() {
@@ -71,6 +78,7 @@ public class AutoTileManager {
Dependency.get(HotspotController.class).removeCallback(mHotspotCallback);
Dependency.get(DataSaverController.class).removeCallback(mDataSaverListener);
Dependency.get(ManagedProfileController.class).removeCallback(mProfileCallback);
+ Dependency.get(NightDisplayController.class).setListener(null);
}
private final ManagedProfileController.Callback mProfileCallback =
@@ -115,4 +123,30 @@ public class AutoTileManager {
}
}
};
+
+ @VisibleForTesting
+ final NightDisplayController.Callback mNightDisplayCallback =
+ new NightDisplayController.Callback() {
+ @Override
+ public void onActivated(boolean activated) {
+ if (activated) {
+ addNightTile();
+ }
+ }
+
+ @Override
+ public void onAutoModeChanged(int autoMode) {
+ if (autoMode == NightDisplayController.AUTO_MODE_CUSTOM
+ || autoMode == NightDisplayController.AUTO_MODE_TWILIGHT) {
+ addNightTile();
+ }
+ }
+
+ private void addNightTile() {
+ mHost.addTile("night");
+ Prefs.putBoolean(mContext, Key.QS_NIGHTDISPLAY_ADDED, true);
+ mHandler.post(() -> Dependency.get(NightDisplayController.class)
+ .setListener(null));
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 2538bdd79b0e..9a49d67d70d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -36,7 +36,6 @@ import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.res.AssetFileDescriptor.AutoCloseOutputStream;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
@@ -64,7 +63,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
@@ -75,7 +73,7 @@ import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
import com.android.systemui.plugins.IntentButtonProvider.IntentButton.IconState;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 3cbac178f9ec..8cad85c35287 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -31,7 +31,7 @@ import android.widget.FrameLayout;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index dc5f98c13c6a..3706dc8242b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -227,6 +227,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
ViewState iconState = mIconStates.get(view);
iconState.initFrom(view);
iconState.alpha = 1.0f;
+ iconState.hidden = false;
}
}
@@ -524,11 +525,5 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
iconColor = ((StatusBarIconView) view).getStaticDrawableColor();
}
}
-
- protected void onYTranslationAnimationFinished(View view) {
- if (hidden) {
- view.setVisibility(INVISIBLE);
- }
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index c0708692cb39..a5590f2c3b08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -43,7 +43,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.keyguard.KeyguardStatusView;
import com.android.settingslib.Utils;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
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 a6b145e07812..53d2d735b14e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -23,6 +23,7 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
+import static com.android.systemui.statusbar.notification.NotificationInflater.InflationExceptionHandler;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
@@ -124,7 +125,6 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.ActivityStarterDelegate;
import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
-import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
@@ -139,7 +139,7 @@ import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.PluginFragmentListener;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeListener;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeOption;
@@ -161,7 +161,6 @@ import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
-import com.android.systemui.statusbar.NotificationContentView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.NotificationGuts;
@@ -172,6 +171,8 @@ import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
@@ -299,7 +300,7 @@ public class StatusBar extends SystemUI implements DemoMode,
"com.android.systemui.statusbar.banner_action_setup";
private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
= "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
- static final String TAG = "StatusBar";
+ public static final String TAG = "StatusBar";
public static final boolean DEBUG = false;
public static final boolean SPEW = false;
public static final boolean DUMPTRUCK = true; // extra dumpsys info
@@ -717,6 +718,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private NotificationIconAreaController mNotificationIconAreaController;
private ConfigurationListener mDensityChangeListener;
+ private InflationExceptionHandler mInflationExceptionHandler = this::handleInflationException;
private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
final int N = array.size();
@@ -1276,12 +1278,11 @@ public class StatusBar extends SystemUI implements DemoMode,
Entry entry = activeNotifications.get(i);
boolean exposedGuts = mNotificationGutsExposed != null
&& entry.row.getGuts() == mNotificationGutsExposed;
- entry.row.reInflateViews();
+ entry.row.onDensityOrFontScaleChanged();
if (exposedGuts) {
mNotificationGutsExposed = entry.row.getGuts();
bindGuts(entry.row, mGutsMenuItem);
}
- inflateViews(entry, mStackScroller);
}
// end old BaseStatusBar.onDensityOrFontScaleChanged().
mScrimController.onDensityOrFontScaleChanged();
@@ -1550,14 +1551,11 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public void addNotification(StatusBarNotification notification, RankingMap ranking,
- Entry oldEntry) {
+ Entry oldEntry) throws InflationException {
if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
mNotificationData.updateRanking(ranking);
Entry shadeEntry = createNotificationViews(notification);
- if (shadeEntry == null) {
- return;
- }
boolean isHeadsUped = shouldPeek(shadeEntry);
if (isHeadsUped) {
mHeadsUpManager.showNotification(shadeEntry);
@@ -1599,6 +1597,10 @@ public class StatusBar extends SystemUI implements DemoMode,
setAreThereNotifications();
}
+ public void handleInflationException(StatusBarNotification notification, InflationException e) {
+ handleNotificationError(notification, e.getMessage());
+ }
+
private boolean shouldSuppressFullScreenIntent(String key) {
if (isDeviceInVrMode()) {
return true;
@@ -1663,10 +1665,17 @@ public class StatusBar extends SystemUI implements DemoMode,
sbn.getOpPkg(),
sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
-
- updateNotification(newSbn, null);
- mKeysKeptForRemoteInput.add(entry.key);
- return;
+ boolean updated = false;
+ try {
+ updateNotification(newSbn, null);
+ updated = true;
+ } catch (InflationException e) {
+ deferRemoval = false;
+ }
+ if (updated) {
+ mKeysKeptForRemoteInput.add(entry.key);
+ return;
+ }
}
if (deferRemoval) {
mLatestRankingMap = ranking;
@@ -1808,15 +1817,6 @@ public class StatusBar extends SystemUI implements DemoMode,
updatePublicContentView(ent, ent.notification);
}
ent.row.setSensitive(sensitive, deviceSensitive);
- if (ent.autoRedacted && ent.legacy) {
- // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
- // for legacy auto redacted notifications.
- if (showingPublic) {
- ent.row.setShowingLegacyBackground(false);
- } else {
- ent.row.setShowingLegacyBackground(true);
- }
- }
if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) {
ExpandableNotificationRow summary = mGroupManager.getGroupSummary(
ent.row.getStatusBarNotification());
@@ -5513,7 +5513,11 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void run() {
for (StatusBarNotification sbn : notifications) {
- addNotification(sbn, currentRanking, null /* oldEntry */);
+ try {
+ addNotification(sbn, currentRanking, null /* oldEntry */);
+ } catch (InflationException e) {
+ handleInflationException(sbn, e);
+ }
}
}
});
@@ -5549,10 +5553,14 @@ public class StatusBar extends SystemUI implements DemoMode,
}
return;
}
- if (isUpdate) {
- updateNotification(sbn, rankingMap);
- } else {
- addNotification(sbn, rankingMap, null /* oldEntry */);
+ try {
+ if (isUpdate) {
+ updateNotification(sbn, rankingMap);
+ } else {
+ addNotification(sbn, rankingMap, null /* oldEntry */);
+ }
+ } catch (InflationException e) {
+ handleInflationException(sbn, e);
}
}
});
@@ -5682,26 +5690,6 @@ public class StatusBar extends SystemUI implements DemoMode,
return mGroupManager;
}
- protected void bindDismissRunnable(final ExpandableNotificationRow row) {
- row.setOnDismissRunnable(() -> performRemoveNotification(row.getStatusBarNotification()));
- }
-
- protected void applyColorsAndBackgrounds(StatusBarNotification sbn,
- NotificationData.Entry entry) {
-
- if (entry.getContentView().getId()
- != com.android.internal.R.id.status_bar_latest_event_content) {
- // Using custom RemoteViews
- if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
- && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
- entry.row.setShowingLegacyBackground(true);
- entry.legacy = true;
- }
- }
-
- entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
- }
-
public boolean isMediaNotification(NotificationData.Entry entry) {
// TODO: confirm that there's a valid media key
return entry.getExpandedContentView() != null &&
@@ -6083,55 +6071,16 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- protected boolean inflateViews(Entry entry, ViewGroup parent) {
+ protected void inflateViews(Entry entry, ViewGroup parent) throws
+ InflationException {
PackageManager pmUser = getPackageManagerForUser(mContext,
entry.notification.getUser().getIdentifier());
final StatusBarNotification sbn = entry.notification;
- boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
- boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn,
- mNotificationData.getImportance(sbn.getKey()));
- boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight && mPanelExpanded;
- try {
- entry.cacheContentViews(mContext, null, isLowPriority, useIncreasedCollapsedHeight,
- useIncreasedHeadsUp);
- } catch (RuntimeException e) {
- Log.e(TAG, "Unable to get notification remote views", e);
- return false;
- }
-
- final RemoteViews contentView = entry.cachedContentView;
- final RemoteViews bigContentView = entry.cachedBigContentView;
- final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
- final RemoteViews publicContentView = entry.cachedPublicContentView;
- final RemoteViews ambientContentView = entry.cachedAmbientContentView;
-
- if (contentView == null) {
- Log.v(TAG, "no contentView for: " + sbn.getNotification());
- return false;
- }
-
- if (DEBUG) {
- Log.v(TAG, "publicContentView: " + publicContentView);
- }
-
ExpandableNotificationRow row;
-
- // Stash away previous user expansion state so we can restore it at
- // the end.
- boolean hasUserChangedExpansion = false;
- boolean userExpanded = false;
- boolean userLocked = false;
-
if (entry.row != null) {
row = entry.row;
- hasUserChangedExpansion = row.hasUserChangedExpansion();
- userExpanded = row.isUserExpanded();
- userLocked = row.isUserLocked();
entry.reset();
- if (hasUserChangedExpansion) {
- row.setUserExpanded(userExpanded);
- }
} else {
// create the row view
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
@@ -6143,6 +6092,8 @@ public class StatusBar extends SystemUI implements DemoMode,
row.setHeadsUpManager(mHeadsUpManager);
row.setRemoteInputController(mRemoteInputController);
row.setOnExpandClickListener(this);
+ row.setRemoteViewClickHandler(mOnClickHandler);
+ row.setInflateExceptionHandler(mInflationExceptionHandler);
// Get the app name.
// Note that Notification.Builder#bindHeaderAppName has similar logic
@@ -6162,86 +6113,19 @@ public class StatusBar extends SystemUI implements DemoMode,
// Do nothing
}
row.setAppName(appname);
+ row.setOnDismissRunnable(() ->
+ performRemoveNotification(row.getStatusBarNotification()));
+ row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ if (ENABLE_REMOTE_INPUT) {
+ row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+ }
}
- bindDismissRunnable(row);
+ boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
row.setIsLowPriority(isLowPriority);
-
- // NB: the large icon is now handled entirely by the template
-
// bind the click event to the content area
- NotificationContentView contentContainer = row.getPrivateLayout();
- NotificationContentView contentContainerPublic = row.getPublicLayout();
-
- row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- if (ENABLE_REMOTE_INPUT) {
- row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
- }
-
mNotificationClicker.register(row, sbn);
- // set up the adaptive layout
- View contentViewLocal = null;
- View bigContentViewLocal = null;
- View headsUpContentViewLocal = null;
- View publicViewLocal = null;
- View ambientViewLocal = null;
- try {
- contentViewLocal = contentView.apply(
- sbn.getPackageContext(mContext),
- contentContainer,
- mOnClickHandler);
- if (bigContentView != null) {
- bigContentViewLocal = bigContentView.apply(
- sbn.getPackageContext(mContext),
- contentContainer,
- mOnClickHandler);
- }
- if (headsUpContentView != null) {
- headsUpContentViewLocal = headsUpContentView.apply(
- sbn.getPackageContext(mContext),
- contentContainer,
- mOnClickHandler);
- }
- if (publicContentView != null) {
- publicViewLocal = publicContentView.apply(
- sbn.getPackageContext(mContext),
- contentContainerPublic, mOnClickHandler);
- }
- if (ambientContentView != null) {
- ambientViewLocal = ambientContentView.apply(
- sbn.getPackageContext(mContext),
- contentContainer, mOnClickHandler);
- }
-
- if (contentViewLocal != null) {
- contentViewLocal.setIsRootNamespace(true);
- contentContainer.setContractedChild(contentViewLocal);
- }
- if (bigContentViewLocal != null) {
- bigContentViewLocal.setIsRootNamespace(true);
- contentContainer.setExpandedChild(bigContentViewLocal);
- }
- if (headsUpContentViewLocal != null) {
- headsUpContentViewLocal.setIsRootNamespace(true);
- contentContainer.setHeadsUpChild(headsUpContentViewLocal);
- }
- if (publicViewLocal != null) {
- publicViewLocal.setIsRootNamespace(true);
- contentContainerPublic.setContractedChild(publicViewLocal);
- }
-
- if (ambientViewLocal != null) {
- ambientViewLocal.setIsRootNamespace(true);
- contentContainer.setAmbientChild(ambientViewLocal);
- }
- }
- catch (RuntimeException e) {
- final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
- Log.e(TAG, "couldn't inflate view for notification " + ident, e);
- return false;
- }
-
// Extract target SDK version.
try {
ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
@@ -6249,25 +6133,20 @@ public class StatusBar extends SystemUI implements DemoMode,
} catch (NameNotFoundException ex) {
Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
}
+ row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
+ && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
+ entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
entry.row = row;
entry.row.setOnActivatedListener(this);
- entry.row.setExpandable(bigContentViewLocal != null);
- applyColorsAndBackgrounds(sbn, entry);
-
- // Restore previous flags.
- if (hasUserChangedExpansion) {
- // Note: setUserExpanded() conveniently ignores calls with
- // userExpanded=true if !isExpandable().
- row.setUserExpanded(userExpanded);
- }
- row.setUserLocked(userLocked);
+ boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn,
+ mNotificationData.getImportance(sbn.getKey()));
+ boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight && mPanelExpanded;
row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
- row.onNotificationUpdated(entry);
- return true;
+ row.updateNotification(entry);
}
/**
@@ -6605,23 +6484,17 @@ public class StatusBar extends SystemUI implements DemoMode,
return entry.notification;
}
- protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
+ protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn)
+ throws InflationException {
if (DEBUG) {
Log.d(TAG, "createNotificationViews(notification=" + sbn);
}
NotificationData.Entry entry = new NotificationData.Entry(sbn);
Dependency.get(LeakDetector.class).trackInstance(entry);
- try {
- entry.createIcons(mContext, sbn);
- } catch (NotificationData.IconException exception) {
- handleNotificationError(sbn, exception.getMessage());
- }
+ entry.createIcons(mContext, sbn);
// Construct the expanded view.
- if (!inflateViews(entry, mStackScroller)) {
- handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
- return null;
- }
+ inflateViews(entry, mStackScroller);
return entry;
}
@@ -6742,7 +6615,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
+ public void updateNotification(StatusBarNotification notification, RankingMap ranking)
+ throws InflationException {
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final String key = notification.getKey();
@@ -6757,56 +6631,16 @@ public class StatusBar extends SystemUI implements DemoMode,
Notification n = notification.getNotification();
mNotificationData.updateRanking(ranking);
- boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(notification,
- mNotificationData.getImportance(notification.getKey()));
- entry.row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
- boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight && mPanelExpanded;
- entry.row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
- boolean applyInPlace;
- try {
- applyInPlace = entry.cacheContentViews(mContext, notification.getNotification(),
- mNotificationData.isAmbient(key), useIncreasedCollapsedHeight,
- useIncreasedHeadsUp);
- } catch (RuntimeException e) {
- Log.e(TAG, "Unable to get notification remote views", e);
- applyInPlace = false;
- }
- boolean shouldPeek = shouldPeek(entry, notification);
- boolean alertAgain = alertAgain(entry, n);
- if (DEBUG) {
- Log.d(TAG, "applyInPlace=" + applyInPlace
- + " shouldPeek=" + shouldPeek
- + " alertAgain=" + alertAgain);
- }
-
final StatusBarNotification oldNotification = entry.notification;
entry.notification = notification;
mGroupManager.onEntryUpdated(entry, oldNotification);
- boolean updateSuccessful = false;
- try {
- if (applyInPlace) {
- if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
- try {
- entry.updateIcons(mContext, n);
- updateNotificationViews(entry, notification);
- updateSuccessful = true;
- } catch (RuntimeException e) {
- // It failed to apply cleanly.
- Log.w(TAG, "Couldn't reapply views for package " +
- notification.getPackageName(), e);
- }
- }
- if (!updateSuccessful) {
- entry.updateIcons(mContext, n);
- if (!inflateViews(entry, mStackScroller)) {
- handleNotificationError(notification, "Couldn't update remote views for: "
- + notification);
- }
- }
- } catch (NotificationData.IconException e) {
- handleNotificationError(notification, e.getMessage());
- }
+ entry.updateIcons(mContext, n);
+ inflateViews(entry, mStackScroller);
+
+ boolean shouldPeek = shouldPeek(entry, notification);
+ boolean alertAgain = alertAgain(entry, n);
+
updateHeadsUp(key, entry, shouldPeek, alertAgain);
updateNotifications();
@@ -6821,44 +6655,9 @@ public class StatusBar extends SystemUI implements DemoMode,
boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
}
-
setAreThereNotifications();
}
- private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
- final RemoteViews contentView = entry.cachedContentView;
- final RemoteViews bigContentView = entry.cachedBigContentView;
- final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
- final RemoteViews publicContentView = entry.cachedPublicContentView;
- final RemoteViews ambientContentView = entry.cachedAmbientContentView;
-
- // Reapply the RemoteViews
- contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
- if (bigContentView != null && entry.getExpandedContentView() != null) {
- bigContentView.reapply(sbn.getPackageContext(mContext),
- entry.getExpandedContentView(),
- mOnClickHandler);
- }
- View headsUpChild = entry.getHeadsUpContentView();
- if (headsUpContentView != null && headsUpChild != null) {
- headsUpContentView.reapply(sbn.getPackageContext(mContext),
- headsUpChild, mOnClickHandler);
- }
- if (publicContentView != null && entry.getPublicContentView() != null) {
- publicContentView.reapply(sbn.getPackageContext(mContext),
- entry.getPublicContentView(), mOnClickHandler);
- }
- if (ambientContentView != null && entry.getAmbientContentView() != null) {
- ambientContentView.reapply(sbn.getPackageContext(mContext),
- entry.getAmbientContentView(), mOnClickHandler);
- }
- // update the contentIntent
- mNotificationClicker.register(entry.row, sbn);
-
- entry.row.onNotificationUpdated(entry);
- entry.row.resetHeight();
- }
-
protected void updatePublicContentView(Entry entry,
StatusBarNotification sbn) {
final RemoteViews publicContentView = entry.cachedPublicContentView;
@@ -6872,10 +6671,7 @@ public class StatusBar extends SystemUI implements DemoMode,
TextView titleView = (TextView) inflatedView.findViewById(android.R.id.title);
if (titleView != null
&& !titleView.getText().toString().equals(notificationHiddenText)) {
- publicContentView.setTextViewText(android.R.id.title, notificationHiddenText);
- publicContentView.reapply(sbn.getPackageContext(mContext),
- inflatedView, mOnClickHandler);
- entry.row.onNotificationUpdated(entry);
+ titleView.setText(notificationHiddenText);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index 821e6358972c..a87b50a4a8df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -116,19 +116,20 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback
}
private void notifyKeyguardChanged() {
- mCallbacks.forEach(Callback::onKeyguardShowingChanged);
+ // Copy the list to allow removal during callback.
+ new ArrayList<Callback>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
}
public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
mKeyguardFadingAway = true;
mKeyguardFadingAwayDelay = delay;
mKeyguardFadingAwayDuration = fadeoutDuration;
- mCallbacks.forEach(Callback::onKeyguardShowingChanged);
+ notifyKeyguardChanged();
}
public void notifyKeyguardDoneFading() {
mKeyguardFadingAway = false;
- mCallbacks.forEach(Callback::onKeyguardShowingChanged);
+ notifyKeyguardChanged();
}
@Override
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 51d931e28720..bc3eec9795f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -39,6 +39,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.MathUtils;
+import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.PhoneConstants;
@@ -78,6 +79,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
private static final int EMERGENCY_FIRST_CONTROLLER = 100;
private static final int EMERGENCY_VOICE_CONTROLLER = 200;
private static final int EMERGENCY_NO_SUB = 300;
+ private static final int EMERGENCY_ASSUMED_VOICE_CONTROLLER = 400;
private final Context mContext;
private final TelephonyManager mPhone;
@@ -99,8 +101,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
final EthernetSignalController mEthernetSignalController;
@VisibleForTesting
- final Map<Integer, MobileSignalController> mMobileSignalControllers =
- new HashMap<Integer, MobileSignalController>();
+ final SparseArray<MobileSignalController> mMobileSignalControllers = new SparseArray<>();
// When no SIMs are around at setup, and one is added later, it seems to default to the first
// SIM for most actions. This may be null if there aren't any SIMs around.
private MobileSignalController mDefaultSignalController;
@@ -232,7 +233,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
private void registerListeners() {
- for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.registerListener();
}
if (mSubscriptionListener == null) {
@@ -261,7 +263,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
private void unregisterListeners() {
mListening = false;
- for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.unregisterListener();
}
mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener);
@@ -305,7 +308,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
if (DEBUG) Log.e(TAG, "No data sim selected");
return mDefaultSignalController;
}
- if (mMobileSignalControllers.containsKey(dataSubId)) {
+ if (mMobileSignalControllers.indexOfKey(dataSubId) >= 0) {
return mMobileSignalControllers.get(dataSubId);
}
if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + dataSubId);
@@ -326,8 +329,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
int voiceSubId = mSubDefaults.getDefaultVoiceSubId();
if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) {
- for (MobileSignalController mobileSignalController :
- mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
if (!mobileSignalController.getState().isEmergency) {
mEmergencySource = EMERGENCY_FIRST_CONTROLLER
+ mobileSignalController.mSubscriptionInfo.getSubscriptionId();
@@ -336,11 +339,20 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
}
}
- if (mMobileSignalControllers.containsKey(voiceSubId)) {
+ if (mMobileSignalControllers.indexOfKey(voiceSubId) >= 0) {
mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId;
if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId);
return mMobileSignalControllers.get(voiceSubId).getState().isEmergency;
}
+ // If we have the wrong subId but there is only one sim anyway, assume it should be the
+ // default.
+ if (mMobileSignalControllers.size() == 1) {
+ mEmergencySource = EMERGENCY_ASSUMED_VOICE_CONTROLLER
+ + mMobileSignalControllers.keyAt(0);
+ if (DEBUG) Log.d(TAG, "Getting assumed emergency from "
+ + mMobileSignalControllers.keyAt(0));
+ return mMobileSignalControllers.valueAt(0).getState().isEmergency;
+ }
if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
mEmergencySource = EMERGENCY_NO_SUB + voiceSubId;
// Something is wrong, better assume we can't make calls...
@@ -363,7 +375,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
cb.setNoSims(mHasNoSims);
mWifiSignalController.notifyListeners(cb);
mEthernetSignalController.notifyListeners(cb);
- for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.notifyListeners(cb);
}
mCallbackHandler.setListening(cb, true);
@@ -416,7 +429,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
} else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
// Notify every MobileSignalController so they can know whether they are the
// data sim or not.
- for (MobileSignalController controller : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController controller = mMobileSignalControllers.valueAt(i);
controller.handleBroadcast(intent);
}
} else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
@@ -433,7 +447,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
if (SubscriptionManager.isValidSubscriptionId(subId)) {
- if (mMobileSignalControllers.containsKey(subId)) {
+ if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
mMobileSignalControllers.get(subId).handleBroadcast(intent);
} else {
// Can't find this subscription... We must be out of date.
@@ -458,8 +472,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
@VisibleForTesting
void handleConfigurationChanged() {
- for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
- mobileSignalController.setConfiguration(mConfig);
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController controller = mMobileSignalControllers.valueAt(i);
+ controller.setConfiguration(mConfig);
}
refreshLocale();
}
@@ -511,15 +526,20 @@ public class NetworkControllerImpl extends BroadcastReceiver
});
mCurrentSubscriptions = subscriptions;
- HashMap<Integer, MobileSignalController> cachedControllers =
- new HashMap<Integer, MobileSignalController>(mMobileSignalControllers);
+ SparseArray<MobileSignalController> cachedControllers =
+ new SparseArray<MobileSignalController>();
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ cachedControllers.put(mMobileSignalControllers.keyAt(i),
+ mMobileSignalControllers.valueAt(i));
+ }
mMobileSignalControllers.clear();
final int num = subscriptions.size();
for (int i = 0; i < num; i++) {
int subId = subscriptions.get(i).getSubscriptionId();
// If we have a copy of this controller already reuse it, otherwise make a new one.
- if (cachedControllers.containsKey(subId)) {
- mMobileSignalControllers.put(subId, cachedControllers.remove(subId));
+ if (cachedControllers.indexOfKey(subId) >= 0) {
+ mMobileSignalControllers.put(subId, cachedControllers.get(subId));
+ cachedControllers.remove(subId);
} else {
MobileSignalController controller = new MobileSignalController(mContext, mConfig,
mHasMobileDataFeature, mPhone, mCallbackHandler,
@@ -535,7 +555,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
}
if (mListening) {
- for (Integer key : cachedControllers.keySet()) {
+ for (int i = 0; i < cachedControllers.size(); i++) {
+ int key = cachedControllers.keyAt(i);
if (cachedControllers.get(key) == mDefaultSignalController) {
mDefaultSignalController = null;
}
@@ -557,7 +578,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
private void handleSetUserSetupComplete(boolean userSetup) {
mUserSetup = userSetup;
- for (MobileSignalController controller : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController controller = mMobileSignalControllers.valueAt(i);
controller.setUserSetupComplete(mUserSetup);
}
}
@@ -568,7 +590,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
return false;
}
for (SubscriptionInfo info : allSubscriptions) {
- if (!mMobileSignalControllers.containsKey(info.getSubscriptionId())) {
+ if (mMobileSignalControllers.indexOfKey(info.getSubscriptionId()) < 0) {
return false;
}
}
@@ -580,7 +602,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
if (airplaneMode != mAirplaneMode || force) {
mAirplaneMode = airplaneMode;
- for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.setAirplaneMode(mAirplaneMode);
}
notifyListeners();
@@ -601,7 +624,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
*/
private void notifyAllListeners() {
notifyListeners();
- for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.notifyListeners();
}
mWifiSignalController.notifyListeners();
@@ -650,7 +674,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
*/
private void pushConnectivityToSignals() {
// We want to update all the icons, all at once, for any condition change
- for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
}
mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
@@ -682,7 +707,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
pw.print(" mEmergencySource=");
pw.println(emergencyToString(mEmergencySource));
- for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.dump(pw);
}
mWifiSignalController.dump(pw);
@@ -694,6 +720,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
private static final String emergencyToString(int emergencySource) {
if (emergencySource > EMERGENCY_NO_SUB) {
+ return "ASSUMED_VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER)
+ + ")";
+ } else if (emergencySource > EMERGENCY_NO_SUB) {
return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")";
} else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) {
return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")";
@@ -724,7 +753,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
// Update what MobileSignalControllers, because they may change
// to set the number of sim slots.
updateMobileControllers();
- for (MobileSignalController controller : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController controller = mMobileSignalControllers.valueAt(i);
controller.resetLastState();
}
mWifiSignalController.resetLastState();
@@ -747,7 +777,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
connected.set(mWifiSignalController.mTransportType);
}
mWifiSignalController.updateConnectivity(connected, connected);
- for (MobileSignalController controller : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController controller = mMobileSignalControllers.valueAt(i);
if (mDemoInetCondition) {
connected.set(controller.mTransportType);
}
@@ -820,8 +851,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
mCallbackHandler.setSubs(subs);
}
// Hack to index linearly for easy use.
- MobileSignalController controller = mMobileSignalControllers
- .values().toArray(new MobileSignalController[0])[slot];
+ MobileSignalController controller = mMobileSignalControllers.valueAt(slot);
controller.getState().dataSim = datatype != null;
controller.getState().isDefault = datatype != null;
controller.getState().dataConnected = datatype != null;
@@ -875,7 +905,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
String carrierNetworkChange = args.getString("carriernetworkchange");
if (carrierNetworkChange != null) {
boolean show = carrierNetworkChange.equals("show");
- for (MobileSignalController controller : mMobileSignalControllers.values()) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController controller = mMobileSignalControllers.valueAt(i);
controller.setCarrierNetworkChangeMode(show);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 6df4a21807db..a776e995a32e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -59,7 +59,7 @@ import com.android.systemui.SystemUI;
import com.android.systemui.SystemUISecondaryUserService;
import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.tiles.UserDetailView;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.util.NotificationChannels;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index e6a3add627f5..83cbd722703c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -52,6 +52,14 @@ public class NotificationChildrenContainer extends ViewGroup {
private static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2;
private static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
private static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
+ private static final AnimationProperties ALPHA_FADE_IN = new AnimationProperties() {
+ private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
+
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return mAnimationFilter;
+ }
+ }.setDuration(200);
private final List<View> mDividers = new ArrayList<>();
private final List<ExpandableNotificationRow> mChildren = new ArrayList<>();
@@ -64,7 +72,7 @@ public class NotificationChildrenContainer extends ViewGroup {
private float mCollapsedBottompadding;
private ViewInvertHelper mOverflowInvertHelper;
private boolean mChildrenExpanded;
- private ExpandableNotificationRow mNotificationParent;
+ private ExpandableNotificationRow mContainingNotification;
private TextView mOverflowNumber;
private ViewState mGroupOverFlowState;
private int mRealHeight;
@@ -75,10 +83,15 @@ public class NotificationChildrenContainer extends ViewGroup {
private NotificationHeaderView mNotificationHeader;
private NotificationViewWrapper mNotificationHeaderWrapper;
+ private NotificationHeaderView mNotificationHeaderLowPriority;
+ private NotificationViewWrapper mNotificationHeaderWrapperLowPriority;
private NotificationHeaderUtil mHeaderUtil;
private ViewState mHeaderViewState;
private int mClipBottomAmount;
private boolean mIsLowPriority;
+ private boolean mHeaderVisible = true;
+ private OnClickListener mHeaderClickListener;
+ private boolean mShowingNormalHeader;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -135,6 +148,11 @@ public class NotificationChildrenContainer extends ViewGroup {
mNotificationHeader.layout(0, 0, mNotificationHeader.getMeasuredWidth(),
mNotificationHeader.getMeasuredHeight());
}
+ if (mNotificationHeaderLowPriority != null) {
+ mNotificationHeaderLowPriority.layout(0, 0,
+ mNotificationHeaderLowPriority.getMeasuredWidth(),
+ mNotificationHeaderLowPriority.getMeasuredHeight());
+ }
}
@Override
@@ -178,10 +196,14 @@ public class NotificationChildrenContainer extends ViewGroup {
height = Math.min(height, size);
}
+ int headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
if (mNotificationHeader != null) {
- int headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
mNotificationHeader.measure(widthMeasureSpec, headerHeightSpec);
}
+ if (mNotificationHeaderLowPriority != null) {
+ headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
+ mNotificationHeaderLowPriority.measure(widthMeasureSpec, headerHeightSpec);
+ }
setMeasuredDimension(width, height);
}
@@ -247,30 +269,66 @@ public class NotificationChildrenContainer extends ViewGroup {
return mChildren.size();
}
- public void recreateNotificationHeader(OnClickListener listener,
- StatusBarNotification notification) {
+ public void recreateNotificationHeader(OnClickListener listener) {
+ mHeaderClickListener = listener;
+ StatusBarNotification notification = mContainingNotification.getStatusBarNotification();
final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
- mNotificationParent.getStatusBarNotification().getNotification());
- final RemoteViews header = mIsLowPriority
- ? builder.makeLowPriorityContentView(true /* useRegularSubtext */)
- : builder.makeNotificationHeader();
+ notification.getNotification());
+ RemoteViews header = builder.makeNotificationHeader();
if (mNotificationHeader == null) {
mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
final View expandButton = mNotificationHeader.findViewById(
com.android.internal.R.id.expand_button);
expandButton.setVisibility(VISIBLE);
- mNotificationHeader.setOnClickListener(listener);
+ mNotificationHeader.setOnClickListener(mHeaderClickListener);
mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
- mNotificationHeader, mNotificationParent);
+ mNotificationHeader, mContainingNotification);
addView(mNotificationHeader, 0);
invalidate();
} else {
header.reapply(getContext(), mNotificationHeader);
- mNotificationHeaderWrapper.notifyContentUpdated(notification, mIsLowPriority);
}
+ mNotificationHeaderWrapper.notifyContentUpdated(mContainingNotification);
+ recreateLowPriorityHeader(builder);
+ updateHeaderVisibility(false /* animate */);
updateChildrenHeaderAppearance();
}
+ /**
+ * Recreate the low-priority header.
+ *
+ * @param builder a builder to reuse. Otherwise the builder will be recovered.
+ */
+ private void recreateLowPriorityHeader(Notification.Builder builder) {
+ RemoteViews header;
+ StatusBarNotification notification = mContainingNotification.getStatusBarNotification();
+ if (mIsLowPriority) {
+ if (builder == null) {
+ builder = Notification.Builder.recoverBuilder(getContext(),
+ notification.getNotification());
+ }
+ header = builder.makeLowPriorityContentView(true /* useRegularSubtext */);
+ if (mNotificationHeaderLowPriority == null) {
+ mNotificationHeaderLowPriority = (NotificationHeaderView) header.apply(getContext(),
+ this);
+ final View expandButton = mNotificationHeaderLowPriority.findViewById(
+ com.android.internal.R.id.expand_button);
+ expandButton.setVisibility(VISIBLE);
+ mNotificationHeaderLowPriority.setOnClickListener(mHeaderClickListener);
+ mNotificationHeaderWrapperLowPriority = NotificationViewWrapper.wrap(getContext(),
+ mNotificationHeaderLowPriority, mContainingNotification);
+ addView(mNotificationHeaderLowPriority, 0);
+ invalidate();
+ } else {
+ header.reapply(getContext(), mNotificationHeaderLowPriority);
+ }
+ mNotificationHeaderWrapperLowPriority.notifyContentUpdated(mContainingNotification);
+ } else {
+ mNotificationHeaderLowPriority = null;
+ mNotificationHeaderWrapperLowPriority = null;
+ }
+ }
+
public void updateChildrenHeaderAppearance() {
mHeaderUtil.updateChildrenHeaderAppearance();
}
@@ -371,9 +429,6 @@ public class NotificationChildrenContainer extends ViewGroup {
* @return the intrinsic size of this children container, i.e the natural fully expanded state
*/
public int getIntrinsicHeight() {
- if (mIsLowPriority && !mChildrenExpanded) {
- return mNotificationHeader.getHeight();
- }
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
return getIntrinsicHeight(maxAllowedVisibleChildren);
}
@@ -383,6 +438,9 @@ public class NotificationChildrenContainer extends ViewGroup {
* in @param maxAllowedVisibleChildren
*/
private int getIntrinsicHeight(float maxAllowedVisibleChildren) {
+ if (showingAsLowPriority()) {
+ return mNotificationHeaderLowPriority.getHeight();
+ }
int intrinsicHeight = mNotificationHeaderMargin;
int visibleChildren = 0;
int childCount = mChildren.size();
@@ -442,24 +500,25 @@ public class NotificationChildrenContainer extends ViewGroup {
int lastVisibleIndex = maxAllowedVisibleChildren - 1;
int firstOverflowIndex = lastVisibleIndex + 1;
float expandFactor = 0;
+ boolean expandingToExpandedGroup = mUserLocked && !showingAsLowPriority();
if (mUserLocked) {
expandFactor = getGroupExpandFraction();
firstOverflowIndex = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
}
- boolean childrenExpanded = !mNotificationParent.isGroupExpansionChanging()
+ boolean childrenExpanded = !mContainingNotification.isGroupExpansionChanging()
&& mChildrenExpanded;
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
if (!firstChild) {
- if (mUserLocked) {
+ if (expandingToExpandedGroup) {
yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
expandFactor);
} else {
yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
}
} else {
- if (mUserLocked) {
+ if (expandingToExpandedGroup) {
yPosition += NotificationUtils.interpolate(
0,
mNotificatonTopPadding + mDividerHeight,
@@ -478,7 +537,7 @@ public class NotificationChildrenContainer extends ViewGroup {
// When the group is expanded, the children cast the shadows rather than the parent
// so use the parent's elevation here.
childState.zTranslation = childrenExpanded
- ? mNotificationParent.getTranslationZ()
+ ? mContainingNotification.getTranslationZ()
: 0;
childState.dimmed = parentState.dimmed;
childState.dark = parentState.dark;
@@ -487,7 +546,7 @@ public class NotificationChildrenContainer extends ViewGroup {
childState.clipTopAmount = 0;
childState.alpha = 0;
if (i < firstOverflowIndex) {
- childState.alpha = mIsLowPriority && !mChildrenExpanded ? expandFactor : 1.0f;
+ childState.alpha = showingAsLowPriority() ? expandFactor : 1.0f;
} else if (expandFactor == 1.0f && i <= lastVisibleIndex) {
childState.alpha = (mActualHeight - childState.yTranslation) / childState.height;
childState.alpha = Math.max(0.0f, Math.min(1.0f, childState.alpha));
@@ -526,7 +585,7 @@ public class NotificationChildrenContainer extends ViewGroup {
}
mHeaderViewState.initFrom(mNotificationHeader);
mHeaderViewState.zTranslation = childrenExpanded
- ? mNotificationParent.getTranslationZ()
+ ? mContainingNotification.getTranslationZ()
: 0;
}
}
@@ -561,11 +620,11 @@ public class NotificationChildrenContainer extends ViewGroup {
}
private int getMaxAllowedVisibleChildren(boolean likeCollapsed) {
- if (!likeCollapsed && (mChildrenExpanded || mNotificationParent.isUserLocked())) {
+ if (!likeCollapsed && (mChildrenExpanded || mContainingNotification.isUserLocked())) {
return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
}
- if (!mNotificationParent.isOnKeyguard()
- && (mNotificationParent.isExpanded() || mNotificationParent.isHeadsUp())) {
+ if (mIsLowPriority || !mContainingNotification.isOnKeyguard()
+ && (mContainingNotification.isExpanded() || mContainingNotification.isHeadsUp())) {
return NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED;
}
return NUMBER_OF_CHILDREN_WHEN_COLLAPSED;
@@ -578,8 +637,8 @@ public class NotificationChildrenContainer extends ViewGroup {
if (mUserLocked) {
expandFraction = getGroupExpandFraction();
}
- final boolean dividersVisible = mUserLocked
- || mNotificationParent.isGroupExpansionChanging();
+ final boolean dividersVisible = mUserLocked && !showingAsLowPriority()
+ || mContainingNotification.isGroupExpansionChanging();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
ExpandableViewState viewState = state.getViewStateForView(child);
@@ -590,7 +649,7 @@ public class NotificationChildrenContainer extends ViewGroup {
tmpState.initFrom(divider);
tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
- if (mUserLocked && viewState.alpha != 0) {
+ if (mUserLocked && !showingAsLowPriority() && viewState.alpha != 0) {
alpha = NotificationUtils.interpolate(0, 0.5f,
Math.min(viewState.alpha, expandFraction));
}
@@ -612,7 +671,7 @@ public class NotificationChildrenContainer extends ViewGroup {
private void updateChildrenClipping() {
int childCount = mChildren.size();
- int layoutEnd = mNotificationParent.getActualHeight() - mClipBottomAmount;
+ int layoutEnd = mContainingNotification.getActualHeight() - mClipBottomAmount;
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
if (child.getVisibility() == GONE) {
@@ -652,8 +711,8 @@ public class NotificationChildrenContainer extends ViewGroup {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
float expandFraction = getGroupExpandFraction();
- final boolean dividersVisible = mUserLocked
- || mNotificationParent.isGroupExpansionChanging();
+ final boolean dividersVisible = mUserLocked && !showingAsLowPriority()
+ || mContainingNotification.isGroupExpansionChanging();
for (int i = childCount - 1; i >= 0; i--) {
ExpandableNotificationRow child = mChildren.get(i);
ExpandableViewState viewState = state.getViewStateForView(child);
@@ -664,7 +723,7 @@ public class NotificationChildrenContainer extends ViewGroup {
tmpState.initFrom(divider);
tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
- if (mUserLocked && viewState.alpha != 0) {
+ if (mUserLocked && !showingAsLowPriority() && viewState.alpha != 0) {
alpha = NotificationUtils.interpolate(0, 0.5f,
Math.min(viewState.alpha, expandFraction));
}
@@ -718,23 +777,100 @@ public class NotificationChildrenContainer extends ViewGroup {
}
}
- public void setNotificationParent(ExpandableNotificationRow parent) {
- mNotificationParent = parent;
- mHeaderUtil = new NotificationHeaderUtil(mNotificationParent);
+ public void setContainingNotification(ExpandableNotificationRow parent) {
+ mContainingNotification = parent;
+ mHeaderUtil = new NotificationHeaderUtil(mContainingNotification);
}
- public ExpandableNotificationRow getNotificationParent() {
- return mNotificationParent;
+ public ExpandableNotificationRow getContainingNotification() {
+ return mContainingNotification;
}
public NotificationHeaderView getHeaderView() {
return mNotificationHeader;
}
- public void updateHeaderVisibility(int visiblity) {
- if (mNotificationHeader != null) {
- mNotificationHeader.setVisibility(visiblity);
+ public NotificationHeaderView getLowPriorityHeaderView() {
+ return mNotificationHeaderLowPriority;
+ }
+
+ public void setHeaderVisible(boolean visible) {
+ mHeaderVisible = visible;
+ updateHeaderVisibility(false /* animate */);
+ }
+
+ private void updateHeaderVisibility(boolean animate) {
+ NotificationHeaderView visibleHeader = mNotificationHeader;
+ NotificationHeaderView hiddenHeader = mNotificationHeaderLowPriority;
+ boolean normalHeaderVisible = true;
+ if (showingAsLowPriority()) {
+ visibleHeader = mNotificationHeaderLowPriority;
+ hiddenHeader = mNotificationHeader;
+ normalHeaderVisible = false;
+ }
+ if (animate) {
+ if (mHeaderVisible && visibleHeader != null && hiddenHeader != null
+ && mShowingNormalHeader != normalHeaderVisible) {
+ hiddenHeader.setVisibility(VISIBLE);
+ visibleHeader.setVisibility(VISIBLE);
+ NotificationViewWrapper visibleWrapper = getWrapperForView(visibleHeader);
+ NotificationViewWrapper hiddenWrapper = getWrapperForView(hiddenHeader);
+ visibleWrapper.transformFrom(hiddenWrapper);
+ hiddenWrapper.transformTo(visibleWrapper, () -> updateHeaderVisibility(false));
+ startChildAlphaAnimations(normalHeaderVisible);
+ } else {
+ animate = false;
+ }
+ }
+ if (!animate) {
+ if (visibleHeader != null) {
+ getWrapperForView(visibleHeader).setVisible(true);
+ visibleHeader.setVisibility(mHeaderVisible ? VISIBLE : INVISIBLE);
+ }
+ if (hiddenHeader != null) {
+ getWrapperForView(hiddenHeader).setVisible(false);
+ hiddenHeader.setVisibility(INVISIBLE);
+ }
+ }
+ mShowingNormalHeader = normalHeaderVisible;
+ }
+
+ private void startChildAlphaAnimations(boolean toVisible) {
+ float target = toVisible ? 1.0f : 0.0f;
+ float start = 1.0f - target;
+ int childCount = mChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ if (i >= NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED) {
+ break;
+ }
+ ExpandableNotificationRow child = mChildren.get(i);
+ child.setAlpha(start);
+ ViewState viewState = new ViewState();
+ viewState.initFrom(child);
+ viewState.alpha = target;
+ ALPHA_FADE_IN.setDelay(i * 50);
+ viewState.animateTo(child, ALPHA_FADE_IN);
+ }
+ }
+
+
+ private void updateHeaderTransformation() {
+ if (mUserLocked && mHeaderVisible && showingAsLowPriority()) {
+ float fraction = getGroupExpandFraction();
+ mNotificationHeaderWrapper.transformFrom(mNotificationHeaderWrapperLowPriority,
+ fraction);
+ mNotificationHeader.setVisibility(VISIBLE);
+ mNotificationHeaderWrapperLowPriority.transformTo(mNotificationHeaderWrapper,
+ fraction);
+ }
+
+ }
+
+ private NotificationViewWrapper getWrapperForView(NotificationHeaderView visibleHeader) {
+ if (visibleHeader == mNotificationHeader) {
+ return mNotificationHeaderWrapper;
}
+ return mNotificationHeaderWrapperLowPriority;
}
/**
@@ -746,7 +882,7 @@ public class NotificationChildrenContainer extends ViewGroup {
if (mNotificationHeader != null) {
if (expanded) {
ColorDrawable cd = new ColorDrawable();
- cd.setColor(mNotificationParent.calculateBgColor());
+ cd.setColor(mContainingNotification.calculateBgColor());
mNotificationHeader.setHeaderBackgroundDrawable(cd);
} else {
mNotificationHeader.setHeaderBackgroundDrawable(null);
@@ -755,6 +891,10 @@ public class NotificationChildrenContainer extends ViewGroup {
}
public int getMaxContentHeight() {
+ if (showingAsLowPriority()) {
+ return getMinHeight(NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED, true
+ /* likeHighPriority */);
+ }
int maxContentHeight = mNotificationHeaderMargin + mNotificatonTopPadding;
int visibleChildren = 0;
int childCount = mChildren.size();
@@ -781,13 +921,21 @@ public class NotificationChildrenContainer extends ViewGroup {
}
mActualHeight = actualHeight;
float fraction = getGroupExpandFraction();
+ boolean showingLowPriority = showingAsLowPriority();
+ updateHeaderTransformation();
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */);
int childCount = mChildren.size();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
- float childHeight = child.isExpanded(true /* allowOnKeyguard */)
- ? child.getMaxExpandHeight()
- : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
+ float childHeight;
+ if (showingLowPriority) {
+ childHeight = child.getShowingLayout().getMinHeight(false /* likeGroupExpanded */);
+ } else if (child.isExpanded(true /* allowOnKeyguard */)) {
+ childHeight = child.getMaxExpandHeight();
+ } else {
+ childHeight = child.getShowingLayout().getMinHeight(
+ true /* likeGroupExpanded */);
+ }
if (i < maxAllowedVisibleChildren) {
float singleLineHeight = child.getShowingLayout().getMinHeight(
false /* likeGroupExpanded */);
@@ -800,7 +948,8 @@ public class NotificationChildrenContainer extends ViewGroup {
}
public float getGroupExpandFraction() {
- int visibleChildrenExpandedHeight = getVisibleChildrenExpandHeight();
+ int visibleChildrenExpandedHeight = showingAsLowPriority() ? getMaxContentHeight()
+ : getVisibleChildrenExpandHeight();
int minExpandHeight = getCollapsedHeight();
float factor = (mActualHeight - minExpandHeight)
/ (float) (visibleChildrenExpandedHeight - minExpandHeight);
@@ -827,16 +976,23 @@ public class NotificationChildrenContainer extends ViewGroup {
}
public int getMinHeight() {
- return getMinHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED);
+ return getMinHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED, false /* likeHighPriority */);
}
public int getCollapsedHeight() {
- return getMinHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
+ return getMinHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */),
+ false /* likeHighPriority */);
}
- private int getMinHeight(int maxAllowedVisibleChildren) {
- if (mIsLowPriority && !mChildrenExpanded) {
- return mNotificationHeader.getHeight();
+ /**
+ * Get the minimum Height for this group.
+ *
+ * @param maxAllowedVisibleChildren the number of children that should be visible
+ * @param likeHighPriority if the height should be calculated as if it were not low priority
+ */
+ private int getMinHeight(int maxAllowedVisibleChildren, boolean likeHighPriority) {
+ if (!likeHighPriority && showingAsLowPriority()) {
+ return mNotificationHeaderLowPriority.getHeight();
}
int minExpandHeight = mNotificationHeaderMargin;
int visibleChildren = 0;
@@ -859,6 +1015,10 @@ public class NotificationChildrenContainer extends ViewGroup {
return minExpandHeight;
}
+ public boolean showingAsLowPriority() {
+ return mIsLowPriority && !mContainingNotification.isExpanded();
+ }
+
public void setDark(boolean dark, boolean fade, long delay) {
if (mOverflowNumber != null) {
mOverflowInvertHelper.setInverted(dark, fade, delay);
@@ -867,9 +1027,15 @@ public class NotificationChildrenContainer extends ViewGroup {
}
public void reInflateViews(OnClickListener listener, StatusBarNotification notification) {
- removeView(mNotificationHeader);
- mNotificationHeader = null;
- recreateNotificationHeader(listener, notification);
+ if (mNotificationHeader != null) {
+ removeView(mNotificationHeader);
+ mNotificationHeader = null;
+ }
+ if (mNotificationHeaderLowPriority != null) {
+ removeView(mNotificationHeaderLowPriority);
+ mNotificationHeaderLowPriority = null;
+ }
+ recreateNotificationHeader(listener);
initDimens();
for (int i = 0; i < mDividers.size(); i++) {
View prevDivider = mDividers.get(i);
@@ -888,16 +1054,19 @@ public class NotificationChildrenContainer extends ViewGroup {
public void setUserLocked(boolean userLocked) {
mUserLocked = userLocked;
+ if (!mUserLocked) {
+ updateHeaderVisibility(false /* animate */);
+ }
int childCount = mChildren.size();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
- child.setUserLocked(userLocked);
+ child.setUserLocked(userLocked && !showingAsLowPriority());
}
}
public void onNotificationUpdated() {
mHybridGroupManager.setOverflowNumberColor(mOverflowNumber,
- mNotificationParent.getNotificationColor());
+ mContainingNotification.getNotificationColor());
}
public int getPositionInLinearLayout(View childInGroup) {
@@ -926,6 +1095,13 @@ public class NotificationChildrenContainer extends ViewGroup {
header.getIcon().setForceHidden(!iconsVisible);
}
}
+ if (mNotificationHeaderWrapperLowPriority != null) {
+ NotificationHeaderView header
+ = mNotificationHeaderWrapperLowPriority.getNotificationHeader();
+ if (header != null) {
+ header.getIcon().setForceHidden(!iconsVisible);
+ }
+ }
}
public void setClipBottomAmount(int clipBottomAmount) {
@@ -935,5 +1111,36 @@ public class NotificationChildrenContainer extends ViewGroup {
public void setIsLowPriority(boolean isLowPriority) {
mIsLowPriority = isLowPriority;
+ if (mContainingNotification != null) { /* we're not yet set up yet otherwise */
+ recreateLowPriorityHeader(null /* existingBuilder */);
+ updateHeaderVisibility(false /* animate */);
+ }
+ if (mUserLocked) {
+ setUserLocked(mUserLocked);
+ }
+ }
+
+ public NotificationHeaderView getVisibleHeader() {
+ NotificationHeaderView header = mNotificationHeader;
+ if (showingAsLowPriority()) {
+ header = mNotificationHeaderLowPriority;
+ }
+ return header;
+ }
+
+ public void onExpansionChanged() {
+ if (mIsLowPriority) {
+ if (mUserLocked) {
+ setUserLocked(mUserLocked);
+ }
+ updateHeaderVisibility(true /* animate */);
+ }
+ }
+
+ public float getIncreasedPaddingAmount() {
+ if (showingAsLowPriority()) {
+ return 0.0f;
+ }
+ return getGroupExpandFraction();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 48dbe499799b..d3b336bef629 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -3416,6 +3416,7 @@ public class NotificationStackScrollLayout extends ViewGroup
for (View view : mClearOverlayViewsWhenFinished) {
StackStateAnimator.removeFromOverlay(view);
}
+ mClearOverlayViewsWhenFinished.clear();
}
private void runAnimationFinishedRunnables() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index e0a6159c4c03..c8659fb62051 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -136,7 +136,7 @@ public class ViewState {
yTranslation = view.getTranslationY();
zTranslation = view.getTranslationZ();
gone = view.getVisibility() == View.GONE;
- hidden = false;
+ hidden = view.getVisibility() == View.INVISIBLE;
scaleX = view.getScaleX();
scaleY = view.getScaleY();
}
@@ -594,7 +594,7 @@ public class ViewState {
}
protected void onYTranslationAnimationFinished(View view) {
- if (hidden) {
+ if (hidden && !gone) {
view.setVisibility(View.INVISIBLE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 15ad0ce5b51b..59117665b5da 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -36,19 +36,19 @@ public class NotificationChannels extends SystemUI {
nm.createNotificationChannels(Arrays.asList(
new NotificationChannel(
ALERTS,
- context.getString(R.string.notification_channel_alerts),
+ R.string.notification_channel_alerts,
NotificationManager.IMPORTANCE_HIGH),
new NotificationChannel(
SCREENSHOTS,
- context.getString(R.string.notification_channel_screenshot),
+ R.string.notification_channel_screenshot,
NotificationManager.IMPORTANCE_LOW),
new NotificationChannel(
GENERAL,
- context.getString(R.string.notification_channel_general),
+ R.string.notification_channel_general,
NotificationManager.IMPORTANCE_MIN),
new NotificationChannel(
STORAGE,
- context.getString(R.string.notification_channel_storage),
+ R.string.notification_channel_storage,
NotificationManager.IMPORTANCE_LOW)
));
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 0a1d34ff701e..9d0ecec43b30 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -25,7 +25,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.view.WindowManager;
-import com.android.systemui.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.Dependency;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index 09ac5a633cb0..053e5cf2d4c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -76,7 +76,7 @@ public class PluginManagerTest extends SysuiTestCase {
public void testOneShot() {
Plugin mockPlugin = mock(Plugin.class);
when(mMockPluginInstance.getPlugin()).thenReturn(new PluginInfo(null, null, mockPlugin,
- null));
+ null, null));
Plugin result = mPluginManager.getOneShotPlugin("myAction", TestPlugin.class);
assertTrue(result == mockPlugin);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java
index d07cea1dca0e..f016aa1bedf8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java
@@ -52,11 +52,11 @@ public class NotificationCustomViewWrapperTest {
RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.custom_view_dark);
View v = views.apply(mContext, null);
NotificationViewWrapper wrap = NotificationCustomViewWrapper.wrap(mContext, v, mRow);
- wrap.notifyContentUpdated(null, false /* isLowPriority */);
+ wrap.notifyContentUpdated(mRow);
Assert.assertTrue(wrap.getCustomBackgroundColor() != 0);
views.reapply(mContext, v);
- wrap.notifyContentUpdated(null, false /* isLowPriority */);
+ wrap.notifyContentUpdated(mRow);
Assert.assertTrue(wrap.getCustomBackgroundColor() != 0);
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 0491fc40a865..9a3fabbbdfaa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -19,6 +19,8 @@ package com.android.systemui.statusbar;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
@@ -98,6 +100,9 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel = new NotificationChannel(
TEST_CHANNEL, TEST_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
when(mMockStatusBarNotification.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ when(mMockPackageManager.getText(eq(TEST_PACKAGE_NAME),
+ eq(R.string.notification_menu_accessibility), anyObject())).thenReturn(
+ getContext().getString(R.string.notification_menu_accessibility));
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(1);
@@ -178,6 +183,19 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
@UiThreadTest
+ public void testBindNotification_SetsTextChannelName_resId() throws Exception {
+ NotificationChannel notificationChannelResId = new NotificationChannel(
+ TEST_CHANNEL, R.string.notification_menu_accessibility,
+ NotificationManager.IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mMockStatusBarNotification, notificationChannelResId, null, null, null);
+ final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
+ assertEquals(getContext().getString(R.string.notification_menu_accessibility),
+ textView.getText());
+ }
+
+ @Test
+ @UiThreadTest
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
new file mode 100644
index 000000000000..9a477d2b7398
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 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.phone;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import com.android.internal.app.NightDisplayController;
+import com.android.systemui.Prefs;
+import com.android.systemui.Prefs.Key;
+import com.android.systemui.SysUIRunner;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+@RunWith(SysUIRunner.class)
+public class AutoTileManagerTest extends SysuiTestCase {
+
+ private QSTileHost mQsTileHost;
+ private AutoTileManager mAutoTileManager;
+
+ @Before
+ public void setUp() throws Exception {
+ Prefs.putBoolean(mContext, Key.QS_NIGHTDISPLAY_ADDED, false);
+ mQsTileHost = Mockito.mock(QSTileHost.class);
+ mAutoTileManager = new AutoTileManager(mContext, mQsTileHost);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mAutoTileManager = null;
+ }
+
+ @Test
+ public void nightTileAdded_whenActivated() {
+ if (!NightDisplayController.isAvailable(mContext)) {
+ return;
+ }
+ mAutoTileManager.mNightDisplayCallback.onActivated(true);
+ verify(mQsTileHost).addTile("night");
+ }
+
+ @Test
+ public void nightTileNotAdded_whenDeactivated() {
+ if (!NightDisplayController.isAvailable(mContext)) {
+ return;
+ }
+ mAutoTileManager.mNightDisplayCallback.onActivated(false);
+ verify(mQsTileHost, never()).addTile("night");
+ }
+
+ @Test
+ public void nightTileAdded_whenNightModeTwilight() {
+ if (!NightDisplayController.isAvailable(mContext)) {
+ return;
+ }
+ mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
+ NightDisplayController.AUTO_MODE_TWILIGHT);
+ verify(mQsTileHost).addTile("night");
+ }
+
+ @Test
+ public void nightTileAdded_whenNightModeCustom() {
+ if (!NightDisplayController.isAvailable(mContext)) {
+ return;
+ }
+ mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
+ NightDisplayController.AUTO_MODE_CUSTOM);
+ verify(mQsTileHost).addTile("night");
+ }
+
+ @Test
+ public void nightTileNotAdded_whenNightModeDisabled() {
+ if (!NightDisplayController.isAvailable(mContext)) {
+ return;
+ }
+ mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
+ NightDisplayController.AUTO_MODE_DISABLED);
+ verify(mQsTileHost, never()).addTile("night");
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index ba2099928d96..e47f75066dce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -12,6 +12,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import com.android.settingslib.net.DataUsageController;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -106,6 +107,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
TelephonyIcons.QS_DATA_4G);
}
+ @Ignore("Flaky")
@Test
public void testDataDisabledIcon() {
setupNetworkController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 2c0f9c93d353..1555856c1875 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -94,6 +94,14 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
}
@Test
+ public void testNoEmergencyOnlyWrongSubscription() {
+ setupDefaultSignal();
+ setDefaultSubId(42);
+ mNetworkController.recalculateEmergency();
+ verifyEmergencyOnly(false);
+ }
+
+ @Test
public void testNoEmengencyNoSubscriptions() {
setupDefaultSignal();
setSubscriptions();
@@ -286,12 +294,12 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
for (int i = 0; i < testSubscriptions.length; i++) {
if (i == indexToSkipController) {
// Make sure a controller was created despite us not adding one.
- assertTrue(mNetworkController.mMobileSignalControllers.containsKey(
- testSubscriptions[i]));
+ assertTrue(mNetworkController.mMobileSignalControllers.indexOfKey(
+ testSubscriptions[i]) >= 0);
} else if (i == indexToSkipSubscription) {
// Make sure the controller that did exist was removed
- assertFalse(mNetworkController.mMobileSignalControllers.containsKey(
- testSubscriptions[i]));
+ assertFalse(mNetworkController.mMobileSignalControllers.indexOfKey(
+ testSubscriptions[i]) >= 0);
} else {
// If a MobileSignalController is around it needs to not be unregistered.
Mockito.verify(mobileSignalControllers[i], Mockito.never())
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index c1c385aa8207..2b219e637aed 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2157,7 +2157,7 @@ message MetricsEvent {
// ACTION: Settings -> Select summary tab.
// CATEGORY: SETTINGS
- ACTION_SELECT_SUMMARY=476;
+ ACTION_SELECT_SUMMARY = 476;
// ACTION: Settings -> Select support tab.
// CATEGORY: SETTINGS
@@ -2208,7 +2208,7 @@ message MetricsEvent {
NIGHT_DISPLAY_SETTINGS = 488;
// ACTION: Settings -> Storage -> Manage storage -> Click Storage Manager
- // SUBTYPE: false is off, true is on
+ // SUBTYPE: false is off, true is on
ACTION_TOGGLE_STORAGE_MANAGER = 489;
// Settings launched from collapsed quick settings.
@@ -3472,6 +3472,20 @@ message MetricsEvent {
// FIELD: Whether developer mode has already been enabled when clicking build number preference
FIELD_SETTINGS_BUILD_NUMBER_DEVELOPER_MODE_ENABLED = 848;
+ // OPEN: Settings > Wi-Fi > Network Details (click on Access Point)
+ // CATEGORY: SETTINGS
+ // OS: O
+ WIFI_NETWORK_DETAILS = 849;
+
+ // ACTION: Settings > Battery > Menu > Usage Alerts
+ ACTION_SETTINGS_MENU_BATTERY_USAGE_ALERTS = 850;
+
+ // ACTION: Settings > Battery > Menu > Optimization
+ ACTION_SETTINGS_MENU_BATTERY_OPTIMIZATION = 851;
+
+ // ACTION: Settings > Battery > Menu > Apps Toggle
+ ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE = 852;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 02223c1b6d75..5ffb7385fcc3 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -856,6 +856,19 @@ class AlarmManagerService extends SystemService {
mFilterStats = fs;
mAlarmType = alarmType;
}
+
+ @Override
+ public String toString() {
+ return "InFlight{"
+ + "pendingIntent=" + mPendingIntent
+ + ", workSource=" + mWorkSource
+ + ", uid=" + mUid
+ + ", tag=" + mTag
+ + ", broadcastStats=" + mBroadcastStats
+ + ", filterStats=" + mFilterStats
+ + ", alarmType=" + mAlarmType
+ + "}";
+ }
}
static final class FilterStats {
@@ -873,6 +886,19 @@ class AlarmManagerService extends SystemService {
mBroadcastStats = broadcastStats;
mTag = tag;
}
+
+ @Override
+ public String toString() {
+ return "FilterStats{"
+ + "tag=" + mTag
+ + ", lastTime=" + lastTime
+ + ", aggregateTime=" + aggregateTime
+ + ", count=" + count
+ + ", numWakeup=" + numWakeup
+ + ", startTime=" + startTime
+ + ", nesting=" + nesting
+ + "}";
+ }
}
static final class BroadcastStats {
@@ -890,6 +916,19 @@ class AlarmManagerService extends SystemService {
mUid = uid;
mPackageName = packageName;
}
+
+ @Override
+ public String toString() {
+ return "BroadcastStats{"
+ + "uid=" + mUid
+ + ", packageName=" + mPackageName
+ + ", aggregateTime=" + aggregateTime
+ + ", count=" + count
+ + ", numWakeup=" + numWakeup
+ + ", startTime=" + startTime
+ + ", nesting=" + nesting
+ + "}";
+ }
}
final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index b95ed08eeb27..69e481fc9e1c 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -28,6 +28,7 @@ import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
import com.android.internal.inputmethod.InputMethodUtils;
import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.TransferPipe;
@@ -1262,13 +1263,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Bundle extras = new Bundle();
extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
- mImeSwitcherNotification = new Notification.Builder(mContext)
- .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
- .setWhen(0)
- .setOngoing(true)
- .addExtras(extras)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setColor(com.android.internal.R.color.system_notification_accent_color);
+ mImeSwitcherNotification =
+ new Notification.Builder(mContext, SystemNotificationChannels.VIRTUAL_KEYBOARD)
+ .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
+ .setWhen(0)
+ .setOngoing(true)
+ .addExtras(extras)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setColor(com.android.internal.R.color.system_notification_accent_color);
Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index f76ddc71bc01..0a9610f36abb 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -76,6 +76,7 @@ import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
@@ -442,21 +443,20 @@ public class LockSettingsService extends ILockSettings.Stub {
// Suppress all notifications on non-FBE devices for now
if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
- Notification notification = new Notification.Builder(mContext)
- .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
- .setWhen(0)
- .setOngoing(true)
- .setTicker(title)
- .setDefaults(0) // please be quiet
- .setPriority(Notification.PRIORITY_MAX)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(message)
- .setSubText(detail)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setContentIntent(intent)
- .build();
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.SECURITY)
+ .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
+ .setWhen(0)
+ .setOngoing(true)
+ .setTicker(title)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(message)
+ .setSubText(detail)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setContentIntent(intent)
+ .build();
mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
}
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index d54ebaafb5bb..b83dbd686ae5 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -663,12 +663,12 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
@Override
public boolean setActiveScorer(String packageName) {
// Only the system can set the active scorer
- if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
- return mNetworkScorerAppManager.setActiveScorer(packageName);
- } else {
+ if (!isCallerSystemProcess(getCallingUid()) || !callerCanRequestScores()) {
throw new SecurityException(
"Caller is neither the system process nor a score requester.");
}
+
+ return mNetworkScorerAppManager.setActiveScorer(packageName);
}
/**
@@ -732,23 +732,23 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
@Override
public List<NetworkScorerAppData> getAllValidScorers() {
// Only the system can access this data.
- if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
- return mNetworkScorerAppManager.getAllValidScorers();
- } else {
+ if (!isCallerSystemProcess(getCallingUid()) || !callerCanRequestScores()) {
throw new SecurityException(
"Caller is neither the system process nor a score requester.");
}
+
+ return mNetworkScorerAppManager.getAllValidScorers();
}
@Override
public void disableScoring() {
// Only the active scorer or the system should be allowed to disable scoring.
- if (isCallerActiveScorer(getCallingUid()) || callerCanRequestScores()) {
- // no-op for now but we could write to the setting if needed.
- } else {
+ if (!isCallerActiveScorer(getCallingUid()) || !callerCanRequestScores()) {
throw new SecurityException(
"Caller is neither the active scorer nor the scorer manager.");
}
+
+ // no-op for now but we could write to the setting if needed.
}
/** Clear scores. Callers are responsible for checking permissions as appropriate. */
diff --git a/services/core/java/com/android/server/NetworkScorerAppManager.java b/services/core/java/com/android/server/NetworkScorerAppManager.java
index 2f4485a4ea4c..90a33a4a217a 100644
--- a/services/core/java/com/android/server/NetworkScorerAppManager.java
+++ b/services/core/java/com/android/server/NetworkScorerAppManager.java
@@ -85,11 +85,12 @@ public class NetworkScorerAppManager {
}
final ComponentName serviceComponentName =
new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ final String serviceLabel = getRecommendationServiceLabel(serviceInfo, pm);
final ComponentName useOpenWifiNetworksActivity =
findUseOpenWifiNetworksActivity(serviceInfo);
appDataList.add(
new NetworkScorerAppData(serviceInfo.applicationInfo.uid,
- serviceComponentName, useOpenWifiNetworksActivity));
+ serviceComponentName, serviceLabel, useOpenWifiNetworksActivity));
} else {
if (VERBOSE) Log.v(TAG, serviceInfo.packageName
+ " is NOT a valid scorer/recommender.");
@@ -100,6 +101,19 @@ public class NetworkScorerAppManager {
}
@Nullable
+ private String getRecommendationServiceLabel(ServiceInfo serviceInfo, PackageManager pm) {
+ if (serviceInfo.metaData != null) {
+ final String label = serviceInfo.metaData
+ .getString(NetworkScoreManager.RECOMMENDATION_SERVICE_LABEL_META_DATA);
+ if (!TextUtils.isEmpty(label)) {
+ return label;
+ }
+ }
+ CharSequence label = serviceInfo.loadLabel(pm);
+ return label == null ? null : label.toString();
+ }
+
+ @Nullable
private ComponentName findUseOpenWifiNetworksActivity(ServiceInfo serviceInfo) {
if (serviceInfo.metaData == null) {
if (DEBUG) {
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index acacb9e0be70..5115fdecd1bf 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -58,6 +58,7 @@ import java.util.Collections;
import com.android.internal.R;
import com.android.internal.app.DisableCarModeActivity;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.power.ShutdownThread;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
@@ -739,7 +740,8 @@ final class UiModeManagerService extends SystemService {
if (mCarModeEnabled) {
Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class);
- Notification.Builder n = new Notification.Builder(context)
+ Notification.Builder n =
+ new Notification.Builder(context, SystemNotificationChannels.CAR_MODE)
.setSmallIcon(R.drawable.stat_notify_car_mode)
.setDefaults(Notification.DEFAULT_LIGHTS)
.setOngoing(true)
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1b2c75d50014..dc73b6385897 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -92,6 +92,7 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -2780,16 +2781,17 @@ public class AccountManagerService
}
UserHandle user = UserHandle.of(userId);
Context contextForUser = getContextForUser(user);
- Notification n = new Notification.Builder(contextForUser)
- .setSmallIcon(android.R.drawable.stat_sys_warning)
- .setWhen(0)
- .setColor(contextForUser.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(subtitle)
- .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
- PendingIntent.FLAG_CANCEL_CURRENT, null, user))
- .build();
+ Notification n =
+ new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setWhen(0)
+ .setColor(contextForUser.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(subtitle)
+ .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT, null, user))
+ .build();
installNotification(getCredentialPermissionNotificationId(
account, authTokenType, uid), n, packageName, user.getIdentifier());
}
@@ -4844,7 +4846,8 @@ public class AccountManagerService
final String notificationTitleFormat =
contextForUser.getText(R.string.notification_title).toString();
- Notification n = new Notification.Builder(contextForUser)
+ Notification n =
+ new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
.setWhen(0)
.setSmallIcon(android.R.drawable.stat_sys_warning)
.setColor(contextForUser.getColor(
@@ -4864,6 +4867,7 @@ public class AccountManagerService
private void installNotification(int notificationId, final Notification notification,
String packageName, int userId) {
+ SystemNotificationChannels.createAccountChannelForPackage(packageName, mContext);
final long token = clearCallingIdentity();
try {
INotificationManager notificationManager = mInjector.getNotificationManager();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2bc131fae905..b4f8f61971f8 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2810,14 +2810,13 @@ public final class ActiveServices {
}
List<ActivityManager.RunningServiceInfo> getRunningServiceInfoLocked(int maxNum, int flags,
- int callingUid, boolean allowed) {
+ int callingUid, boolean allowed, boolean canInteractAcrossUsers) {
ArrayList<ActivityManager.RunningServiceInfo> res
= new ArrayList<ActivityManager.RunningServiceInfo>();
final long ident = Binder.clearCallingIdentity();
try {
- if (ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, callingUid)
- == PERMISSION_GRANTED) {
+ if (canInteractAcrossUsers) {
int[] users = mAm.mUserController.getUsers();
for (int ui=0; ui<users.length && res.size() < maxNum; ui++) {
ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(users[ui]);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 67cac981f599..88ceb6fa4109 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -47,6 +47,8 @@ import static android.os.Process.PROC_CHAR;
import static android.os.Process.PROC_OUT_LONG;
import static android.os.Process.PROC_PARENS;
import static android.os.Process.PROC_SPACE_TERM;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
import static android.provider.Settings.Global.DEBUG_APP;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
@@ -314,11 +316,13 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
+import com.android.internal.notification.SystemNotificationChannels;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.internal.app.DumpHeapActivity;
import com.android.internal.app.IAppOpsCallback;
@@ -1440,6 +1444,17 @@ public class ActivityManagerService extends IActivityManager.Stub
private final ArraySet<BroadcastQueue> mTmpBroadcastQueue = new ArraySet();
+ /**
+ * A global counter for generating sequence numbers.
+ * This value will be used when incrementing sequence numbers in individual uidRecords.
+ *
+ * Having a global counter ensures that seq numbers are monotonically increasing for a
+ * particular uid even when the uidRecord is re-created.
+ */
+ @GuardedBy("this")
+ @VisibleForTesting
+ long mProcStateSeqCounter = 0;
+
static final class ProcessChangeItem {
static final int CHANGE_ACTIVITIES = 1<<0;
int changes;
@@ -1972,7 +1987,8 @@ public class ActivityManagerService extends IActivityManager.Stub
Context context = mContext.createPackageContext(process.info.packageName, 0);
String text = mContext.getString(R.string.heavy_weight_notification,
context.getApplicationInfo().loadLabel(context.getPackageManager()));
- Notification notification = new Notification.Builder(context)
+ Notification notification =
+ new Notification.Builder(context, SystemNotificationChannels.DEVELOPER)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
@@ -2222,7 +2238,8 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.putExtra(DumpHeapActivity.KEY_DIRECT_LAUNCH, reportPackage);
}
int userId = UserHandle.getUserId(uid);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
@@ -2603,6 +2620,33 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ @VisibleForTesting
+ public ActivityManagerService() {
+ GL_ES_VERSION = 0;
+ mActivityStarter = null;
+ mAppErrors = null;
+ mAppOpsService = null;
+ mBatteryStatsService = null;
+ mCompatModePackages = null;
+ mConstants = null;
+ mGrantFile = null;
+ mHandler = null;
+ mHandlerThread = null;
+ mIntentFirewall = null;
+ mKeyguardController = null;
+ mPermissionReviewRequired = false;
+ mProcessCpuThread = null;
+ mProcessStats = null;
+ mProviderMap = null;
+ mRecentTasks = null;
+ mServices = null;
+ mStackSupervisor = null;
+ mSystemThread = null;
+ mTaskChangeNotificationController = null;
+ mUiHandler = null;
+ mUserController = null;
+ }
+
// Note: This method is invoked on the main thread but may need to attach various
// handlers to other threads. So take care to be explicit about the looper.
public ActivityManagerService(Context systemContext) {
@@ -3028,7 +3072,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final IVoiceInteractionSession session;
if (mLastResumedActivity.task != null
- && mLastResumedActivity.task.voiceSession != null) {
+ && mLastResumedActivity.task.voiceSession != null) {
session = mLastResumedActivity.task.voiceSession;
} else {
session = mLastResumedActivity.voiceSession;
@@ -14395,7 +14439,8 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean dumpClient = false;
boolean dumpCheckin = false;
boolean dumpCheckinFormat = false;
- boolean dumpVisibleStacks = false;
+ boolean dumpVisibleStacksOnly = false;
+ boolean dumpFocusedStackOnly = false;
String dumpPackage = null;
int opti = 0;
@@ -14410,7 +14455,9 @@ public class ActivityManagerService extends IActivityManager.Stub
} else if ("-c".equals(opt)) {
dumpClient = true;
} else if ("-v".equals(opt)) {
- dumpVisibleStacks = true;
+ dumpVisibleStacksOnly = true;
+ } else if ("-f".equals(opt)) {
+ dumpFocusedStackOnly = true;
} else if ("-p".equals(opt)) {
if (opti < args.length) {
dumpPackage = args[opti];
@@ -14601,7 +14648,8 @@ public class ActivityManagerService extends IActivityManager.Stub
LockGuard.dump(fd, pw, args);
} else {
// Dumping a single activity?
- if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll, dumpVisibleStacks)) {
+ if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll, dumpVisibleStacksOnly,
+ dumpFocusedStackOnly)) {
ActivityManagerShellCommand shell = new ActivityManagerShellCommand(this, true);
int res = shell.exec(this, null, fd, null, args, null,
new ResultReceiver(null));
@@ -15540,13 +15588,17 @@ public class ActivityManagerService extends IActivityManager.Stub
* - the cmd arg isn't the flattened component name of an existing activity:
* dump all activity whose component contains the cmd as a substring
* - A hex number of the ActivityRecord object instance.
+ *
+ * @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
+ * @param dumpFocusedStackOnly dump activity with {@param name} only if in the focused stack
*/
protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
- int opti, boolean dumpAll, boolean dumpVisibleStacks) {
+ int opti, boolean dumpAll, boolean dumpVisibleStacksOnly, boolean dumpFocusedStackOnly) {
ArrayList<ActivityRecord> activities;
synchronized (this) {
- activities = mStackSupervisor.getDumpActivitiesLocked(name, dumpVisibleStacks);
+ activities = mStackSupervisor.getDumpActivitiesLocked(name, dumpVisibleStacksOnly,
+ dumpFocusedStackOnly);
}
if (activities.size() <= 0) {
@@ -17506,12 +17558,15 @@ public class ActivityManagerService extends IActivityManager.Stub
public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
int flags) {
enforceNotIsolatedCaller("getServices");
- synchronized (this) {
- final int callingUid = Binder.getCallingUid();
- final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
- callingUid);
- return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid, allowed);
+ final int callingUid = Binder.getCallingUid();
+ final boolean canInteractAcrossUsers = (ActivityManager.checkUidPermission(
+ INTERACT_ACROSS_USERS_FULL, callingUid) == PERMISSION_GRANTED);
+ final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
+ callingUid);
+ synchronized (this) {
+ return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid,
+ allowed, canInteractAcrossUsers);
}
}
@@ -18780,7 +18835,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
- if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueing broadcast: " + intent.getAction()
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
+ " replacePending=" + replacePending);
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
@@ -19088,14 +19143,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (doNext) {
- if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
- String.format("ProcessBroadcast from %s (%s) %s", r.callerPackage,
- r.callerApp == null ? "caller unknown" : r.callerApp.toShortString(),
- r.intent == null ? "" : r.intent.toString()));
- }
r.queue.processNextBroadcast(false);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
trimApplications();
} finally {
@@ -21746,6 +21794,10 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ for (int i = mActiveUids.size() - 1; i >= 0; --i) {
+ incrementProcStateSeqIfNeeded(mActiveUids.valueAt(i));
+ }
+
mNumServiceProcs = mNewNumServiceProcs;
// Now determine the memory trimming level of background processes.
@@ -22095,6 +22147,42 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ /**
+ * If {@link UidRecord#curProcStateSeq} needs to be updated, then increments the global seq
+ * counter {@link #mProcStateSeqCounter} and uses that value for {@param uidRec}.
+ */
+ @VisibleForTesting
+ void incrementProcStateSeqIfNeeded(UidRecord uidRec) {
+ if (uidRec.curProcState != uidRec.setProcState && shouldIncrementProcStateSeq(uidRec)) {
+ uidRec.curProcStateSeq = ++mProcStateSeqCounter;
+ }
+ }
+
+ /**
+ * Checks if {@link UidRecord#curProcStateSeq} needs to be incremented depending on whether
+ * the uid is coming from background to foreground state or vice versa.
+ *
+ * @return Returns true if the uid is coming from background to foreground state or vice versa,
+ * false otherwise.
+ */
+ @VisibleForTesting
+ boolean shouldIncrementProcStateSeq(UidRecord uidRec) {
+ final boolean isAllowedOnRestrictBackground
+ = isProcStateAllowedWhileOnRestrictBackground(uidRec.curProcState);
+ final boolean isAllowedOnDeviceIdleOrPowerSaveMode
+ = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.curProcState);
+
+ final boolean wasAllowedOnRestrictBackground
+ = isProcStateAllowedWhileOnRestrictBackground(uidRec.setProcState);
+ final boolean wasAllowedOnDeviceIdleOrPowerSaveMode
+ = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.setProcState);
+
+ // If the uid is coming from background to foreground or vice versa,
+ // then return true. Otherwise false.
+ return (wasAllowedOnDeviceIdleOrPowerSaveMode != isAllowedOnDeviceIdleOrPowerSaveMode)
+ || (wasAllowedOnRestrictBackground != isAllowedOnRestrictBackground);
+ }
+
final void runInBackgroundDisabled(int uid) {
synchronized (this) {
UidRecord uidRec = mActiveUids.get(uid);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 10055c8d98f7..fa7dd28eb856 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -2019,6 +2019,12 @@ final class ActivityRecord implements AppWindowContainerListener {
// Okay we now are going to make this activity have the new config.
// But then we need to figure out how it needs to deal with that.
+
+ // Find changes between last reported merged configuration and the current one. This is used
+ // to decide whether to relaunch an activity or just report a configuration change.
+ final int changes = getTaskConfigurationChanges(mTmpConfig1);
+
+ // Update last reported values.
final Configuration newGlobalConfig = service.getGlobalConfiguration();
final Configuration newTaskMergedOverrideConfig = task.getMergedOverrideConfiguration();
mTmpConfig1.setTo(mLastReportedConfiguration);
@@ -2026,9 +2032,6 @@ final class ActivityRecord implements AppWindowContainerListener {
mLastReportedConfiguration.setTo(newGlobalConfig);
mLastReportedOverrideConfiguration.setTo(newTaskMergedOverrideConfig);
- int taskChanges = getTaskConfigurationChanges(this, newTaskMergedOverrideConfig,
- mTmpConfig2);
- final int changes = mTmpConfig1.diff(newGlobalConfig) | taskChanges;
if (changes == 0 && !forceNewConfig) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration no differences in " + this);
@@ -2043,8 +2046,7 @@ final class ActivityRecord implements AppWindowContainerListener {
}
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration changes for " + this + " ; taskChanges="
- + Configuration.configurationDiffToString(taskChanges) + ", allChanges="
+ "Configuration changes for " + this + ", allChanges="
+ Configuration.configurationDiffToString(changes));
// If the activity isn't currently running, just leave the new configuration and it will
@@ -2142,40 +2144,27 @@ final class ActivityRecord implements AppWindowContainerListener {
return (changes&(~configChanged)) != 0;
}
- private static int getTaskConfigurationChanges(ActivityRecord record, Configuration taskConfig,
- Configuration oldTaskOverride) {
- // If we went from full-screen to non-full-screen, make sure to use the correct
- // configuration task diff, so the diff stays as small as possible.
- if (Configuration.EMPTY.equals(oldTaskOverride)
- && !Configuration.EMPTY.equals(taskConfig)) {
- oldTaskOverride = record.task.extractOverrideConfig(record.mLastReportedConfiguration);
- }
-
- // Conversely, do the same when going the other direction.
- if (Configuration.EMPTY.equals(taskConfig)
- && !Configuration.EMPTY.equals(oldTaskOverride)) {
- taskConfig = record.task.extractOverrideConfig(record.mLastReportedConfiguration);
- }
-
+ private int getTaskConfigurationChanges(Configuration newTaskConfig) {
// Determine what has changed. May be nothing, if this is a config that has come back from
// the app after going idle. In that case we just want to leave the official config object
// now in the activity and do nothing else.
- int taskChanges = oldTaskOverride.diff(taskConfig, true /* skipUndefined */);
+ final Configuration oldTaskConfig = task.getConfiguration();
+ int taskChanges = oldTaskConfig.diff(newTaskConfig, true /* skipUndefined */);
// We don't want to use size changes if they don't cross boundaries that are important to
// the app.
if ((taskChanges & CONFIG_SCREEN_SIZE) != 0) {
- final boolean crosses = record.crossesHorizontalSizeThreshold(
- oldTaskOverride.screenWidthDp, taskConfig.screenWidthDp)
- || record.crossesVerticalSizeThreshold(
- oldTaskOverride.screenHeightDp, taskConfig.screenHeightDp);
+ final boolean crosses = crossesHorizontalSizeThreshold(oldTaskConfig.screenWidthDp,
+ newTaskConfig.screenWidthDp)
+ || crossesVerticalSizeThreshold(oldTaskConfig.screenHeightDp,
+ newTaskConfig.screenHeightDp);
if (!crosses) {
taskChanges &= ~CONFIG_SCREEN_SIZE;
}
}
if ((taskChanges & CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
- final int oldSmallest = oldTaskOverride.smallestScreenWidthDp;
- final int newSmallest = taskConfig.smallestScreenWidthDp;
- if (!record.crossesSmallestSizeThreshold(oldSmallest, newSmallest)) {
+ final int oldSmallest = oldTaskConfig.smallestScreenWidthDp;
+ final int newSmallest = newTaskConfig.smallestScreenWidthDp;
+ if (!crossesSmallestSizeThreshold(oldSmallest, newSmallest)) {
taskChanges &= ~CONFIG_SMALLEST_SCREEN_SIZE;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 7f7caff5dfb9..827a41e776d8 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3827,7 +3827,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
r.app = null;
r.removeWindowContainer();
final TaskRecord task = r.task;
- if (task != null && task.removeActivity(r)) {
+ final boolean lastActivity = task != null ? task.removeActivity(r) : false;
+
+ if (lastActivity) {
if (DEBUG_STACK) Slog.i(TAG_STACK,
"removeActivityFromHistoryLocked: last activity removed from " + this);
if (mStackSupervisor.isFocusedStack(this) && task == topTask() &&
@@ -4819,7 +4821,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
- ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
+ ArrayList<ActivityRecord> activities = new ArrayList<>();
if ("all".equals(name)) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index ab1559d8afb4..d3ad0572d556 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3521,22 +3521,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
* Dumps the activities matching the given {@param name} in the either the focused stack
* or all visible stacks if {@param dumpVisibleStacks} is true.
*/
- ArrayList<ActivityRecord> getDumpActivitiesLocked(String name, boolean dumpVisibleStacks) {
- if (dumpVisibleStacks) {
+ ArrayList<ActivityRecord> getDumpActivitiesLocked(String name, boolean dumpVisibleStacksOnly,
+ boolean dumpFocusedStackOnly) {
+ if (dumpFocusedStackOnly) {
+ return mFocusedStack.getDumpActivitiesLocked(name);
+ } else {
ArrayList<ActivityRecord> activities = new ArrayList<>();
int numDisplays = mActivityDisplays.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
ActivityStack stack = stacks.get(stackNdx);
- if (stack.getStackVisibilityLocked(null) == STACK_VISIBLE) {
+ if (!dumpVisibleStacksOnly ||
+ stack.getStackVisibilityLocked(null) == STACK_VISIBLE) {
activities.addAll(stack.getDumpActivitiesLocked(name));
}
}
}
return activities;
- } else {
- return mFocusedStack.getDumpActivitiesLocked(name);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index d8c5533811cb..857241afa0a8 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -100,7 +100,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AuxiliaryResolveInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
@@ -509,22 +508,23 @@ class ActivityStarter {
doPendingActivityLaunchesLocked(false);
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
- options, inTask);
+ options, inTask);
}
- /** Creates a launch intent for the given auxiliary resolution data. */
+ /**
+ * Creates a launch intent for the given auxiliary resolution data.
+ */
private @NonNull Intent createLaunchIntent(@NonNull AuxiliaryResolveInfo auxiliaryResponse,
- Intent originalIntent, String callingPackage,
- String resolvedType, int userId) {
+ Intent originalIntent, String callingPackage, String resolvedType, int userId) {
if (auxiliaryResponse.needsPhaseTwo) {
// request phase two resolution
mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
- auxiliaryResponse, originalIntent, resolvedType, callingPackage, userId);
+ auxiliaryResponse, originalIntent, resolvedType, callingPackage, userId);
}
return EphemeralResolver.buildEphemeralInstallerIntent(originalIntent,
- callingPackage, resolvedType, userId, auxiliaryResponse.packageName,
- auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
- auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
+ callingPackage, resolvedType, userId, auxiliaryResponse.packageName,
+ auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
+ auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
}
void postStartActivityProcessing(
@@ -930,14 +930,13 @@ class ActivityStarter {
}
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
int result = START_CANCELED;
try {
mService.mWindowManager.deferSurfaceLayout();
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
- startFlags,
- doResume, options, inTask);
+ startFlags, doResume, options, inTask);
} finally {
// If we are not able to proceed, disassociate the activity from the task. Leaving an
// activity in an incomplete state can lead to issues, such as performing operations
@@ -948,8 +947,8 @@ class ActivityStarter {
mService.mWindowManager.continueSurfaceLayout();
}
- postStartActivityProcessing(r, result, mSupervisor.mFocusedStack.mStackId,
- mSourceRecord, mTargetStack);
+ postStartActivityProcessing(r, result, mSupervisor.mFocusedStack.mStackId, mSourceRecord,
+ mTargetStack);
return result;
}
@@ -1000,11 +999,22 @@ class ActivityStarter {
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| mLaunchSingleInstance || mLaunchSingleTask) {
+ final TaskRecord task = mReusedActivity.task;
+
// In this situation we want to remove all activities from the task up to the one
// being started. In most cases this means we are resetting the task to its initial
// state.
- final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
- mStartActivity, mLaunchFlags);
+ final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
+ mLaunchFlags);
+
+ // The above code can remove {@code mReusedActivity} from the task, leading to the
+ // the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
+ // task reference is needed in the call below to
+ // {@link setTargetStackAndMoveToFrontIfNeeded}.
+ if (mReusedActivity.task == null) {
+ mReusedActivity.task = task;
+ }
+
if (top != null) {
if (top.frontOfTask) {
// Activity aliases may mean we use different intents for the top activity,
@@ -1562,6 +1572,9 @@ class ActivityStarter {
// running, and the caller has asked to clear the current task to have this
// activity at the top.
mAddingToTask = true;
+
+ // We are no longer placing the activity in the task we previously thought we were.
+ mStartActivity.task = null;
// Now pretend like this activity is being started by the top of its task, so it
// is put in the right place.
mSourceRecord = intentActivity;
@@ -1862,7 +1875,7 @@ class ActivityStarter {
final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
try {
startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null,
- null);
+ null);
} catch (Exception e) {
Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
pal.sendErrorResult(e.getMessage());
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index ee2467a925c1..68253c78c78c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.os.Trace;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
@@ -216,12 +217,26 @@ public final class BroadcastQueue {
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
mParallelBroadcasts.add(r);
- r.enqueueClockTime = System.currentTimeMillis();
+ enqueueBroadcastHelper(r);
}
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
mOrderedBroadcasts.add(r);
+ enqueueBroadcastHelper(r);
+ }
+
+ /**
+ * Don't call this method directly; call enqueueParallelBroadcastLocked or
+ * enqueueOrderedBroadcastLocked.
+ */
+ private void enqueueBroadcastHelper(BroadcastRecord r) {
r.enqueueClockTime = System.currentTimeMillis();
+
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
+ System.identityHashCode(r));
+ }
}
public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
@@ -751,7 +766,7 @@ public final class BroadcastQueue {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
+ mQueueName + "]: "
- + mParallelBroadcasts.size() + " broadcasts, "
+ + mParallelBroadcasts.size() + " parallel broadcasts, "
+ mOrderedBroadcasts.size() + " ordered broadcasts");
mService.updateCpuStats();
@@ -765,6 +780,16 @@ public final class BroadcastQueue {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
+
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
+ System.identityHashCode(r));
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
+ System.identityHashCode(r));
+ }
+
final int N = r.receivers.size();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
@@ -915,6 +940,14 @@ public final class BroadcastQueue {
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
+ System.identityHashCode(r));
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
+ System.identityHashCode(r));
+ }
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
+ mQueueName + "] " + r);
}
@@ -1398,6 +1431,12 @@ public final class BroadcastQueue {
}
r.finishTime = SystemClock.uptimeMillis();
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
+ System.identityHashCode(r));
+ }
+
mBroadcastHistory[mHistoryNext] = r;
mHistoryNext = ringAdvance(mHistoryNext, 1, MAX_BROADCAST_HISTORY);
@@ -1456,6 +1495,14 @@ public final class BroadcastQueue {
}
}
+ private String createBroadcastTraceTitle(BroadcastRecord record, int state) {
+ return String.format("Broadcast %s from %s (%s) %s",
+ state == BroadcastRecord.DELIVERY_PENDING ? "in queue" : "dispatched",
+ record.callerPackage == null ? "" : record.callerPackage,
+ record.callerApp == null ? "process unknown" : record.callerApp.toShortString(),
+ record.intent == null ? "" : record.intent.getAction());
+ }
+
final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index f4f6b661c0e1..e0d3abd03988 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -35,6 +35,7 @@ import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ProgressReporter;
import com.android.server.UiThread;
@@ -144,13 +145,13 @@ public abstract class PreBootBroadcaster extends IIntentReceiver.Stub {
contentIntent = null;
}
- final Notification notif = new Notification.Builder(mService.mContext)
+ final Notification notif =
+ new Notification.Builder(mService.mContext,
+ SystemNotificationChannels.UPDATES)
.setSmallIcon(R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
- .setDefaults(0)
- .setPriority(Notification.PRIORITY_MAX)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 82b00da5b809..dfbe59f1c8f2 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -115,7 +115,7 @@ final class ServiceRecord extends Binder {
long destroyTime; // time at which destory was initiated.
String stringName; // caching of toString
-
+
private int lastStartId; // identifier of most recent start request.
static class StartItem {
@@ -203,7 +203,7 @@ final class ServiceRecord extends Binder {
}
}
}
-
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("intent={");
pw.print(intent.getIntent().toShortString(false, true, false, true));
@@ -413,7 +413,7 @@ final class ServiceRecord extends Binder {
restartDelay = 0;
restartTime = 0;
}
-
+
public StartItem findDeliveredStart(int id, boolean remove) {
final int N = deliveredStarts.size();
for (int i=0; i<N; i++) {
@@ -423,10 +423,10 @@ final class ServiceRecord extends Binder {
return si;
}
}
-
+
return null;
}
-
+
public int getLastStartId() {
return lastStartId;
}
@@ -478,7 +478,8 @@ final class ServiceRecord extends Binder {
ctx = ams.mContext.createPackageContextAsUser(
appInfo.packageName, 0, new UserHandle(userId));
- Notification.Builder notiBuilder = new Notification.Builder(ctx);
+ Notification.Builder notiBuilder = new Notification.Builder(ctx,
+ localForegroundNoti.getChannel());
// it's ugly, but it clearly identifies the app
notiBuilder.setSmallIcon(appInfo.icon);
@@ -486,9 +487,6 @@ final class ServiceRecord extends Binder {
// mark as foreground
notiBuilder.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true);
- // we are doing the app a kindness here
- notiBuilder.setPriority(Notification.PRIORITY_MIN);
-
Intent runningIntent = new Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
runningIntent.setData(Uri.fromParts("package",
@@ -541,7 +539,7 @@ final class ServiceRecord extends Binder {
});
}
}
-
+
public void cancelNotification() {
// Do asynchronous communication with notification manager to
// avoid deadlocks.
@@ -588,7 +586,7 @@ final class ServiceRecord extends Binder {
}
});
}
-
+
public void clearDeliveredStartsLocked() {
for (int i=deliveredStarts.size()-1; i>=0; i--) {
deliveredStarts.get(i).removeUriPermissionsLocked();
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index b0513049ff3a..241042452fb1 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1081,11 +1081,13 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
r.onOverrideConfigurationSent();
}
- /** @return true if this was the last activity in the task */
+ /**
+ * @return true if this was the last activity in the task
+ */
boolean removeActivity(ActivityRecord r) {
if (r.task != this) {
throw new IllegalArgumentException(
- "Activity=" + r + " does not belong to task=" + this);
+ "Activity=" + r + " does not belong to task=" + this);
}
r.task = null;
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 302f628edc44..f15543a4255e 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -34,6 +34,12 @@ public final class UidRecord {
boolean setWhitelist;
boolean idle;
int numProcs;
+ /**
+ * Sequence number associated with the {@link #curProcState}. This is incremented using
+ * {@link ActivityManagerService#mProcStateSeqCounter}
+ * when {@link #curProcState} changes from background to foreground or vice versa.
+ */
+ long curProcStateSeq;
static final int CHANGE_PROCSTATE = 0;
static final int CHANGE_GONE = 1;
@@ -83,6 +89,8 @@ public final class UidRecord {
}
sb.append(" procs:");
sb.append(numProcs);
+ sb.append(" curProcStateSeq:");
+ sb.append(curProcStateSeq);
sb.append("}");
return sb.toString();
}
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 42c31b1a6de4..6710bdc3cd2d 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -16,7 +16,6 @@
package com.android.server.am;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -80,10 +79,11 @@ public final class UserState {
}
public void setState(int newState) {
- if (DEBUG_MU) {
- Slog.i(TAG, "User " + mHandle.getIdentifier() + " state changed from "
- + stateToString(state) + " to " + stateToString(newState));
+ if (newState == state) {
+ return;
}
+ Slog.i(TAG, "User " + mHandle.getIdentifier() + " state changed from "
+ + stateToString(state) + " to " + stateToString(newState));
lastState = state;
state = newState;
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index d648dd82dc9a..4404dcf5e01c 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -152,9 +152,11 @@ public final class PlaybackActivityMonitor
synchronized(mPlayerLock) {
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
if (checkConfigurationCaller(piid, apc, binderUid)) {
- apc.getPlayerProxy().applyVolumeShaper(
- DUCK_ID,
- TERMINATE);
+ try {
+ apc.getPlayerProxy().applyVolumeShaper(
+ DUCK_ID,
+ TERMINATE);
+ } catch (Exception e) { /* silent failure, happens happens with binder failure */ }
mPlayers.remove(new Integer(piid));
} else {
Log.e(TAG, "Error releasing player " + piid);
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 68fe5053b585..83751a9c15df 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -32,6 +32,7 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.notification.SystemNotificationChannels;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -187,7 +188,9 @@ public class NetworkNotificationManager {
return;
}
- Notification.Builder builder = new Notification.Builder(mContext)
+ final String channelId = highPriority ? SystemNotificationChannels.NETWORK_ALERTS :
+ SystemNotificationChannels.NETWORK_STATUS;
+ Notification.Builder builder = new Notification.Builder(mContext, channelId)
.setWhen(System.currentTimeMillis())
.setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
.setSmallIcon(icon)
@@ -198,10 +201,6 @@ public class NetworkNotificationManager {
.setContentTitle(title)
.setContentIntent(intent)
.setLocalOnly(true)
- .setPriority(highPriority ?
- Notification.PRIORITY_HIGH :
- Notification.PRIORITY_DEFAULT)
- .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
.setOnlyAlertOnce(true);
if (notifyType == NotificationType.NETWORK_SWITCH) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 6c608a28089d..39e3758393df 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -66,6 +66,7 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.IndentingPrintWriter;
@@ -668,7 +669,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
tethered_notification_message);
if (mTetheredNotificationBuilder == null) {
- mTetheredNotificationBuilder = new Notification.Builder(mContext);
+ mTetheredNotificationBuilder =
+ new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_STATUS);
mTetheredNotificationBuilder.setWhen(0)
.setOngoing(true)
.setColor(mContext.getColor(
@@ -950,6 +952,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
// Events from NetworkCallbacks that we process on the master state
// machine thread on behalf of the UpstreamNetworkMonitor.
static final int EVENT_UPSTREAM_CALLBACK = BASE_MASTER + 5;
+ // we treated the error and want now to clear it
+ static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
private State mInitialState;
private State mTetherModeAliveState;
@@ -1491,6 +1495,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
who.sendMessage(mErrorNotification);
break;
+ case CMD_CLEAR_ERROR:
+ mErrorNotification = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ transitionTo(mInitialState);
+ break;
default:
retValue = false;
}
@@ -1635,6 +1643,12 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
// Not really very much we can do here.
}
+ // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
+ // Thus we give a chance for TetherMasterSM to recover to InitialState
+ // by sending CMD_CLEAR_ERROR
+ if (error == ConnectivityManager.TETHER_ERROR_MASTER_ERROR) {
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
+ }
switch (state) {
case IControlsTethering.STATE_UNAVAILABLE:
case IControlsTethering.STATE_AVAILABLE:
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index b963555124ab..9fc2fc7bb31e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -85,6 +85,7 @@ import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
@@ -1293,17 +1294,16 @@ public class Vpn {
mContext, /* request */ 0, intent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
null, user);
- final Notification.Builder builder = new Notification.Builder(mContext)
- .setDefaults(0)
- .setSmallIcon(R.drawable.vpn_connected)
- .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
- .setContentText(mContext.getString(R.string.vpn_lockdown_config))
- .setContentIntent(configIntent)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setPriority(Notification.PRIORITY_LOW)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setOngoing(true)
- .setColor(mContext.getColor(R.color.system_notification_accent_color));
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.VPN)
+ .setSmallIcon(R.drawable.vpn_connected)
+ .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
+ .setContentText(mContext.getString(R.string.vpn_lockdown_config))
+ .setContentIntent(configIntent)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setOngoing(true)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color));
notificationManager.notifyAsUser(TAG, 0, builder.build(), user);
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 5e5157913f20..710ab33874cd 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -167,7 +167,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
private void maybeLogMessage(State state, int what) {
if (DBG) {
Log.d(TAG, state.getName() + " got " +
- sMagicDecoderRing.get(what, Integer.toString(what)));
+ sMagicDecoderRing.get(what, Integer.toString(what)) + ", Iface = " +
+ mIfaceName);
}
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 4b34eba56e9b..f47a90795fa3 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -297,7 +297,7 @@ public final class ContentService extends IContentService.Stub {
final int pid = Binder.getCallingPid();
userHandle = handleIncomingUser(uri, pid, uid,
- Intent.FLAG_GRANT_READ_URI_PERMISSION, userHandle);
+ Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle);
final String msg = LocalServices.getService(ActivityManagerInternal.class)
.checkContentProviderAccess(uri.getAuthority(), userHandle);
@@ -364,7 +364,7 @@ public final class ContentService extends IContentService.Stub {
final int callingUserHandle = UserHandle.getCallingUserId();
userHandle = handleIncomingUser(uri, pid, uid,
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION, userHandle);
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userHandle);
final String msg = LocalServices.getService(ActivityManagerInternal.class)
.checkContentProviderAccess(uri.getAuthority(), userHandle);
@@ -1144,7 +1144,8 @@ public final class ContentService extends IContentService.Stub {
}
}
- private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, int userId) {
+ private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull,
+ int userId) {
if (userId == UserHandle.USER_CURRENT) {
userId = ActivityManager.getCurrentUser();
}
@@ -1157,8 +1158,24 @@ public final class ContentService extends IContentService.Stub {
} else if (userId != UserHandle.getCallingUserId()) {
if (checkUriPermission(uri, pid, uid, modeFlags,
userId) != PackageManager.PERMISSION_GRANTED) {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
+ boolean allow = false;
+ if (mContext.checkCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ == PackageManager.PERMISSION_GRANTED) {
+ allow = true;
+ } else if (allowNonFull && mContext.checkCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS)
+ == PackageManager.PERMISSION_GRANTED) {
+ allow = true;
+ }
+ if (!allow) {
+ final String permissions = allowNonFull
+ ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " +
+ Manifest.permission.INTERACT_ACROSS_USERS)
+ : Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+ throw new SecurityException(TAG + "Neither user " + uid
+ + " nor current process has " + permissions);
+ }
}
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 5b539ff1976d..bbad493a913f 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -81,6 +81,7 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerInternal;
@@ -3250,7 +3251,8 @@ public class SyncManager {
R.string.contentServiceTooManyDeletesNotificationDesc);
Context contextForUser = getContextForUser(user);
- Notification notification = new Notification.Builder(contextForUser)
+ Notification notification =
+ new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
.setSmallIcon(R.drawable.stat_notify_sync_error)
.setTicker(mContext.getString(R.string.contentServiceSync))
.setWhen(System.currentTimeMillis())
@@ -3460,4 +3462,4 @@ public class SyncManager {
return mContext;
}
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
index 5a1e44574e13..43bb21d2b44a 100644
--- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java
+++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
@@ -68,7 +68,9 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient {
mIsRestricted = restricted;
mOwner = owner;
try {
- token.linkToDeath(this, 0);
+ if (token != null) {
+ token.linkToDeath(this, 0);
+ }
} catch (RemoteException e) {
Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 3793b911a038..297d5bd1afc9 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -23,6 +23,7 @@ import android.os.ShellCallback;
import android.util.Log;
import android.view.Display;
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
import com.android.internal.R;
import com.android.internal.util.Preconditions;
@@ -973,17 +974,17 @@ public class InputManagerService extends IInputManager.Stub
intent, 0, null, UserHandle.CURRENT);
Resources r = mContext.getResources();
- Notification notification = new Notification.Builder(mContext)
- .setContentTitle(r.getString(
- R.string.select_keyboard_layout_notification_title))
- .setContentText(r.getString(
- R.string.select_keyboard_layout_notification_message))
- .setContentIntent(keyboardLayoutIntent)
- .setSmallIcon(R.drawable.ic_settings_language)
- .setPriority(Notification.PRIORITY_LOW)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .build();
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
+ .setContentTitle(r.getString(
+ R.string.select_keyboard_layout_notification_title))
+ .setContentText(r.getString(
+ R.string.select_keyboard_layout_notification_message))
+ .setContentIntent(keyboardLayoutIntent)
+ .setSmallIcon(R.drawable.ic_settings_language)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .build();
mNotificationManager.notifyAsUser(null,
R.string.select_keyboard_layout_notification_title,
notification, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 4a8539aa3282..a5e7d7c7b945 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -47,6 +47,7 @@ import android.util.Slog;
import com.android.internal.R;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.Preconditions;
import com.android.server.ConnectivityService;
import com.android.server.EventLogTags;
@@ -330,18 +331,18 @@ public class LockdownVpnTracker {
}
private void showNotification(int titleRes, int iconRes) {
- final Notification.Builder builder = new Notification.Builder(mContext)
- .setWhen(0)
- .setSmallIcon(iconRes)
- .setContentTitle(mContext.getString(titleRes))
- .setContentText(mContext.getString(R.string.vpn_lockdown_config))
- .setContentIntent(mConfigIntent)
- .setPriority(Notification.PRIORITY_LOW)
- .setOngoing(true)
- .addAction(R.drawable.ic_menu_refresh, mContext.getString(R.string.reset),
- mResetIntent)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.VPN)
+ .setWhen(0)
+ .setSmallIcon(iconRes)
+ .setContentTitle(mContext.getString(titleRes))
+ .setContentText(mContext.getString(R.string.vpn_lockdown_config))
+ .setContentIntent(mConfigIntent)
+ .setOngoing(true)
+ .addAction(R.drawable.ic_menu_refresh, mContext.getString(R.string.reset),
+ mResetIntent)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
NotificationManager.from(mContext).notify(TAG, 0, builder.build());
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index ac3a025a6fc0..507899836ee2 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -58,6 +58,8 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
@@ -169,6 +171,7 @@ import android.util.Xml;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -1067,7 +1070,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
final String tag = buildNotificationTag(policy, type);
- final Notification.Builder builder = new Notification.Builder(mContext);
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_STATUS);
builder.setOnlyAlertOnce(true);
builder.setWhen(0L);
builder.setColor(mContext.getColor(
@@ -1085,7 +1089,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
builder.setContentTitle(title);
builder.setContentText(body);
builder.setDefaults(Notification.DEFAULT_ALL);
- builder.setPriority(Notification.PRIORITY_HIGH);
+ builder.setChannel(SystemNotificationChannels.NETWORK_ALERTS);
final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
builder.setDeleteIntent(PendingIntent.getBroadcast(
@@ -2527,14 +2531,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
- return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
- }
-
- static boolean isProcStateAllowedWhileOnRestrictBackground(int procState) {
- return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
- }
-
void updateRulesForPowerSaveUL() {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerSaveUL");
try {
@@ -2608,8 +2604,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
private void updateRulesForWhitelistedPowerSaveUL(int uid, boolean enabled, int chain) {
if (enabled) {
- if (isWhitelistedBatterySaverUL(uid)
- || isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid))) {
+ if (isWhitelistedBatterySaverUL(uid) || isUidForegroundOnRestrictPowerUL(uid)) {
setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW);
} else {
setUidFirewallRule(chain, uid, FIREWALL_RULE_DEFAULT);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 45ff20bd3a6d..0e767daf76c8 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2736,9 +2736,10 @@ public class NotificationManagerService extends SystemService {
Notification.EXTRA_BUILDER_APPLICATION_INFO);
final Bundle extras = new Bundle();
extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
+ final String channelId = notificationRecord.getChannel().getId();
final Notification summaryNotification =
- new Notification.Builder(getContext()).setSmallIcon(
- adjustedSbn.getNotification().getSmallIcon())
+ new Notification.Builder(getContext(), channelId)
+ .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
.setGroupSummary(true)
.setGroup(GroupHelper.AUTOGROUP_KEY)
.setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
@@ -3049,6 +3050,10 @@ public class NotificationManagerService extends SystemService {
throw new IllegalArgumentException("null not allowed: pkg=" + pkg
+ " id=" + id + " notification=" + notification);
}
+
+ // The system can post notifications for any package, let us resolve that.
+ final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
+
// Fix the notification as best we can.
try {
final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
@@ -3068,13 +3073,13 @@ public class NotificationManagerService extends SystemService {
channelId = (new Notification.TvExtender(notification)).getChannel();
}
final NotificationChannel channel = mRankingHelper.getNotificationChannelWithFallback(pkg,
- callingUid, channelId, false /* includeDeleted */);
+ notificationUid, channelId, false /* includeDeleted */);
final StatusBarNotification n = new StatusBarNotification(
- pkg, opPkg, id, tag, callingUid, callingPid, notification,
+ pkg, opPkg, id, tag, notificationUid, callingPid, notification,
user, null, System.currentTimeMillis());
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
- if (!checkDisqualifyingFeatures(userId, callingUid, id,tag, r)) {
+ if (!checkDisqualifyingFeatures(userId, notificationUid, id,tag, r)) {
return;
}
@@ -3100,6 +3105,19 @@ public class NotificationManagerService extends SystemService {
idOut[0] = id;
}
+ private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
+ // The system can post notifications on behalf of any package it wants
+ if (isCallerSystem() && opPackageName != null && !"android".equals(opPackageName)) {
+ try {
+ return getContext().getPackageManager()
+ .getPackageUidAsUser(opPackageName, userId);
+ } catch (NameNotFoundException e) {
+ /* ignore */
+ }
+ }
+ return callingUid;
+ }
+
/**
* Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
*
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 867af9a4dd2f..e72f7ffea8e3 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -66,6 +66,7 @@ public class RankingHelper implements RankingConfig {
private static final String ATT_VERSION = "version";
private static final String ATT_NAME = "name";
+ private static final String ATT_NAME_RES_ID = "name_res_id";
private static final String ATT_UID = "uid";
private static final String ATT_ID = "id";
private static final String ATT_PRIORITY = "priority";
@@ -201,12 +202,19 @@ public class RankingHelper implements RankingConfig {
if (TAG_CHANNEL.equals(tagName)) {
String id = parser.getAttributeValue(null, ATT_ID);
CharSequence channelName = parser.getAttributeValue(null, ATT_NAME);
+ int channelNameRes = safeInt(parser, ATT_NAME_RES_ID, -1);
int channelImportance =
safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
if (!TextUtils.isEmpty(id)) {
- final NotificationChannel channel = new NotificationChannel(id,
- channelName, channelImportance);
+ NotificationChannel channel;
+ if (channelName != null) {
+ channel = new NotificationChannel(id, channelName,
+ channelImportance);
+ } else {
+ channel = new NotificationChannel(id, channelNameRes,
+ channelImportance);
+ }
channel.populateFromXml(parser);
r.channels.put(id, channel);
}
@@ -286,7 +294,7 @@ public class RankingHelper implements RankingConfig {
NotificationChannel channel;
channel = new NotificationChannel(
NotificationChannel.DEFAULT_CHANNEL_ID,
- mContext.getString(R.string.default_notification_channel_label),
+ R.string.default_notification_channel_label,
r.importance);
channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
channel.setLockscreenVisibility(r.visibility);
@@ -480,7 +488,8 @@ public class RankingHelper implements RankingConfig {
Preconditions.checkNotNull(pkg);
Preconditions.checkNotNull(channel);
Preconditions.checkNotNull(channel.getId());
- Preconditions.checkNotNull(channel.getName());
+ Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName())
+ || channel.getNameResId() != 0);
Record r = getOrCreateRecord(pkg, uid);
if (r == null) {
throw new IllegalArgumentException("Invalid package");
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 55a5f725f90b..0ae5f314d473 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -438,6 +438,7 @@ class InstantAppRegistry {
bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(),
icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
+ icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
icon.draw(canvas);
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index bbd227e5f313..aac04da0c780 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -314,7 +314,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
optimizer.performDexOpt(pkg, libraryDependencies,
null /* ISAs */, false /* checkProfiles */,
getCompilerFilterForReason(compilationReason),
- null /* CompilerStats.PackageStats */);
+ null /* CompilerStats.PackageStats */,
+ mPackageManagerService.getDexManager().isUsedByOtherApps(pkg.packageName));
return commands;
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index b589057ada3e..d9ea7284616d 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -104,7 +104,7 @@ public class PackageDexOptimizer {
*/
int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
String[] instructionSets, boolean checkProfiles, String targetCompilationFilter,
- CompilerStats.PackageStats packageStats) {
+ CompilerStats.PackageStats packageStats, boolean isUsedByOtherApps) {
if (!canOptimizePackage(pkg)) {
return DEX_OPT_SKIPPED;
}
@@ -119,7 +119,7 @@ public class PackageDexOptimizer {
}
try {
return performDexOptLI(pkg, sharedLibraries, instructionSets, checkProfiles,
- targetCompilationFilter, packageStats);
+ targetCompilationFilter, packageStats, isUsedByOtherApps);
} finally {
if (useLock) {
mDexoptWakeLock.release();
@@ -135,7 +135,8 @@ public class PackageDexOptimizer {
@GuardedBy("mInstallLock")
private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
String[] targetInstructionSets, boolean checkForProfileUpdates,
- String targetCompilerFilter, CompilerStats.PackageStats packageStats) {
+ String targetCompilerFilter, CompilerStats.PackageStats packageStats,
+ boolean isUsedByOtherApps) {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
@@ -143,7 +144,7 @@ public class PackageDexOptimizer {
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
- targetCompilerFilter, isUsedByOtherApps(pkg));
+ targetCompilerFilter, isUsedByOtherApps);
final boolean profileUpdated = checkForProfileUpdates &&
isProfileUpdated(pkg, sharedGid, compilerFilter);
@@ -477,40 +478,6 @@ public class PackageDexOptimizer {
mSystemReady = true;
}
- /**
- * Returns true if the profiling data collected for the given app indicate
- * that the apps's APK has been loaded by another app.
- * Note that this returns false for all forward-locked apps and apps without
- * any collected profiling data.
- */
- public static boolean isUsedByOtherApps(PackageParser.Package pkg) {
- if (pkg.isForwardLocked()) {
- // Skip the check for forward locked packages since they don't share their code.
- return false;
- }
-
- for (String apkPath : pkg.getAllCodePathsExcludingResourceOnly()) {
- try {
- apkPath = PackageManagerServiceUtils.realpath(new File(apkPath));
- } catch (IOException e) {
- // Log an error but continue without it.
- Slog.w(TAG, "Failed to get canonical path", e);
- continue;
- }
- String useMarker = apkPath.replace('/', '@');
- final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
- for (int i = 0; i < currentUserIds.length; i++) {
- File profileDir =
- Environment.getDataProfilesDeForeignDexDirectory(currentUserIds[i]);
- File foreignUseMark = new File(profileDir, useMarker);
- if (foreignUseMark.exists()) {
- return true;
- }
- }
- }
- return false;
- }
-
private String printDexoptFlags(int flags) {
ArrayList<String> flagsList = new ArrayList<>();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index a7a1683f8479..37f78b40c4ff 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -88,6 +88,7 @@ import libcore.io.IoUtils;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageHelper;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.ImageUtils;
import com.android.internal.util.IndentingPrintWriter;
@@ -1103,7 +1104,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
context.getResources().getDimensionPixelSize(
android.R.dimen.notification_large_icon_height));
CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
- return new Notification.Builder(context)
+ return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(R.drawable.ic_check_circle_24px)
.setColor(context.getResources().getColor(
R.color.system_notification_accent_color))
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1c5675ac010e..fd731c323a74 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -29,6 +29,7 @@ import static com.android.server.pm.PackageInstallerService.prepareExternalStage
import static com.android.server.pm.PackageInstallerService.prepareStageDir;
import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
@@ -45,6 +46,7 @@ import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.Signature;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.FileBridge;
@@ -295,6 +297,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
info.active = mActiveCount.get() > 0;
info.mode = params.mode;
+ info.installReason = params.installReason;
info.sizeBytes = params.sizeBytes;
info.appPackageName = params.appPackageName;
info.appIcon = params.appIcon;
@@ -1139,6 +1142,25 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
+
+ // Send broadcast to default launcher only if it's a new install
+ final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
+ if (success && isNewInstall) {
+ UserManagerService ums = UserManagerService.getInstance();
+ if (ums != null) {
+ final UserInfo parent = ums.getProfileParent(userId);
+ final int launcherUid = (parent != null) ? parent.id : userId;
+ final ComponentName launcherComponent = mPm.getDefaultHomeActivity(launcherUid);
+ if (launcherComponent != null) {
+ Intent launcherIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
+ .putExtra(PackageInstaller.EXTRA_SESSION, generateInfo())
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
+ .setPackage(launcherComponent.getPackageName());
+ mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid));
+ }
+ }
+ }
+
mCallback.onSessionFinished(this, success);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5ebced81ae1d..caacc46a8ebd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -582,7 +582,8 @@ public class PackageManagerService extends IPackageManager.Stub {
Manifest.permission.RECEIVE_MMS,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_NUMBER);
+ Manifest.permission.READ_PHONE_NUMBER,
+ Manifest.permission.ANSWER_PHONE_CALLS);
/**
@@ -745,6 +746,12 @@ public class PackageManagerService extends IPackageManager.Stub {
@GuardedBy("mPackages")
final SparseArray<Map<String, Integer>> mChangedPackagesSequenceNumbers = new SparseArray<>();
+ final PackageParser.Callback mPackageParserCallback = new PackageParser.Callback() {
+ @Override public boolean hasFeature(String feature) {
+ return PackageManagerService.this.hasSystemFeature(feature, 0);
+ }
+ };
+
public static final class SharedLibraryEntry {
public final String path;
public final String apk;
@@ -6317,6 +6324,7 @@ public class PackageManagerService extends IPackageManager.Stub {
ephemeralInstaller.filter = new IntentFilter(intent.getAction());
ephemeralInstaller.filter.addDataPath(
intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
+ ephemeralInstaller.instantAppAvailable = true;
result.add(ephemeralInstaller);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -7310,12 +7318,17 @@ public class PackageManagerService extends IPackageManager.Stub {
return false;
}
- if (!isCallerSameApp(packageName)) {
- return false;
- }
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps != null) {
+ final boolean returnAllowed =
+ ps != null
+ && (isCallerSameApp(packageName)
+ || mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_INSTANT_APPS)
+ == PERMISSION_GRANTED
+ || mInstantAppRegistry.isInstantAccessGranted(
+ userId, UserHandle.getAppId(Binder.getCallingUid()), ps.appId));
+ if (returnAllowed) {
return ps.getInstantApp(userId);
}
}
@@ -7577,7 +7590,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ " flags=0x" + Integer.toHexString(parseFlags));
}
ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
- mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir);
+ mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mPackageParserCallback);
// Submit files for parsing in parallel
int fileCount = 0;
@@ -7746,6 +7759,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
+ pp.setCallback(mPackageParserCallback);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
@@ -8427,11 +8441,13 @@ public class PackageManagerService extends IPackageManager.Stub {
pdo.performDexOpt(depPackage, null /* sharedLibraries */, instructionSets,
false /* checkProfiles */,
getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY),
- getOrCreateCompilerPackageStats(depPackage));
+ getOrCreateCompilerPackageStats(depPackage),
+ mDexManager.isUsedByOtherApps(p.packageName));
}
}
return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets, checkProfiles,
- targetCompilerFilter, getOrCreateCompilerPackageStats(p));
+ targetCompilerFilter, getOrCreateCompilerPackageStats(p),
+ mDexManager.isUsedByOtherApps(p.packageName));
}
// Performs dexopt on the used secondary dex files belonging to the given package.
@@ -8703,6 +8719,7 @@ public class PackageManagerService extends IPackageManager.Stub {
} catch (InstallerException e) {
Slog.w(TAG, String.valueOf(e));
}
+ mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId);
}
}
@@ -9609,7 +9626,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/**
* Asserts the parsed package is valid according to the given policy. If the
- * package is invalid, for whatever reason, throws {@link PackgeManagerException}.
+ * package is invalid, for whatever reason, throws {@link PackageManagerException}.
* <p>
* Implementation detail: This method must NOT have any side effects. It would
* ideally be static, but, it requires locks to read system state.
@@ -12334,6 +12351,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
res.iconResourceId = info.icon;
res.system = res.activityInfo.applicationInfo.isSystemApp();
+ res.instantAppAvailable = userState.instantApp;
return res;
}
@@ -12806,7 +12824,7 @@ public class PackageManagerService extends IPackageManager.Stub {
* By having a field variable, we're able to track filter ordering as soon as
* a non-zero order is defined. Otherwise, multiple loops across the result set
* would be needed to apply ordering. If the intent resolver becomes re-entrant,
- * this needs to be contained entirely within {@link #filterResults()}.
+ * this needs to be contained entirely within {@link #filterResults}.
*/
final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
@@ -16117,6 +16135,8 @@ public class PackageManagerService extends IPackageManager.Stub {
setInstantAppForUser(ps, user.getIdentifier(), instantApp, fullApp);
prepareAppDataAfterInstallLIF(newPackage);
addedPkg = true;
+ mDexManager.notifyPackageUpdated(newPackage.packageName,
+ newPackage.baseCodePath, newPackage.splitCodePaths);
} catch (PackageManagerException e) {
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}
@@ -16266,6 +16286,9 @@ public class PackageManagerService extends IPackageManager.Stub {
updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
installReason);
prepareAppDataAfterInstallLIF(newPackage);
+
+ mDexManager.notifyPackageUpdated(newPackage.packageName,
+ newPackage.baseCodePath, newPackage.splitCodePaths);
}
} catch (PackageManagerException e) {
res.setReturnCode(INSTALL_FAILED_INTERNAL_ERROR);
@@ -16628,6 +16651,7 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
+ pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
@@ -16640,13 +16664,19 @@ public class PackageManagerService extends IPackageManager.Stub {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
-// // Ephemeral apps must have target SDK >= O.
-// // TODO: Update conditional and error message when O gets locked down
-// if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
-// res.setError(PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID,
-// "Ephemeral apps must have target SDK version of at least O");
-// return;
-// }
+ // Instant apps must have target SDK >= O and have targetSanboxVersion >= 2
+ if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+ Slog.w(TAG, "Instant app package " + pkg.packageName
+ + " does not target O, this will be a fatal error.");
+ // STOPSHIP: Make this a fatal error
+ pkg.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
+ }
+ if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {
+ Slog.w(TAG, "Instant app package " + pkg.packageName
+ + " does not target targetSandboxVersion 2, this will be a fatal error.");
+ // STOPSHIP: Make this a fatal error
+ pkg.applicationInfo.targetSandboxVersion = 2;
+ }
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// Static shared libraries have synthetic package names
@@ -16943,7 +16973,8 @@ public class PackageManagerService extends IPackageManager.Stub {
mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
null /* instructionSets */, false /* checkProfiles */,
getCompilerFilterForReason(REASON_INSTALL),
- getOrCreateCompilerPackageStats(pkg));
+ getOrCreateCompilerPackageStats(pkg),
+ mDexManager.isUsedByOtherApps(pkg.packageName));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Notify BackgroundDexOptJobService that the package has been changed.
@@ -19645,6 +19676,35 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
}
+ /**
+ * Report the 'Home' activity which is currently set as "always use this one". If non is set
+ * then reports the most likely home activity or null if there are more than one.
+ */
+ public ComponentName getDefaultHomeActivity(int userId) {
+ List<ResolveInfo> allHomeCandidates = new ArrayList<>();
+ ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId);
+ if (cn != null) {
+ return cn;
+ }
+
+ // Find the launcher with the highest priority and return that component if there are no
+ // other home activity with the same priority.
+ int lastPriority = Integer.MIN_VALUE;
+ ComponentName lastComponent = null;
+ final int size = allHomeCandidates.size();
+ for (int i = 0; i < size; i++) {
+ final ResolveInfo ri = allHomeCandidates.get(i);
+ if (ri.priority > lastPriority) {
+ lastComponent = ri.activityInfo.getComponentName();
+ lastPriority = ri.priority;
+ } else if (ri.priority == lastPriority) {
+ // Two components found with same priority.
+ lastComponent = null;
+ }
+ }
+ return lastComponent;
+ }
+
private Intent getHomeIntent() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 45887e1c8a3f..9feee8c97c0d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -133,7 +133,8 @@ public class PackageManagerServiceUtils {
sortTemp, packageManagerService);
// Give priority to apps used by other apps.
- applyPackageFilter((pkg) -> PackageDexOptimizer.isUsedByOtherApps(pkg), result,
+ applyPackageFilter((pkg) ->
+ packageManagerService.getDexManager().isUsedByOtherApps(pkg.packageName), result,
remainingPkgs, sortTemp, packageManagerService);
// Filter out packages that aren't recently used, add all remaining apps.
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 603385548689..4ff3e1218b53 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -46,6 +46,7 @@ class ParallelPackageParser implements AutoCloseable {
private final boolean mOnlyCore;
private final DisplayMetrics mMetrics;
private final File mCacheDir;
+ private final PackageParser.Callback mPackageParserCallback;
private volatile String mInterruptedInThread;
private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
@@ -54,11 +55,12 @@ class ParallelPackageParser implements AutoCloseable {
"package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND);
ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps,
- DisplayMetrics metrics, File cacheDir) {
+ DisplayMetrics metrics, File cacheDir, PackageParser.Callback callback) {
mSeparateProcesses = separateProcesses;
mOnlyCore = onlyCoreApps;
mMetrics = metrics;
mCacheDir = cacheDir;
+ mPackageParserCallback = callback;
}
static class ParseResult {
@@ -110,6 +112,7 @@ class ParallelPackageParser implements AutoCloseable {
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCacheDir(mCacheDir);
+ pp.setCallback(mPackageParserCallback);
pr.scanFile = scanFile;
pr.pkg = parsePackage(pp, scanFile, parseFlags);
} catch (Throwable e) {
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index ac98ab96f9ca..7885748fdf13 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1635,10 +1635,10 @@ class ShortcutPackage extends ShortcutPackageItem {
Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ " still has an icon");
}
- if (si.hasMaskableBitmap() && !si.hasIconFile()) {
+ if (si.hasAdaptiveBitmap() && !si.hasIconFile()) {
failed = true;
Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
- + " has maskable bitmap but was not saved to a file.");
+ + " has adaptive bitmap but was not saved to a file.");
}
if (si.hasIconFile() && si.hasIconResource()) {
failed = true;
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 74eb340b23e3..43288cd8fc9d 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -46,7 +46,6 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
-import android.content.pm.ShortcutManager;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
import android.content.pm.UserInfo;
@@ -1219,7 +1218,7 @@ public class ShortcutService extends IShortcutService.Stub {
shortcut.setIconResourceId(0);
shortcut.setIconResName(null);
shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE |
- ShortcutInfo.FLAG_MASKABLE_BITMAP | ShortcutInfo.FLAG_HAS_ICON_RES);
+ ShortcutInfo.FLAG_ADAPTIVE_BITMAP | ShortcutInfo.FLAG_HAS_ICON_RES);
}
public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) {
@@ -1355,7 +1354,7 @@ public class ShortcutService extends IShortcutService.Stub {
return;
}
case Icon.TYPE_BITMAP:
- case Icon.TYPE_BITMAP_MASKABLE: {
+ case Icon.TYPE_ADAPTIVE_BITMAP: {
bitmap = icon.getBitmap(); // Don't recycle in this case.
break;
}
@@ -1386,8 +1385,8 @@ public class ShortcutService extends IShortcutService.Stub {
shortcut.setBitmapPath(out.getFile().getAbsolutePath());
shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_FILE);
- if (icon.getType() == Icon.TYPE_BITMAP_MASKABLE) {
- shortcut.addFlags(ShortcutInfo.FLAG_MASKABLE_BITMAP);
+ if (icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
+ shortcut.addFlags(ShortcutInfo.FLAG_ADAPTIVE_BITMAP);
}
} finally {
IoUtils.closeQuietly(out);
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 00f3711c7038..755c486d1be5 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -22,6 +22,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageParser;
import android.os.RemoteException;
import android.os.storage.StorageManager;
+import android.os.UserHandle;
import android.util.Slog;
@@ -179,17 +180,64 @@ public class DexManager {
}
}
- public void notifyPackageInstalled(PackageInfo info, int userId) {
- cachePackageCodeLocation(info, userId);
+ /**
+ * Notifies that a new package was installed for {@code userId}.
+ * {@code userId} must not be {@code UserHandle.USER_ALL}.
+ *
+ * @throws IllegalArgumentException if {@code userId} is {@code UserHandle.USER_ALL}.
+ */
+ public void notifyPackageInstalled(PackageInfo pi, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ throw new IllegalArgumentException(
+ "notifyPackageInstalled called with USER_ALL");
+ }
+ cachePackageCodeLocation(pi.packageName, pi.applicationInfo.sourceDir,
+ pi.applicationInfo.splitSourceDirs, pi.applicationInfo.dataDir, userId);
+ }
+
+ /**
+ * Notifies that package {@code packageName} was updated.
+ * This will clear the UsedByOtherApps mark if it exists.
+ */
+ public void notifyPackageUpdated(String packageName, String baseCodePath,
+ String[] splitCodePaths) {
+ cachePackageCodeLocation(packageName, baseCodePath, splitCodePaths, null, /*userId*/ -1);
+ // In case there was an update, write the package use info to disk async.
+ // Note that we do the writing here and not in PackageDexUsage in order to be
+ // consistent with other methods in DexManager (e.g. reconcileSecondaryDexFiles performs
+ // multiple updates in PackaeDexUsage before writing it).
+ if (mPackageDexUsage.clearUsedByOtherApps(packageName)) {
+ mPackageDexUsage.maybeWriteAsync();
+ }
}
- private void cachePackageCodeLocation(PackageInfo info, int userId) {
- PackageCodeLocations pcl = mPackageCodeLocationsCache.get(info.packageName);
- if (pcl != null) {
- pcl.mergeAppDataDirs(info.applicationInfo, userId);
- } else {
- mPackageCodeLocationsCache.put(info.packageName,
- new PackageCodeLocations(info.applicationInfo, userId));
+ /**
+ * Notifies that the user {@code userId} data for package {@code packageName}
+ * was destroyed. This will remove all usage info associated with the package
+ * for the given user.
+ * {@code userId} is allowed to be {@code UserHandle.USER_ALL} in which case
+ * all usage information for the package will be removed.
+ */
+ public void notifyPackageDataDestroyed(String packageName, int userId) {
+ boolean updated = userId == UserHandle.USER_ALL
+ ? mPackageDexUsage.removePackage(packageName)
+ : mPackageDexUsage.removeUserPackage(packageName, userId);
+ // In case there was an update, write the package use info to disk async.
+ // Note that we do the writing here and not in PackageDexUsage in order to be
+ // consistent with other methods in DexManager (e.g. reconcileSecondaryDexFiles performs
+ // multiple updates in PackaeDexUsage before writing it).
+ if (updated) {
+ mPackageDexUsage.maybeWriteAsync();
+ }
+ }
+
+ public void cachePackageCodeLocation(String packageName, String baseCodePath,
+ String[] splitCodePaths, String dataDir, int userId) {
+ PackageCodeLocations pcl = putIfAbsent(mPackageCodeLocationsCache, packageName,
+ new PackageCodeLocations(packageName, baseCodePath, splitCodePaths));
+ pcl.updateCodeLocation(baseCodePath, splitCodePaths);
+ if (dataDir != null) {
+ pcl.mergeAppDataDirs(dataDir, userId);
}
}
@@ -202,7 +250,8 @@ public class DexManager {
int userId = entry.getKey();
for (PackageInfo pi : packageInfoList) {
// Cache the code locations.
- cachePackageCodeLocation(pi, userId);
+ cachePackageCodeLocation(pi.packageName, pi.applicationInfo.sourceDir,
+ pi.applicationInfo.splitSourceDirs, pi.applicationInfo.dataDir, userId);
// Cache a map from package name to the set of user ids who installed the package.
// We will use it to sync the data and remove obsolete entries from
@@ -359,6 +408,23 @@ public class DexManager {
}
/**
+ * Return true if the profiling data collected for the given app indicate
+ * that the apps's APK has been loaded by another app.
+ * Note that this returns false for all apps without any collected profiling data.
+ */
+ public boolean isUsedByOtherApps(String packageName) {
+ PackageUseInfo useInfo = getPackageUseInfo(packageName);
+ if (useInfo == null) {
+ // No use info, means the package was not used or it was used but not by other apps.
+ // Note that right now we might prune packages which are not used by other apps.
+ // TODO(calin): maybe we should not (prune) so we can have an accurate view when we try
+ // to access the package use.
+ return false;
+ }
+ return useInfo.isUsedByOtherApps();
+ }
+
+ /**
* Retrieves the package which owns the given dexPath.
*/
private DexSearchResult getDexPackage(
@@ -408,27 +474,36 @@ public class DexManager {
*/
private static class PackageCodeLocations {
private final String mPackageName;
- private final String mBaseCodePath;
+ private String mBaseCodePath;
private final Set<String> mSplitCodePaths;
// Maps user id to the application private directory.
private final Map<Integer, Set<String>> mAppDataDirs;
public PackageCodeLocations(ApplicationInfo ai, int userId) {
- mPackageName = ai.packageName;
- mBaseCodePath = ai.sourceDir;
+ this(ai.packageName, ai.sourceDir, ai.splitSourceDirs);
+ mergeAppDataDirs(ai.dataDir, userId);
+ }
+ public PackageCodeLocations(String packageName, String baseCodePath,
+ String[] splitCodePaths) {
+ mPackageName = packageName;
mSplitCodePaths = new HashSet<>();
- if (ai.splitSourceDirs != null) {
- for (String split : ai.splitSourceDirs) {
+ mAppDataDirs = new HashMap<>();
+ updateCodeLocation(baseCodePath, splitCodePaths);
+ }
+
+ public void updateCodeLocation(String baseCodePath, String[] splitCodePaths) {
+ mBaseCodePath = baseCodePath;
+ mSplitCodePaths.clear();
+ if (splitCodePaths != null) {
+ for (String split : splitCodePaths) {
mSplitCodePaths.add(split);
}
}
- mAppDataDirs = new HashMap<>();
- mergeAppDataDirs(ai, userId);
}
- public void mergeAppDataDirs(ApplicationInfo ai, int userId) {
+ public void mergeAppDataDirs(String dataDir, int userId) {
Set<String> dataDirs = putIfAbsent(mAppDataDirs, userId, new HashSet<>());
- dataDirs.add(ai.dataDir);
+ dataDirs.add(dataDir);
}
public int searchDex(String dexPath, int userId) {
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index 3693bce04eb1..8a66f12cb6d9 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -377,7 +377,34 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
}
/**
+ * Clears the {@code usesByOtherApps} marker for the package {@code packageName}.
+ * @return true if the package usage info was updated.
+ */
+ public boolean clearUsedByOtherApps(String packageName) {
+ synchronized (mPackageUseInfoMap) {
+ PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName);
+ if (packageUseInfo == null || !packageUseInfo.mIsUsedByOtherApps) {
+ return false;
+ }
+ packageUseInfo.mIsUsedByOtherApps = false;
+ return true;
+ }
+ }
+
+ /**
+ * Remove the usage data associated with package {@code packageName}.
+ * @return true if the package usage was found and removed successfully.
+ */
+ public boolean removePackage(String packageName) {
+ synchronized (mPackageUseInfoMap) {
+ return mPackageUseInfoMap.remove(packageName) != null;
+ }
+ }
+
+ /**
* Remove all the records about package {@code packageName} belonging to user {@code userId}.
+ * If the package is left with no records of secondary dex usage and is not used by other
+ * apps it will be removed as well.
* @return true if the record was found and actually deleted,
* false if the record doesn't exist
*/
@@ -397,6 +424,12 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
updated = true;
}
}
+ // If no secondary dex info is left and the package is not used by other apps
+ // remove the data since it is now useless.
+ if (packageUseInfo.mDexUseInfoMap.isEmpty() && !packageUseInfo.mIsUsedByOtherApps) {
+ mPackageUseInfoMap.remove(packageName);
+ updated = true;
+ }
return updated;
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0d6cd804cdf2..4f1754a8045f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2398,8 +2398,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* permission to add alert windows that aren't
* {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY}.
*/
- return (mContext.checkCallingPermission(INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED)
- ? ADD_OKAY : ADD_PERMISSION_DENIED;
+ return (mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)
+ == PERMISSION_GRANTED) ? ADD_OKAY : ADD_PERMISSION_DENIED;
}
// check if user has enabled this operation. SecurityException will be thrown if this app
@@ -2420,8 +2420,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
default:
// in the default mode, we will make a decision here based on
// checkCallingPermission()
- return (mContext.checkCallingPermission(SYSTEM_ALERT_WINDOW) == PERMISSION_GRANTED)
- ? ADD_OKAY : ADD_PERMISSION_DENIED;
+ return (mContext.checkCallingOrSelfPermission(SYSTEM_ALERT_WINDOW)
+ == PERMISSION_GRANTED) ? ADD_OKAY : ADD_PERMISSION_DENIED;
}
}
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index afdec9ffddc3..12836dbb4820 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -17,6 +17,7 @@
package com.android.server.storage;
import android.app.NotificationChannel;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.EventLogTags;
import com.android.server.SystemService;
import com.android.server.pm.InstructionSets;
@@ -141,7 +142,7 @@ public class DeviceStorageMonitorService extends SystemService {
*/
static final String SERVICE = "devicestoragemonitor";
- private static final String NOTIFICATION_CHANNEL_ID = SERVICE;
+ private static final String TV_NOTIFICATION_CHANNEL_ID = "devicestoragemonitor.tv";
/**
* Handler that checks the amount of disk space on the device and sends a
@@ -388,14 +389,13 @@ public class DeviceStorageMonitorService extends SystemService {
PackageManager packageManager = context.getPackageManager();
boolean isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
- int importance = isTv
- ? NotificationManager.IMPORTANCE_HIGH // Do not change: this is TV-specific
- : NotificationManager.IMPORTANCE_LOW;
- notificationMgr.createNotificationChannel(
- new NotificationChannel(NOTIFICATION_CHANNEL_ID,
- context.getString(
- com.android.internal.R.string.device_storage_monitor_notification_channel),
- importance));
+ if (isTv) {
+ notificationMgr.createNotificationChannel(new NotificationChannel(
+ TV_NOTIFICATION_CHANNEL_ID,
+ context.getString(
+ com.android.internal.R.string.device_storage_monitor_notification_channel),
+ NotificationManager.IMPORTANCE_HIGH));
+ }
publishBinderService(SERVICE, mRemoteService);
publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
@@ -495,21 +495,22 @@ public class DeviceStorageMonitorService extends SystemService {
: com.android.internal.R.string.low_internal_storage_view_text_no_boot);
PendingIntent intent = PendingIntent.getActivityAsUser(context, 0, lowMemIntent, 0,
null, UserHandle.CURRENT);
- Notification notification = new Notification.Builder(context)
- .setSmallIcon(com.android.internal.R.drawable.stat_notify_disk_full)
- .setTicker(title)
- .setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(details)
- .setContentIntent(intent)
- .setStyle(new Notification.BigTextStyle()
- .bigText(details))
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setChannel(NOTIFICATION_CHANNEL_ID)
- .extend(new Notification.TvExtender())
- .build();
+ Notification notification =
+ new Notification.Builder(context, SystemNotificationChannels.ALERTS)
+ .setSmallIcon(com.android.internal.R.drawable.stat_notify_disk_full)
+ .setTicker(title)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(details)
+ .setContentIntent(intent)
+ .setStyle(new Notification.BigTextStyle()
+ .bigText(details))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .extend(new Notification.TvExtender()
+ .setChannel(TV_NOTIFICATION_CHANNEL_ID))
+ .build();
notification.flags |= Notification.FLAG_NO_CLEAR;
notificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
UserHandle.ALL);
diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java
index 0d282ef3f8d6..b7b419bf1b41 100644
--- a/services/core/java/com/android/server/wm/AlertWindowNotification.java
+++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.Notification.VISIBILITY_PRIVATE;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
import static android.content.Context.NOTIFICATION_SERVICE;
@@ -34,8 +33,10 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+
import com.android.internal.R;
+import com.android.server.policy.IconUtilities;
/** Displays an ongoing notification for a process displaying an alert window */
class AlertWindowNotification {
@@ -50,6 +51,7 @@ class AlertWindowNotification {
private final String mPackageName;
private final int mUid;
private boolean mCancelled;
+ private IconUtilities mIconUtilities;
AlertWindowNotification(WindowManagerService service, String packageName, int uid) {
mService = service;
@@ -59,20 +61,33 @@ class AlertWindowNotification {
(NotificationManager) mService.mContext.getSystemService(NOTIFICATION_SERVICE);
mNotificationTag = CHANNEL_PREFIX + mPackageName;
mRequestCode = sNextRequestCode++;
+ mIconUtilities = new IconUtilities(mService.mContext);
// We can't create/post the notification while the window manager lock is held since it will
// end up calling into activity manager. So, we post a message to do it later.
- mService.mH.post(this::postNotification);
+ mService.mH.post(this::onPostNotification);
}
/** Cancels the notification */
void cancel() {
+ // We can't call into NotificationManager with WM lock held since it might call into AM.
+ // So, we post a message to do it later.
+ mService.mH.post(this::onCancelNotification);
+ }
+
+ /** Don't call with the window manager lock held! */
+ private void onCancelNotification() {
mNotificationManager.cancel(mNotificationTag, NOTIFICATION_ID);
mCancelled = true;
}
/** Don't call with the window manager lock held! */
- private void postNotification() {
+ private void onPostNotification() {
+ if (mCancelled) {
+ // Notification was cancelled, so nothing more to do...
+ return;
+ }
+
final Context context = mService.mContext;
final PackageManager pm = context.getPackageManager();
final ApplicationInfo aInfo = getApplicationInfo(pm, mPackageName);
@@ -94,17 +109,14 @@ class AlertWindowNotification {
.addAction(getTurnOffAction(context, mPackageName, mUid));
if (aInfo != null) {
- final Bitmap bitmap = ((BitmapDrawable) pm.getApplicationIcon(aInfo)).getBitmap();
- builder.setLargeIcon(bitmap);
- }
-
- synchronized (mService.mWindowMap) {
- if (mCancelled) {
- // Notification was cancelled, so nothing more to do...
- return;
+ final Drawable drawable = pm.getApplicationIcon(aInfo);
+ if (drawable != null) {
+ final Bitmap bitmap = mIconUtilities.createIconBitmap(drawable);
+ builder.setLargeIcon(bitmap);
}
- mNotificationManager.notify(mNotificationTag, NOTIFICATION_ID, builder.build());
}
+
+ mNotificationManager.notify(mNotificationTag, NOTIFICATION_ID, builder.build());
}
private Notification.Action getTurnOffAction(Context context, String packageName, int uid) {
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index c42647ed0aee..e3941b9a2b18 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -248,8 +248,9 @@ public class AppWindowAnimator {
}
}
- void updateLayers() {
- thumbnailLayer = mAppToken.adjustAnimLayer(animLayerAdjustment);
+ private void updateLayers() {
+ mAppToken.getDisplayContent().assignWindowLayers(false /* relayoutNeeded */);
+ thumbnailLayer = mAppToken.getHighestAnimLayer();
}
private void stepThumbnailAnimation(long currentTime) {
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 3a86874b1f4e..266ab4cfde0b 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -525,7 +525,8 @@ public class AppWindowContainerController
private boolean createSnapshot() {
final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
- mContainer.mTask.mTaskId, mContainer.mTask.mUserId, false /* restoreFromDisk */);
+ mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
+ false /* restoreFromDisk */);
if (snapshot == null) {
return false;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 22630428ad01..994f38d5a94a 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -85,13 +85,17 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
final boolean mVoiceInteraction;
// TODO: Use getParent instead?
- Task mTask;
+ private Task mTask;
/** @see WindowContainer#fillsParent() */
private boolean mFillsParent;
boolean layoutConfigChanges;
boolean mShowForAllUsers;
int mTargetSdk;
+ // Flag set while reparenting to prevent actions normally triggered by an individual parent
+ // change.
+ private boolean mReparenting;
+
// The input dispatching timeout for this application token in nanoseconds.
long mInputDispatchingTimeoutNanos;
@@ -426,10 +430,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
void removeIfPossible() {
mIsExiting = false;
removeAllWindowsIfPossible();
- if (mTask != null) {
- mTask.mStack.mExitingAppTokens.remove(this);
- removeImmediately();
- }
+ removeImmediately();
}
@Override
@@ -483,6 +484,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
removed = true;
stopFreezingScreen(true, true);
+
if (mService.mFocusedApp == this) {
if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this);
mService.mFocusedApp = null;
@@ -664,6 +666,37 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
allDrawnExcludingSaved = false;
}
+ Task getTask() {
+ return mTask;
+ }
+
+ /**
+ * Sets the associated task, cleaning up dependencies when unset.
+ */
+ void setTask(Task task) {
+ // Note: the following code assumes that the previous task's stack is the same as the
+ // new task's stack.
+ if (!mReparenting && mTask != null && mTask.mStack != null) {
+ mTask.mStack.mExitingAppTokens.remove(this);
+ }
+
+ mTask = task;
+ }
+
+ @Override
+ void onParentSet() {
+ super.onParentSet();
+
+ // When the associated task is {@code null}, the {@link AppWindowToken} can no longer
+ // access visual elements like the {@link DisplayContent}. We must remove any associations
+ // such as animations.
+ if (!mReparenting && mTask == null) {
+ // It is possible we have been marked as a closing app earlier. We must remove ourselves
+ // from this list so we do not participate in any future animations.
+ mService.mClosingApps.remove(this);
+ }
+ }
+
void postWindowRemoveStartingWindowCleanup(WindowState win) {
// TODO: Something smells about the code below...Is there a better way?
if (startingWindow == win) {
@@ -762,6 +795,16 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
if (canFreezeBounds()) {
freezeBounds();
}
+
+ // In the process of tearing down before relaunching, the app will
+ // try and clean up it's child surfaces. We need to prevent this from
+ // happening, so we sever the children, transfering their ownership
+ // from the client it-self to the parent surface (owned by us).
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final WindowState w = mChildren.get(i);
+ w.mWinAnimator.detachChildren();
+ }
+
mPendingRelaunchCount++;
}
@@ -856,13 +899,24 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
throw new IllegalArgumentException(
"window token=" + this + " already child of task=" + mTask);
}
+
+ if (mTask.mStack != task.mStack) {
+ throw new IllegalArgumentException(
+ "window token=" + this + " current task=" + mTask
+ + " belongs to a different stack than " + task);
+ }
+
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this
+ " from task=" + mTask);
final DisplayContent prevDisplayContent = getDisplayContent();
+ mReparenting = true;
+
getParent().removeChild(this);
task.addChild(this, position);
+ mReparenting = false;
+
// Relayout display(s).
final DisplayContent displayContent = task.getDisplayContent();
displayContent.setLayoutNeeded();
@@ -1409,6 +1463,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
@Override
+ int getAnimLayerAdjustment() {
+ return mAppAnimator.animLayerAdjustment;
+ }
+
+ @Override
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
if (appToken != null) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2f9868e059d3..461c3faf1d9e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -341,9 +341,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
};
- private final Consumer<WindowState> mSetInputMethodAnimLayerAdjustment =
- w -> w.adjustAnimLayer(mInputMethodAnimLayerAdjustment);
-
private final Consumer<WindowState> mScheduleToastTimeout = w -> {
final int lostFocusUid = mTmpWindow.mOwnerUid;
final Handler handler = mService.mH;
@@ -1281,8 +1278,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
void setInputMethodAnimLayerAdjustment(int adj) {
if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj);
mInputMethodAnimLayerAdjustment = adj;
- mImeWindowsContainers.forAllWindows(mSetInputMethodAnimLayerAdjustment,
- true /* traverseTopToBottom */);
+ assignWindowLayers(false /* relayoutNeeded */);
}
/**
@@ -1688,7 +1684,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to "
+ target + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : ""));
setInputMethodTarget(target, false, target.mAppToken != null
- ? target.mAppToken.mAppAnimator.animLayerAdjustment : 0);
+ ? target.mAppToken.getAnimLayerAdjustment() : 0);
}
return target;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 75a79fd0b55f..aa8e37742767 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -588,7 +588,7 @@ public class DockedStackDividerController implements DimLayerUser {
private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
for (int i = apps.size() - 1; i >= 0; i--) {
final AppWindowToken token = apps.valueAt(i);
- if (token.mTask != null && token.mTask.mStack.mStackId == DOCKED_STACK_ID) {
+ if (token.getTask() != null && token.getTask().mStack.mStackId == DOCKED_STACK_ID) {
return true;
}
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 5355f3159c86..720a4544259e 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -93,7 +93,7 @@ public class Session extends IWindowSession.Stub
mUid = Binder.getCallingUid();
mPid = Binder.getCallingPid();
mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
- mCanAddInternalSystemWindow = service.mContext.checkCallingPermission(
+ mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission(
INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
StringBuilder sb = new StringBuilder();
sb.append("Session{");
@@ -664,6 +664,7 @@ public class Session extends IWindowSession.Stub
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
+ pw.print(" mCanAddInternalSystemWindow="); pw.print(mCanAddInternalSystemWindow);
pw.print(" mAppOverlaySurfaces="); pw.print(mAppOverlaySurfaces);
pw.print(" mAlertWindowSurfaces="); pw.print(mAlertWindowSurfaces);
pw.print(" mClientDead="); pw.print(mClientDead);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index da5fcf301c98..07eb88dc9ad7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -133,7 +133,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
void addChild(AppWindowToken wtoken, int position) {
position = getAdjustedAddPosition(position);
super.addChild(wtoken, position);
- wtoken.mTask = this;
+ wtoken.setTask(this);
mDeferRemoval = false;
}
@@ -244,7 +244,8 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
removeIfPossible();
}
}
- token.mTask = null;
+
+ token.setTask(null /*task*/);
}
void setSendingToBottom(boolean toBottom) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
index 601bf28b7ed8..40283360dcfc 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -106,8 +106,8 @@ class TaskSnapshotCache {
if (taskId != null) {
removeRunningEntry(taskId);
}
- if (wtoken.mTask != null) {
- mRetrievalCache.remove(wtoken.mTask.mTaskId);
+ if (wtoken.getTask() != null) {
+ mRetrievalCache.remove(wtoken.getTask().mTaskId);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 5041138a77a3..5995bba2c4ff 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -141,11 +141,12 @@ class TaskSnapshotController {
outClosingTasks.clear();
for (int i = closingApps.size() - 1; i >= 0; i--) {
final AppWindowToken atoken = closingApps.valueAt(i);
+ final Task task = atoken.getTask();
// If the task of the app is not visible anymore, it means no other app in that task
// is opening. Thus, the task is closing.
- if (atoken.mTask != null && !atoken.mTask.isVisible()) {
- outClosingTasks.add(closingApps.valueAt(i).mTask);
+ if (task != null && !task.isVisible()) {
+ outClosingTasks.add(task);
}
}
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 9f5241226d09..9f34bd788f2e 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -96,9 +96,11 @@ class TaskSnapshotSurface implements StartingSurface {
// TODO: Inherit behavior whether to draw behind status bar/nav bar.
layoutParams.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- layoutParams.setTitle(String.format(TITLE_FORMAT, token.mTask.mTaskId));
- if (token.mTask != null) {
- final TaskDescription taskDescription = token.mTask.getTaskDescription();
+ final Task task = token.getTask();
+ if (task != null) {
+ layoutParams.setTitle(String.format(TITLE_FORMAT,task.mTaskId));
+
+ final TaskDescription taskDescription = task.getTaskDescription();
if (taskDescription != null) {
fillBackgroundColor = taskDescription.getBackgroundColor();
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 34e99a6e64c5..6cc2efb78526 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -644,7 +644,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
}
for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
- if (wtoken.mTask == task) {
+ if (wtoken.getTask() == task) {
wtoken.mIsExiting = false;
mExitingAppTokens.remove(appNdx);
}
@@ -1425,16 +1425,6 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
}
public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) {
- synchronized (mService.mWindowMap) {
- if (mDisplayContent == null) {
- return false;
- }
- if (mStackId != PINNED_STACK_ID) {
- Slog.w(TAG_WM, "Attempt to use pinned stack resize animation helper on"
- + "non pinned stack");
- return false;
- }
- }
try {
mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index c32e68908100..7213c9518d16 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -547,6 +547,7 @@ class WallpaperController {
for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
token.updateWallpaperWindows(visible, mWallpaperAnimLayerAdjustment);
+ token.getDisplayContent().assignWindowLayers(false);
}
}
@@ -568,7 +569,7 @@ class WallpaperController {
// Only do this if we are not transferring between two wallpaper targets.
mWallpaperAnimLayerAdjustment =
(mPrevWallpaperTarget == null && mWallpaperTarget.mAppToken != null)
- ? mWallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0;
+ ? mWallpaperTarget.mAppToken.getAnimLayerAdjustment() : 0;
if (mWallpaperTarget.mWallpaperX >= 0) {
mLastWallpaperX = mWallpaperTarget.mWallpaperX;
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 28aebbbb281c..a12c0e5003c8 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -142,7 +142,6 @@ class WallpaperWindowToken extends WindowToken {
// First, make sure the client has the current visibility state.
wallpaper.dispatchWallpaperVisibility(visible);
- wallpaper.adjustAnimLayer(animLayerAdj);
if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
+ wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 1cd2b53de9ba..172ec4871b48 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -129,7 +129,7 @@ class WindowLayersController {
final WindowStateAnimator winAnimator = w.mWinAnimator;
Slog.v(TAG_WM, "Assign layer " + w + ": " + "mBase=" + w.mBaseLayer
+ " mLayer=" + w.mLayer + (w.mAppToken == null
- ? "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
+ ? "" : " mAppLayer=" + w.mAppToken.getAnimLayerAdjustment())
+ " =mAnimLayer=" + winAnimator.mAnimLayer);
}, false /* traverseTopToBottom */);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2a4dfc444fe2..eb3a2d15a855 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1445,9 +1445,9 @@ public class WindowManagerService extends IWindowManager.Stub
if (displayContent.isDefaultDisplay) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final Rect taskBounds;
- if (atoken != null && atoken.mTask != null) {
+ if (atoken != null && atoken.getTask() != null) {
taskBounds = mTmpRect;
- atoken.mTask.getBounds(mTmpRect);
+ atoken.getTask().getBounds(mTmpRect);
} else {
taskBounds = null;
}
@@ -2199,6 +2199,15 @@ public class WindowManagerService extends IWindowManager.Stub
if (mAccessibilityController != null && win.getDisplayId() == DEFAULT_DISPLAY) {
mAccessibilityController.onWindowTransitionLocked(win, transit);
}
+
+ // When we start the exit animation we take the Surface from the client
+ // so it will stop perturbing it. We need to likewise takeaway the SurfaceFlinger
+ // side child surfaces, so they will remain preserved in their current state
+ // (rather than be cleaned up immediately by the app code).
+ SurfaceControl.openTransaction();
+ winAnimator.detachChildren();
+ SurfaceControl.closeTransaction();
+
return focusMayChange;
}
@@ -2283,7 +2292,7 @@ public class WindowManagerService extends IWindowManager.Stub
// is running.
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
if (okToDisplay()) {
- final DisplayContent displayContent = atoken.mTask.getDisplayContent();
+ final DisplayContent displayContent = atoken.getTask().getDisplayContent();
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int width = displayInfo.appWidth;
final int height = displayInfo.appHeight;
@@ -2324,7 +2333,7 @@ public class WindowManagerService extends IWindowManager.Stub
final Configuration displayConfig = displayContent.getConfiguration();
Animation a = mAppTransition.loadAnimation(lp, transit, enter, displayConfig.uiMode,
displayConfig.orientation, frame, displayFrame, insets, surfaceInsets,
- isVoiceInteraction, freeform, atoken.mTask.mTaskId);
+ isVoiceInteraction, freeform, atoken.getTask().mTaskId);
if (a != null) {
if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken);
final int containingWidth = frame.width();
@@ -2544,8 +2553,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
void setFocusTaskRegionLocked(AppWindowToken previousFocus) {
- final Task focusedTask = mFocusedApp != null ? mFocusedApp.mTask : null;
- final Task previousTask = previousFocus != null ? previousFocus.mTask : null;
+ final Task focusedTask = mFocusedApp != null ? mFocusedApp.getTask() : null;
+ final Task previousTask = previousFocus != null ? previousFocus.getTask() : null;
final DisplayContent focusedDisplayContent =
focusedTask != null ? focusedTask.getDisplayContent() : null;
final DisplayContent previousDisplayContent =
@@ -5076,8 +5085,8 @@ public class WindowManagerService extends IWindowManager.Stub
// Also don't use mInputMethodTarget's stack, because some window with FLAG_NOT_FOCUSABLE
// and FLAG_ALT_FOCUSABLE_IM flags both set might be set to IME target so they're moved
// to make room for IME, but the window is not the focused window that's taking input.
- return (mFocusedApp != null && mFocusedApp.mTask != null) ?
- mFocusedApp.mTask.mStack : null;
+ return (mFocusedApp != null && mFocusedApp.getTask() != null) ?
+ mFocusedApp.getTask().mStack : null;
}
public boolean detectSafeMode() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 945a349a28fd..48060686a1de 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -844,20 +844,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Make sure the content and visible frames are inside of the
// final window frame.
if (windowsAreFloating && !mFrame.isEmpty()) {
+ // For pinned workspace the frame isn't limited in any particular
+ // way since SystemUI controls the bounds. For freeform however
+ // we want to keep things inside the content frame.
+ final Rect limitFrame = task.inPinnedWorkspace() ? mFrame : mContentFrame;
// Keep the frame out of the blocked system area, limit it in size to the content area
// and make sure that there is always a minimum visible so that the user can drag it
// into a usable area..
- final int height = Math.min(mFrame.height(), mContentFrame.height());
- final int width = Math.min(mContentFrame.width(), mFrame.width());
+ final int height = Math.min(mFrame.height(), limitFrame.height());
+ final int width = Math.min(limitFrame.width(), mFrame.width());
final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
final int minVisibleHeight = Math.min(height, WindowManagerService.dipToPixel(
MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics));
final int minVisibleWidth = Math.min(width, WindowManagerService.dipToPixel(
MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics));
- final int top = Math.max(mContentFrame.top,
- Math.min(mFrame.top, mContentFrame.bottom - minVisibleHeight));
- final int left = Math.max(mContentFrame.left + minVisibleWidth - width,
- Math.min(mFrame.left, mContentFrame.right - minVisibleWidth));
+ final int top = Math.max(limitFrame.top,
+ Math.min(mFrame.top, limitFrame.bottom - minVisibleHeight));
+ final int left = Math.max(limitFrame.left + minVisibleWidth - width,
+ Math.min(mFrame.left, limitFrame.right - minVisibleWidth));
mFrame.set(left, top, left + width, top + height);
mContentFrame.set(mFrame);
mVisibleFrame.set(mContentFrame);
@@ -1202,7 +1206,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
Task getTask() {
- return mAppToken != null ? mAppToken.mTask : null;
+ return mAppToken != null ? mAppToken.getTask() : null;
}
TaskStack getStack() {
@@ -1528,6 +1532,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return changed;
}
+ // Next up we will notify the client that it's visibility has changed.
+ // We need to prevent it from destroying child surfaces until
+ // the animation has finished.
+ if (!visible && isVisibleNow()) {
+ mWinAnimator.detachChildren();
+ }
+
if (visible != isVisibleNow()) {
if (!runningAppAnimation) {
final AccessibilityController accessibilityController =
@@ -1923,16 +1934,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (mIsImWindow && mService.mInputMethodTarget != null) {
final AppWindowToken appToken = mService.mInputMethodTarget.mAppToken;
if (appToken != null) {
- return appToken.mAppAnimator.animLayerAdjustment;
+ return appToken.getAnimLayerAdjustment();
}
}
- if (mAppToken != null) {
- return mAppToken.mAppAnimator.animLayerAdjustment;
- }
-
- // Nothing is animating, so there is no animation adjustment.
- return 0;
+ return mToken.getAnimLayerAdjustment();
}
int getSpecialWindowAnimLayerAdjustment() {
@@ -2383,8 +2389,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/** @return true if this window desires touch events. */
boolean canReceiveTouchInput() {
- return mAppToken != null && mAppToken.mTask != null
- && mAppToken.mTask.mStack.shouldIgnoreInput();
+ return mAppToken != null && mAppToken.getTask() != null
+ && mAppToken.getTask().mStack.shouldIgnoreInput();
}
@Override
@@ -2717,29 +2723,32 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
destroyedSomething |= c.destroySurface(cleanupOnResume, appStopped);
}
- if (appStopped || mWindowRemovalAllowed || cleanupOnResume) {
+ if (!(appStopped || mWindowRemovalAllowed || cleanupOnResume)) {
+ return destroyedSomething;
+ }
+ if (appStopped || mWindowRemovalAllowed) {
mWinAnimator.destroyPreservedSurfaceLocked();
+ }
- if (mDestroying) {
- if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + this
- + " destroySurfaces: appStopped=" + appStopped
- + " win.mWindowRemovalAllowed=" + mWindowRemovalAllowed
- + " win.mRemoveOnExit=" + mRemoveOnExit);
-
- if (!cleanupOnResume || mRemoveOnExit) {
- destroyOrSaveSurface();
- }
- if (mRemoveOnExit) {
- removeImmediately();
- }
- if (cleanupOnResume) {
- requestUpdateWallpaperIfNeeded();
- }
- mDestroying = false;
- destroyedSomething = true;
+ if (mDestroying) {
+ if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + this
+ + " destroySurfaces: appStopped=" + appStopped
+ + " win.mWindowRemovalAllowed=" + mWindowRemovalAllowed
+ + " win.mRemoveOnExit=" + mRemoveOnExit);
+ if (!cleanupOnResume || mRemoveOnExit) {
+ destroyOrSaveSurface();
+ }
+ if (mRemoveOnExit) {
+ removeImmediately();
+ }
+ if (cleanupOnResume) {
+ requestUpdateWallpaperIfNeeded();
}
+ mDestroying = false;
+ destroyedSomething = true;
}
+
return destroyedSomething;
}
@@ -3860,20 +3869,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return highest;
}
- int adjustAnimLayer(int adj) {
- int highestAnimLayer = mWinAnimator.mAnimLayer = mLayer + adj;
- if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG_WM,
- "adjustAnimLayer win=" + this + " anim layer: " + mWinAnimator.mAnimLayer);
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState childWindow = mChildren.get(i);
- childWindow.adjustAnimLayer(adj);
- if (childWindow.mWinAnimator.mAnimLayer > highestAnimLayer) {
- highestAnimLayer = childWindow.mWinAnimator.mAnimLayer;
- }
- }
- return highestAnimLayer;
- }
-
@Override
boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
if (mChildren.isEmpty()) {
@@ -4397,7 +4392,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// will keep their surface and its size may change over time.
if (mHasSurface && !isChildWindow()) {
mWinAnimator.preserveSurfaceLocked();
- result |= RELAYOUT_RES_FIRST_TIME;
+ result |= RELAYOUT_RES_SURFACE_CHANGED |
+ RELAYOUT_RES_FIRST_TIME;
}
}
final boolean freeformResizing = isDragResizing()
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 98598e1654dc..4b7133836db8 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -566,6 +566,20 @@ class WindowStateAnimator {
if (!mDestroyPreservedSurfaceUponRedraw) {
return;
}
+ if (mSurfaceController != null) {
+ if (mPendingDestroySurface != null) {
+ // If we are preserving a surface but we aren't relaunching that means
+ // we are just doing an in-place switch. In that case any SurfaceFlinger side
+ // child layers need to be reparented to the new surface to make this
+ // transparent to the app.
+ if (mWin.mAppToken == null || mWin.mAppToken.isRelaunching() == false) {
+ SurfaceControl.openTransaction();
+ mPendingDestroySurface.reparentChildrenInTransaction(mSurfaceController);
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
destroyDeferredSurfaceLocked();
mDestroyPreservedSurfaceUponRedraw = false;
}
@@ -1965,4 +1979,10 @@ class WindowStateAnimator {
}
return mForceScaleUntilResize;
}
+
+ void detachChildren() {
+ if (mSurfaceController != null) {
+ mSurfaceController.detachChildren();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index f8e74284fafd..f7d3343831bf 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -135,6 +135,20 @@ class WindowSurfaceController {
}
}
+ void reparentChildrenInTransaction(WindowSurfaceController other) {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "REPARENT from: " + this + " to: " + other);
+ if ((mSurfaceControl != null) && (other.mSurfaceControl != null)) {
+ mSurfaceControl.reparentChildren(other.getHandle());
+ }
+ }
+
+ void detachChildren() {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "SEVER CHILDREN");
+ if (mSurfaceControl != null) {
+ mSurfaceControl.detachChildren();
+ }
+ }
+
void hideInTransaction(String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
mHiddenForOtherReasons = true;
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 897d5b86d3d9..f247ebe62f8c 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -651,7 +651,7 @@ class WindowSurfacePlacer {
if (openingAppAnimator == null || openingAppAnimator.animation == null) {
return;
}
- final int taskId = appToken.mTask.mTaskId;
+ final int taskId = appToken.getTask().mTaskId;
Bitmap thumbnailHeader = mService.mAppTransition.getAppTransitionThumbnailHeader(taskId);
if (thumbnailHeader == null || thumbnailHeader.getConfig() == Bitmap.Config.ALPHA_8) {
if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId);
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 8beb87d3354b..fab59d6c8f08 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -151,21 +151,6 @@ class WindowToken extends WindowContainer<WindowState> {
}
}
- int adjustAnimLayer(int adj) {
- int highestAnimLayer = -1;
- for (int j = mChildren.size() - 1; j >= 0; j--) {
- final WindowState w = mChildren.get(j);
- final int winHighestAnimLayer = w.adjustAnimLayer(adj);
- if (winHighestAnimLayer > highestAnimLayer) {
- highestAnimLayer = winHighestAnimLayer;
- }
- if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
- mDisplayContent.setInputMethodAnimLayerAdjustment(adj);
- }
- }
- return highestAnimLayer;
- }
-
/**
* Returns true if the new window is considered greater than the existing window in terms of
* z-order.
@@ -197,6 +182,11 @@ class WindowToken extends WindowContainer<WindowState> {
return mChildren.isEmpty();
}
+ // Used by AppWindowToken.
+ int getAnimLayerAdjustment() {
+ return 0;
+ }
+
WindowState getReplacingWindow() {
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState win = mChildren.get(i);
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index 74af639cd9af..813dcf5c93e7 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -43,63 +43,46 @@ static sp<ILight> gLight;
static bool validate(jint light, jint flash, jint brightness) {
bool valid = true;
- if (light < 0 || light >= static_cast<int>(Type::COUNT)) {
+ if (light < 0 || light >= static_cast<jint>(Type::COUNT)) {
ALOGE("Invalid light parameter %d.", light);
valid = false;
}
- if (flash != static_cast<int>(Flash::NONE) &&
- flash != static_cast<int>(Flash::TIMED) &&
- flash != static_cast<int>(Flash::HARDWARE)) {
+ if (flash != static_cast<jint>(Flash::NONE) &&
+ flash != static_cast<jint>(Flash::TIMED) &&
+ flash != static_cast<jint>(Flash::HARDWARE)) {
ALOGE("Invalid flash parameter %d.", flash);
valid = false;
}
- if (brightness != static_cast<int>(Brightness::USER) &&
- brightness != static_cast<int>(Brightness::SENSOR) &&
- brightness != static_cast<int>(Brightness::LOW_PERSISTENCE)) {
+ if (brightness != static_cast<jint>(Brightness::USER) &&
+ brightness != static_cast<jint>(Brightness::SENSOR) &&
+ brightness != static_cast<jint>(Brightness::LOW_PERSISTENCE)) {
ALOGE("Invalid brightness parameter %d.", brightness);
valid = false;
}
+ if (brightness == static_cast<jint>(Brightness::LOW_PERSISTENCE) &&
+ light != static_cast<jint>(Type::BACKLIGHT)) {
+ ALOGE("Cannot set low-persistence mode for non-backlight device.");
+ valid = false;
+ }
+
return valid;
}
-static void setLight_native(
- JNIEnv* /* env */,
- jobject /* clazz */,
- jint light,
+static LightState constructState(
jint colorARGB,
jint flashMode,
jint onMS,
jint offMS,
- jint brightnessMode) {
-
- if (!validate(light, flashMode, brightnessMode)) {
- return;
- }
-
- // TODO(b/31632518)
- if (gLight == nullptr) {
- gLight = ILight::getService();
- }
-
- if (gLight == nullptr) {
- ALOGE("LightService unable to get ILight interface.");
- return;
- }
-
- Type type = static_cast<Type>(light);
+ jint brightnessMode){
Flash flash = static_cast<Flash>(flashMode);
Brightness brightness = static_cast<Brightness>(brightnessMode);
LightState state{};
- if (brightnessMode == static_cast<int>(Brightness::LOW_PERSISTENCE)) {
- if (light != static_cast<int>(Type::BACKLIGHT)) {
- ALOGE("Cannot set low-persistence mode for non-backlight device.");
- return;
- }
+ if (brightness == Brightness::LOW_PERSISTENCE) {
state.flashMode = Flash::NONE;
} else {
// Only set non-brightness settings when not in low-persistence mode
@@ -111,27 +94,28 @@ static void setLight_native(
state.color = colorARGB;
state.brightnessMode = brightness;
- Status status;
- {
- ALOGD_IF_SLOW(50, "Excessive delay setting light");
- Return<Status> ret = gLight->setLight(type, state);
-
- if (!ret.isOk()) {
- ALOGE("Failed to issue set light command.");
- return;
- }
+ return state;
+}
- status = static_cast<Status>(ret); // hal status
+static void processReturn(
+ const Return<Status> &ret,
+ Type type,
+ const LightState &state) {
+ if (!ret.isOk()) {
+ ALOGE("Failed to issue set light command.");
+ gLight = nullptr;
+ return;
}
- switch (status) {
+ switch (static_cast<Status>(ret)) {
case Status::SUCCESS:
break;
case Status::LIGHT_NOT_SUPPORTED:
- ALOGE("Light requested not availale on this device.");
+ ALOGE("Light requested not available on this device. %d", type);
break;
case Status::BRIGHTNESS_NOT_SUPPORTED:
- ALOGE("Brightness parameter not supported on this device.");
+ ALOGE("Brightness parameter not supported on this device: %d",
+ state.brightnessMode);
break;
case Status::UNKNOWN:
default:
@@ -139,6 +123,40 @@ static void setLight_native(
}
}
+static void setLight_native(
+ JNIEnv* /* env */,
+ jobject /* clazz */,
+ jint light,
+ jint colorARGB,
+ jint flashMode,
+ jint onMS,
+ jint offMS,
+ jint brightnessMode) {
+
+ if (!validate(light, flashMode, brightnessMode)) {
+ return;
+ }
+
+ if (gLight == nullptr || !gLight->ping().isOk()) {
+ gLight = ILight::getService();
+ }
+
+ if (gLight == nullptr) {
+ ALOGE("Unable to get ILight interface.");
+ return;
+ }
+
+ Type type = static_cast<Type>(light);
+ LightState state = constructState(
+ colorARGB, flashMode, onMS, offMS, brightnessMode);
+
+ {
+ ALOGD_IF_SLOW(50, "Excessive delay setting light");
+ Return<Status> ret = gLight->setLight(type, state);
+ processReturn(ret, type, state);
+ }
+}
+
static const JNINativeMethod method_table[] = {
{ "setLight_native", "(IIIIII)V", (void*)setLight_native },
};
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 20b70a6344b4..36ae94b88b23 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1144,7 +1144,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
}
auto result = gnssHal->setCallback(gnssCbIface);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("SetCallback for Gnss Interface fails\n");
return JNI_FALSE;
}
@@ -1154,7 +1154,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
ALOGE("Unable to initialize GNSS Xtra interface\n");
} else {
result = gnssXtraIface->setCallback(gnssXtraCbIface);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
gnssXtraIface = nullptr;
ALOGE("SetCallback for Gnss Xtra Interface fails\n");
}
@@ -1344,7 +1344,7 @@ static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */,
jlong time, jlong timeReference, jint uncertainty) {
if (gnssHal != nullptr) {
auto result = gnssHal->injectTime(time, timeReference, uncertainty);
- if (!result || !result.isOk()) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Gnss injectTime() failed", __func__);
}
}
@@ -1354,7 +1354,7 @@ static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env
jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) {
if (gnssHal != nullptr) {
auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
- if (!result || !result.isOk()) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Gnss injectLocation() failed", __func__);
}
}
@@ -1391,7 +1391,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_open(
const char *apnStr = env->GetStringUTFChars(apn, NULL);
auto result = agnssIface->dataConnOpen(apnStr, static_cast<IAGnss::ApnIpType>(apnIpType));
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result){
ALOGE("%s: Failed to set APN and its IP type", __func__);
}
env->ReleaseStringUTFChars(apn, apnStr);
@@ -1405,7 +1405,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv*
}
auto result = agnssIface->dataConnClosed();
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Failed to close AGnss data connection", __func__);
}
}
@@ -1418,7 +1418,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv*
}
auto result = agnssIface->dataConnFailed();
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Failed to notify unavailability of AGnss data connection", __func__);
}
}
@@ -1434,7 +1434,7 @@ static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, j
auto result = agnssIface->setServer(static_cast<IAGnssCallback::AGnssType>(type),
c_hostname,
port);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Failed to set AGnss host name and port", __func__);
}
@@ -1512,13 +1512,13 @@ static void android_location_GnssLocationProvider_update_network_state(JNIEnv* e
auto result = agnssRilIface->updateNetworkState(connected,
static_cast<IAGnssRil::NetworkType>(type),
roaming);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("updateNetworkState failed");
}
const char *c_apn = env->GetStringUTFChars(apn, NULL);
result = agnssRilIface->updateNetworkAvailability(available, c_apn);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("updateNetworkAvailability failed");
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c2abb38c7a97..8b94ca067621 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -165,10 +165,10 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
-import com.android.internal.util.ParcelableString;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
@@ -5293,13 +5293,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void sendWipeProfileNotification() {
String contentText = mContext.getString(R.string.work_profile_deleted_description_dpm_wipe);
- Notification notification = new Notification.Builder(mContext)
- .setSmallIcon(android.R.drawable.stat_sys_warning)
- .setContentTitle(mContext.getString(R.string.work_profile_deleted))
- .setContentText(contentText)
- .setColor(mContext.getColor(R.color.system_notification_accent_color))
- .setStyle(new Notification.BigTextStyle().bigText(contentText))
- .build();
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setContentTitle(mContext.getString(R.string.work_profile_deleted))
+ .setContentText(contentText)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setStyle(new Notification.BigTextStyle().bigText(contentText))
+ .build();
mInjector.getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
}
@@ -10719,7 +10720,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
intent.setPackage("com.android.systemui");
final PendingIntent pendingIntent = PendingIntent.getBroadcastAsUser(mContext, 0, intent, 0,
UserHandle.CURRENT);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(R.drawable.ic_qs_network_logging)
.setContentTitle(mContext.getString(R.string.network_logging_notification_title))
.setContentText(mContext.getString(R.string.network_logging_notification_text))
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java b/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
index 03c137a95b85..1933fe750e75 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
@@ -34,8 +34,8 @@ import android.provider.Settings;
import android.security.KeyChain.KeyChainConnection;
import android.util.Log;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.R;
-import com.android.internal.util.ParcelableString;
import java.util.ArrayList;
import java.util.List;
@@ -132,16 +132,16 @@ public class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Voi
dialogIntent, PendingIntent.FLAG_UPDATE_CURRENT, null,
UserHandle.of(parentUserId));
- final Notification noti = new Notification.Builder(userContext)
- .setSmallIcon(smallIconId)
- .setContentTitle(resources.getQuantityText(R.plurals.ssl_ca_cert_warning,
- pendingCertificateCount))
- .setContentText(contentText)
- .setContentIntent(notifyIntent)
- .setPriority(Notification.PRIORITY_HIGH)
- .setShowWhen(false)
- .setColor(R.color.system_notification_accent_color)
- .build();
+ final Notification noti =
+ new Notification.Builder(userContext, SystemNotificationChannels.SECURITY)
+ .setSmallIcon(smallIconId)
+ .setContentTitle(resources.getQuantityText(R.plurals.ssl_ca_cert_warning,
+ pendingCertificateCount))
+ .setContentText(contentText)
+ .setContentIntent(notifyIntent)
+ .setShowWhen(false)
+ .setColor(R.color.system_notification_accent_color)
+ .build();
mInjector.getNotificationManager().notifyAsUser(
LOG_TAG, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
@@ -150,12 +150,7 @@ public class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Voi
private List<String> getInstalledCaCertificates(UserHandle userHandle)
throws RemoteException, RuntimeException {
try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) {
- List<ParcelableString> aliases = conn.getService().getUserCaAliases().getList();
- List<String> result = new ArrayList<>(aliases.size());
- for (int i = 0; i < aliases.size(); i++) {
- result.add(aliases.get(i).string);
- }
- return result;
+ return conn.getService().getUserCaAliases().getList();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
index 6d42dc9e4e5a..969c89eb4029 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
@@ -28,6 +28,7 @@ import android.provider.Settings;
import android.text.format.DateUtils;
import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -62,14 +63,14 @@ class RemoteBugreportUtils {
PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(context, type,
dialogIntent, 0, null, UserHandle.CURRENT);
- Notification.Builder builder = new Notification.Builder(context)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setOngoing(true)
- .setLocalOnly(true)
- .setPriority(Notification.PRIORITY_HIGH)
- .setContentIntent(pendingDialogIntent)
- .setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color));
+ Notification.Builder builder =
+ new Notification.Builder(context, SystemNotificationChannels.DEVELOPER)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setOngoing(true)
+ .setLocalOnly(true)
+ .setContentIntent(pendingDialogIntent)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
builder.setContentTitle(context.getString(
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e586482af83e..1a0aff79be6e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -53,6 +53,7 @@ import android.view.WindowManager;
import com.android.internal.R;
import com.android.internal.app.NightDisplayController;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.policy.EmergencyAffordanceManager;
@@ -1118,6 +1119,7 @@ public final class SystemServer {
traceBeginAndSlog("StartNotificationManager");
mSystemServiceManager.startService(NotificationManagerService.class);
+ SystemNotificationChannels.createAll(context);
notification = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
networkPolicy.bindNotificationManager(notification);
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index f943ee2c09bf..472f98455d6a 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -61,6 +61,7 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.KeyValueListParser;
import android.util.Slog;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -818,7 +819,7 @@ public class RetailDemoModeService extends SystemService {
}
Notification createResetNotification() {
- return new Notification.Builder(getContext())
+ return new Notification.Builder(getContext(), SystemNotificationChannels.RETAIL_MODE)
.setContentTitle(getContext().getString(R.string.reset_retail_demo_mode_title))
.setContentText(getContext().getString(R.string.reset_retail_demo_mode_text))
.setOngoing(true)
diff --git a/services/tests/notification/AndroidManifest.xml b/services/tests/notification/AndroidManifest.xml
index 92f155f53420..cf050a89b0e6 100644
--- a/services/tests/notification/AndroidManifest.xml
+++ b/services/tests/notification/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
index 936531b07059..05c33a4e1cea 100644
--- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
@@ -64,7 +64,7 @@ public class GroupHelperTest {
private StatusBarNotification getSbn(String pkg, int id, String tag,
UserHandle user, String groupKey) {
- Notification.Builder nb = new Notification.Builder(getContext())
+ Notification.Builder nb = new Notification.Builder(getContext(), "test_channel_id")
.setContentTitle("A")
.setWhen(1205);
if (groupKey != null) {
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index 064ab0a3adc4..176342be99fd 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -63,6 +63,7 @@ public class NotificationComparatorTest {
private final int smsUid = 11;
private final String pkg2 = "pkg2";
private final int uid2 = 1111111;
+ private static final String TEST_CHANNEL_ID = "test_channel_id";
private NotificationRecord mRecordMinCall;
private NotificationRecord mRecordHighCall;
@@ -100,7 +101,7 @@ public class NotificationComparatorTest {
smsPkg = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION);
- Notification n1 = new Notification.Builder(mContext)
+ Notification n1 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_CALL)
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
.build();
@@ -109,7 +110,7 @@ public class NotificationComparatorTest {
new UserHandle(userId), "", 2000), getDefaultChannel());
mRecordMinCall.setUserImportance(NotificationManager.IMPORTANCE_MIN);
- Notification n2 = new Notification.Builder(mContext)
+ Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_CALL)
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
.setColorized(true /* colorized */)
@@ -119,7 +120,7 @@ public class NotificationComparatorTest {
new UserHandle(userId), "", 1999), getDefaultChannel());
mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
- Notification n3 = new Notification.Builder(mContext)
+ Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MediaStyle()
.setMediaSession(new MediaSession.Token(null)))
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
@@ -129,7 +130,7 @@ public class NotificationComparatorTest {
"", 1499), getDefaultChannel());
mRecordDefaultMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n4 = new Notification.Builder(mContext)
+ Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MessagingStyle("sender!")).build();
mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId),
@@ -137,34 +138,34 @@ public class NotificationComparatorTest {
mRecordInlineReply.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX);
- Notification n5 = new Notification.Builder(mContext)
+ Notification n5 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE).build();
mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg,
smsPkg, 1, "sms", smsUid, smsUid, n5, new UserHandle(userId),
"", 1299), getDefaultChannel());
mRecordSms.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n6 = new Notification.Builder(mContext).build();
+ Notification n6 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordStarredContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "starred", uid2, uid2, n6, new UserHandle(userId),
"", 1259), getDefaultChannel());
mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT);
mRecordStarredContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n7 = new Notification.Builder(mContext).build();
+ Notification n7 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "contact", uid2, uid2, n7, new UserHandle(userId),
"", 1259), getDefaultChannel());
mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT);
mRecordContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n8 = new Notification.Builder(mContext).build();
+ Notification n8 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "urgent", uid2, uid2, n8, new UserHandle(userId),
"", 1258), getDefaultChannel());
mRecordUrgent.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
- Notification n9 = new Notification.Builder(mContext)
+ Notification n9 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE)
.setFlag(Notification.FLAG_ONGOING_EVENT
|Notification.FLAG_FOREGROUND_SERVICE, true)
@@ -174,7 +175,7 @@ public class NotificationComparatorTest {
"", 9258), getDefaultChannel());
mRecordCheater.setUserImportance(NotificationManager.IMPORTANCE_LOW);
- Notification n10 = new Notification.Builder(mContext)
+ Notification n10 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.InboxStyle().setSummaryText("message!")).build();
mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "email", uid2, uid2, n10, new UserHandle(userId),
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 88f1a5362008..b7b3617d7ecf 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -129,11 +129,9 @@ public class NotificationManagerServiceTest {
if (channel == null) {
channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
}
- Notification.Builder nb = new Notification.Builder(mContext)
+ Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
.setContentTitle("foo")
- .setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setChannel(channel.getId())
- .setPriority(Notification.PRIORITY_HIGH);
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
if (extender != null) {
nb.extend(extender);
}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 821007213993..ffb0a9e75d8a 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -93,6 +93,7 @@ public class RankingHelperTest {
private final int uid = 0;
private final String pkg2 = "pkg2";
private final int uid2 = 1111111;
+ private static final String TEST_CHANNEL_ID = "test_channel_id";
private AudioAttributes mAudioAttributes;
private Context getContext() {
@@ -107,7 +108,7 @@ public class RankingHelperTest {
mHelper = new RankingHelper(getContext(), mPm, handler, mUsageStats,
new String[]{ImportanceExtractor.class.getName()});
- mNotiGroupGSortA = new Notification.Builder(getContext())
+ mNotiGroupGSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
@@ -117,7 +118,7 @@ public class RankingHelperTest {
"package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiGroupGSortB = new Notification.Builder(getContext())
+ mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("B")
.setGroup("G")
.setSortKey("B")
@@ -127,7 +128,7 @@ public class RankingHelperTest {
"package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiNoGroup = new Notification.Builder(getContext())
+ mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("C")
.setWhen(1201)
.build();
@@ -135,7 +136,7 @@ public class RankingHelperTest {
"package", "package", 1, null, 0, 0, mNotiNoGroup, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiNoGroup2 = new Notification.Builder(getContext())
+ mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("D")
.setWhen(1202)
.build();
@@ -143,7 +144,7 @@ public class RankingHelperTest {
"package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiNoGroupSortA = new Notification.Builder(getContext())
+ mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("E")
.setWhen(1201)
.setSortKey("A")
@@ -195,6 +196,7 @@ public class RankingHelperTest {
private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
assertEquals(expected.getId(), actual.getId());
assertEquals(expected.getName(), actual.getName());
+ assertEquals(expected.getNameResId(), actual.getNameResId());
assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
assertEquals(expected.getImportance(), actual.getImportance());
@@ -259,11 +261,13 @@ public class RankingHelperTest {
@Test
public void testChannelXml() throws Exception {
+ int nameResId = 924896;
+
NotificationChannelGroup ncg = new NotificationChannelGroup("1", "2");
NotificationChannel channel1 =
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
NotificationChannel channel2 =
- new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+ new NotificationChannel("id2", nameResId, IMPORTANCE_LOW);
channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel2.enableLights(true);
channel2.setBypassDnd(true);
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index c5abba8313c1..9575d3253b28 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -51,6 +51,8 @@ import static org.mockito.Mockito.when;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SnoozeHelperTest {
+ private static final String TEST_CHANNEL_ID = "test_channel_id";
+
@Mock SnoozeHelper.Callback mCallback;
@Mock AlarmManager mAm;
@Mock ManagedServices.UserProfiles mUserProfiles;
@@ -77,7 +79,7 @@ public class SnoozeHelperTest {
verify(mAm, times(1)).setExactAndAllowWhileIdle(
anyInt(), captor.capture(), any(PendingIntent.class));
long actualSnoozedUntilDuration = captor.getValue() - SystemClock.elapsedRealtime();
- assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 2);
+ assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 25);
assertTrue(mSnoozeHelper.isSnoozed(
UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
}
@@ -232,20 +234,16 @@ public class SnoozeHelperTest {
private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
UserHandle user) {
- Notification n = new Notification.Builder(getContext())
+ Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
.setWhen(1205)
.build();
+ final NotificationChannel notificationChannel = new NotificationChannel(
+ TEST_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_LOW);
return new NotificationRecord(getContext(), new StatusBarNotification(
pkg, pkg, id, tag, 0, 0, n, user, null,
- System.currentTimeMillis()), getDefaultChannel());
- }
-
- private NotificationChannel getDefaultChannel() {
- return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
- NotificationManager.IMPORTANCE_LOW);
+ System.currentTimeMillis()), notificationChannel);
}
-
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 4141f2f722d6..38c6b0d35a41 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -119,6 +119,7 @@ public class NetworkScoreServiceTest {
private static final String INVALID_BSSID = "invalid_bssid";
private static final ComponentName RECOMMENDATION_SERVICE_COMP =
new ComponentName("newPackageName", "newScoringServiceClass");
+ private static final String RECOMMENDATION_SERVICE_LABEL = "Test Recommendation Service";
private static final ComponentName USE_WIFI_ENABLE_ACTIVITY_COMP =
new ComponentName("useWifiPackageName", "enableUseWifiActivityClass");
private static final ScoredNetwork SCORED_NETWORK =
@@ -128,7 +129,8 @@ public class NetworkScoreServiceTest {
new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID_2), "00:00:00:00:00:00")),
null /* rssiCurve*/);
private static final NetworkScorerAppData NEW_SCORER = new NetworkScorerAppData(
- 1, RECOMMENDATION_SERVICE_COMP, USE_WIFI_ENABLE_ACTIVITY_COMP);
+ 1, RECOMMENDATION_SERVICE_COMP, RECOMMENDATION_SERVICE_LABEL,
+ USE_WIFI_ENABLE_ACTIVITY_COMP);
@Mock private NetworkScorerAppManager mNetworkScorerAppManager;
@Mock private Context mContext;
@@ -924,7 +926,8 @@ public class NetworkScoreServiceTest {
when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_GRANTED);
NetworkScorerAppData expectedAppData = new NetworkScorerAppData(Binder.getCallingUid(),
- RECOMMENDATION_SERVICE_COMP, USE_WIFI_ENABLE_ACTIVITY_COMP);
+ RECOMMENDATION_SERVICE_COMP, RECOMMENDATION_SERVICE_LABEL,
+ USE_WIFI_ENABLE_ACTIVITY_COMP);
bindToScorer(expectedAppData);
assertEquals(expectedAppData, mNetworkScoreService.getActiveScorer());
}
@@ -965,7 +968,8 @@ public class NetworkScoreServiceTest {
private void bindToScorer(boolean callerIsScorer) {
final int callingUid = callerIsScorer ? Binder.getCallingUid() : Binder.getCallingUid() + 1;
NetworkScorerAppData appData = new NetworkScorerAppData(callingUid,
- RECOMMENDATION_SERVICE_COMP, USE_WIFI_ENABLE_ACTIVITY_COMP);
+ RECOMMENDATION_SERVICE_COMP, RECOMMENDATION_SERVICE_LABEL,
+ USE_WIFI_ENABLE_ACTIVITY_COMP);
bindToScorer(appData);
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
index e9a2d34b63ae..502bf06dd6d6 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
@@ -59,6 +59,9 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class NetworkScorerAppManagerTest {
+ private static String MOCK_SERVICE_LABEL = "Mock Service";
+ private static String MOCK_OVERRIDEN_SERVICE_LABEL = "Mock Service Label Override";
+
@Mock private Context mMockContext;
@Mock private PackageManager mMockPm;
@Mock private Resources mResources;
@@ -94,6 +97,22 @@ public class NetworkScorerAppManagerTest {
assertNotNull(activeScorer);
assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
assertEquals(924, activeScorer.packageUid);
+ assertEquals(MOCK_SERVICE_LABEL, activeScorer.getRecommendationServiceLabel());
+ }
+
+ @Test
+ public void testGetActiveScorer_providerAvailable_serviceLabelOverride() throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
+ null /* enableUseOpenWifiPackageActivityPackage*/, true /* serviceLabelOverride */);
+
+ final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+ assertNotNull(activeScorer);
+ assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
+ assertEquals(924, activeScorer.packageUid);
+ assertEquals(MOCK_OVERRIDEN_SERVICE_LABEL, activeScorer.getRecommendationServiceLabel());
}
@Test
@@ -269,11 +288,17 @@ public class NetworkScorerAppManagerTest {
}
private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid) {
- mockRecommendationServiceAvailable(compName, packageUid, null);
+ mockRecommendationServiceAvailable(compName, packageUid, null, false);
}
private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid,
String enableUseOpenWifiActivityPackage) {
+ mockRecommendationServiceAvailable(
+ compName, packageUid, enableUseOpenWifiActivityPackage, false);
+ }
+
+ private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid,
+ String enableUseOpenWifiActivityPackage, boolean serviceLabelOverride) {
final ResolveInfo serviceInfo = new ResolveInfo();
serviceInfo.serviceInfo = new ServiceInfo();
serviceInfo.serviceInfo.name = compName.getClassName();
@@ -286,6 +311,16 @@ public class NetworkScorerAppManagerTest {
NetworkScoreManager.USE_OPEN_WIFI_PACKAGE_META_DATA,
enableUseOpenWifiActivityPackage);
}
+ if (serviceLabelOverride) {
+ if (serviceInfo.serviceInfo.metaData == null) {
+ serviceInfo.serviceInfo.metaData = new Bundle();
+ }
+ serviceInfo.serviceInfo.metaData.putString(
+ NetworkScoreManager.RECOMMENDATION_SERVICE_LABEL_META_DATA,
+ MOCK_OVERRIDEN_SERVICE_LABEL);
+ } else {
+ serviceInfo.serviceInfo.nonLocalizedLabel = MOCK_SERVICE_LABEL;
+ }
final int flags = PackageManager.GET_META_DATA;
when(mMockPm.resolveService(
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
new file mode 100644
index 000000000000..cc2f7d5c914e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 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.am;
+
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
+import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
+import static android.util.DebugUtils.valueToString;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.ActivityManager;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.Function;
+
+/**
+ * Test class for {@link ActivityManagerService}.
+ *
+ * To run the tests, use
+ *
+ * runtest -c com.android.server.am.ActivityManagerServiceTest frameworks-services
+ *
+ * or the following steps:
+ *
+ * Build: m FrameworksServicesTests
+ * Install: adb install -r \
+ * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ * Run: adb shell am instrument -e class com.android.server.am.ActivityManagerServiceTest -w \
+ * com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ActivityManagerServiceTest {
+ private static final int TEST_UID = 111;
+
+ @Test
+ public void testIncrementProcStateSeqIfNeeded() {
+ final ActivityManagerService ams = new ActivityManagerService();
+ final UidRecord uidRec = new UidRecord(TEST_UID);
+
+ assertEquals("Initially global seq counter should be 0", 0, ams.mProcStateSeqCounter);
+ assertEquals("Initially seq counter in uidRecord should be 0", 0, uidRec.curProcStateSeq);
+
+ // Uid state is not moving from background to foreground or vice versa.
+ uidRec.setProcState = PROCESS_STATE_TOP;
+ uidRec.curProcState = PROCESS_STATE_TOP;
+ ams.incrementProcStateSeqIfNeeded(uidRec);
+ assertEquals(0, ams.mProcStateSeqCounter);
+ assertEquals(0, uidRec.curProcStateSeq);
+
+ // Uid state is moving from foreground to background.
+ uidRec.curProcState = PROCESS_STATE_FOREGROUND_SERVICE;
+ uidRec.setProcState = PROCESS_STATE_SERVICE;
+ ams.incrementProcStateSeqIfNeeded(uidRec);
+ assertEquals(1, ams.mProcStateSeqCounter);
+ assertEquals(1, uidRec.curProcStateSeq);
+
+ // Explicitly setting the seq counter for more verification.
+ ams.mProcStateSeqCounter = 42;
+
+ // Uid state is not moving from background to foreground or vice versa.
+ uidRec.setProcState = PROCESS_STATE_IMPORTANT_BACKGROUND;
+ uidRec.curProcState = PROCESS_STATE_IMPORTANT_FOREGROUND;
+ ams.incrementProcStateSeqIfNeeded(uidRec);
+ assertEquals(42, ams.mProcStateSeqCounter);
+ assertEquals(1, uidRec.curProcStateSeq);
+
+ // Uid state is moving from background to foreground.
+ uidRec.setProcState = PROCESS_STATE_LAST_ACTIVITY;
+ uidRec.curProcState = PROCESS_STATE_TOP;
+ ams.incrementProcStateSeqIfNeeded(uidRec);
+ assertEquals(43, ams.mProcStateSeqCounter);
+ assertEquals(43, uidRec.curProcStateSeq);
+ }
+
+ @Test
+ public void testShouldIncrementProcStateSeq() {
+ final ActivityManagerService ams = new ActivityManagerService();
+ final UidRecord uidRec = new UidRecord(TEST_UID);
+
+ final String error1 = "Seq should be incremented: prevState: %s, curState: %s";
+ final String error2 = "Seq should not be incremented: prevState: %s, curState: %s";
+ Function<String, String> errorMsg = errorTemplate -> {
+ return String.format(errorTemplate,
+ valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.setProcState),
+ valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.curProcState));
+ };
+
+ // No change in uid state
+ uidRec.setProcState = PROCESS_STATE_RECEIVER;
+ uidRec.curProcState = PROCESS_STATE_RECEIVER;
+ assertFalse(errorMsg.apply(error2), ams.shouldIncrementProcStateSeq(uidRec));
+
+ // Foreground to foreground
+ uidRec.setProcState = PROCESS_STATE_FOREGROUND_SERVICE;
+ uidRec.curProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ assertFalse(errorMsg.apply(error2), ams.shouldIncrementProcStateSeq(uidRec));
+
+ // Background to background
+ uidRec.setProcState = PROCESS_STATE_CACHED_ACTIVITY;
+ uidRec.curProcState = PROCESS_STATE_CACHED_EMPTY;
+ assertFalse(errorMsg.apply(error2), ams.shouldIncrementProcStateSeq(uidRec));
+
+ // Background to background
+ uidRec.setProcState = PROCESS_STATE_NONEXISTENT;
+ uidRec.curProcState = PROCESS_STATE_CACHED_ACTIVITY;
+ assertFalse(errorMsg.apply(error2), ams.shouldIncrementProcStateSeq(uidRec));
+
+ // Background to foreground
+ uidRec.setProcState = PROCESS_STATE_SERVICE;
+ uidRec.curProcState = PROCESS_STATE_FOREGROUND_SERVICE;
+ assertTrue(errorMsg.apply(error1), ams.shouldIncrementProcStateSeq(uidRec));
+
+ // Foreground to background
+ uidRec.setProcState = PROCESS_STATE_TOP;
+ uidRec.curProcState = PROCESS_STATE_LAST_ACTIVITY;
+ assertTrue(errorMsg.apply(error1), ams.shouldIncrementProcStateSeq(uidRec));
+ }
+} \ No newline at end of file
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 d65a9bfbf897..756514bbecc4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -34,7 +34,7 @@ import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
import android.content.res.Resources;
import android.graphics.Color;
import android.net.IIpConnectivityMetrics;
@@ -56,7 +56,6 @@ import android.util.ArraySet;
import android.util.Pair;
import com.android.internal.R;
-import com.android.internal.util.ParcelableString;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -1220,8 +1219,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.userContexts.put(user, mContext);
when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
- ParceledListSlice<ParcelableString> oneCert = asSlice(new String[] {"1"});
- ParceledListSlice<ParcelableString> fourCerts = asSlice(new String[] {"1", "2", "3", "4"});
+ StringParceledListSlice oneCert = asSlice(new String[] {"1"});
+ StringParceledListSlice fourCerts = asSlice(new String[] {"1", "2", "3", "4"});
final String TEST_STRING = "Test for exactly 2 certs out of 4";
doReturn(TEST_STRING).when(mContext.resources).getQuantityText(anyInt(), eq(2));
@@ -1229,7 +1228,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Given that we have exactly one certificate installed,
when(mContext.keyChainConnection.getService().getUserCaAliases()).thenReturn(oneCert);
// when that certificate is approved,
- dpms.approveCaCert(oneCert.getList().get(0).string, userId, true);
+ dpms.approveCaCert(oneCert.getList().get(0), userId, true);
// a notification should not be shown.
verify(mContext.notificationManager, timeout(1000))
.cancelAsUser(anyString(), anyInt(), eq(user));
@@ -1237,8 +1236,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Given that we have four certificates installed,
when(mContext.keyChainConnection.getService().getUserCaAliases()).thenReturn(fourCerts);
// when two of them are approved (one of them approved twice hence no action),
- dpms.approveCaCert(fourCerts.getList().get(0).string, userId, true);
- dpms.approveCaCert(fourCerts.getList().get(1).string, userId, true);
+ dpms.approveCaCert(fourCerts.getList().get(0), userId, true);
+ dpms.approveCaCert(fourCerts.getList().get(1), userId, true);
// a notification should be shown saying that there are two certificates left to approve.
verify(mContext.notificationManager, timeout(1000))
.notifyAsUser(anyString(), anyInt(), argThat(
@@ -3974,18 +3973,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
/**
- * Convert String[] to ParceledListSlice&lt;ParcelableString&gt;.
- * <p>
- * TODO: This shouldn't be necessary. If ParcelableString does need to exist, it also needs
- * a real constructor.
+ * Convert String[] to StringParceledListSlice.
*/
- private static ParceledListSlice<ParcelableString> asSlice(String[] s) {
- List<ParcelableString> list = new ArrayList<>(s.length);
- for (int i = 0; i < s.length; i++) {
- ParcelableString item = new ParcelableString();
- item.string = s[i];
- list.add(i, item);
- }
- return new ParceledListSlice<ParcelableString>(list);
+ private static StringParceledListSlice asSlice(String[] s) {
+ return new StringParceledListSlice(Arrays.asList(s));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
index 6c6eb7eebafc..d665094c5a26 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -69,7 +69,7 @@ public class ParallelPackageParserTest {
class TestParallelPackageParser extends ParallelPackageParser {
TestParallelPackageParser() {
- super(null, false, null, null);
+ super(null, false, null, null, null);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 94ff07fb9d71..4b3c2f8e3948 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -247,7 +247,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1);
final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.icon2));
- final Icon icon3 = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource(
+ final Icon icon3 = Icon.createWithAdaptiveBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.icon2));
final ShortcutInfo si1 = makeShortcut(
@@ -567,7 +567,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.black_32x32));
- final Icon bmp64x64_maskable = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource(
+ final Icon bmp64x64_maskable = Icon.createWithAdaptiveBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.black_64x64));
final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.black_512x512));
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index c54fa02b68ef..900da091481b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -46,7 +46,6 @@ import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.frameworks.servicestests.R;
-import com.android.server.pm.ShortcutService.ConfigConstants;
import com.android.server.pm.ShortcutUser.PackageWithUser;
import java.io.File;
@@ -993,7 +992,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
setCaller(CALLING_PACKAGE_1, USER_10);
- final Icon bmp32x32 = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource(
+ final Icon bmp32x32 = Icon.createWithAdaptiveBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.black_32x32));
PersistableBundle pb = new PersistableBundle();
@@ -1047,7 +1046,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE
- | ShortcutInfo.FLAG_STRINGS_RESOLVED | ShortcutInfo.FLAG_MASKABLE_BITMAP,
+ | ShortcutInfo.FLAG_STRINGS_RESOLVED | ShortcutInfo.FLAG_ADAPTIVE_BITMAP,
si.getFlags());
assertNotNull(si.getBitmapPath()); // Something should be set.
assertEquals(0, si.getIconResourceId());
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 90a2ec0c7628..fa0bd392f75d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -16,9 +16,10 @@
package com.android.server.pm.dex;
-import android.os.Build;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.os.Build;
+import android.os.UserHandle;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -57,6 +58,7 @@ public class DexManagerTests {
private int mUser0;
private int mUser1;
+
@Before
public void setup() {
@@ -243,6 +245,113 @@ public class DexManagerTests {
assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/false, mUser0);
}
+ @Test
+ public void testNotifyPackageUpdated() {
+ // Foo loads Bar main apks.
+ notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0);
+
+ // Bar is used by others now and should be in our records.
+ PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+ assertNotNull(pui);
+ assertTrue(pui.isUsedByOtherApps());
+ assertTrue(pui.getDexUseInfoMap().isEmpty());
+
+ // Notify that bar is updated.
+ mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(),
+ mBarUser0.mPackageInfo.applicationInfo.sourceDir,
+ mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs);
+
+ // The usedByOtherApps flag should be clear now.
+ pui = getPackageUseInfo(mBarUser0);
+ assertNotNull(pui);
+ assertFalse(pui.isUsedByOtherApps());
+ }
+
+ @Test
+ public void testNotifyPackageUpdatedCodeLocations() {
+ // Simulate a split update.
+ String newSplit = mBarUser0.replaceLastSplit();
+ List<String> newSplits = new ArrayList<>();
+ newSplits.add(newSplit);
+
+ // We shouldn't find yet the new split as we didn't notify the package update.
+ notifyDexLoad(mFooUser0, newSplits, mUser0);
+ PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+ assertNull(pui);
+
+ // Notify that bar is updated. splitSourceDirs will contain the updated path.
+ mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(),
+ mBarUser0.mPackageInfo.applicationInfo.sourceDir,
+ mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs);
+
+ // Now, when the split is loaded we will find it and we should mark Bar as usedByOthers.
+ notifyDexLoad(mFooUser0, newSplits, mUser0);
+ pui = getPackageUseInfo(mBarUser0);
+ assertNotNull(pui);
+ assertTrue(pui.isUsedByOtherApps());
+ }
+
+ @Test
+ public void testNotifyPackageDataDestroyForOne() {
+ // Bar loads its own secondary files.
+ notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0);
+ notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1);
+
+ mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0);
+
+ // Bar should not be around since it was removed for all users.
+ PackageUseInfo pui = getPackageUseInfo(mBarUser1);
+ assertNotNull(pui);
+ assertSecondaryUse(mBarUser1, pui, mBarUser1.getSecondaryDexPaths(),
+ /*isUsedByOtherApps*/false, mUser1);
+ }
+
+ @Test
+ public void testNotifyPackageDataDestroyForeignUse() {
+ // Foo loads its own secondary files.
+ List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
+ notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
+
+ // Bar loads Foo main apks.
+ notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0);
+
+ mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
+
+ // Foo should still be around since it's used by other apps but with no
+ // secondary dex info.
+ PackageUseInfo pui = getPackageUseInfo(mFooUser0);
+ assertNotNull(pui);
+ assertTrue(pui.isUsedByOtherApps());
+ assertTrue(pui.getDexUseInfoMap().isEmpty());
+ }
+
+ @Test
+ public void testNotifyPackageDataDestroyComplete() {
+ // Foo loads its own secondary files.
+ List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
+ notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
+
+ mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
+
+ // Foo should not be around since all its secondary dex info were deleted
+ // and it is not used by other apps.
+ PackageUseInfo pui = getPackageUseInfo(mFooUser0);
+ assertNull(pui);
+ }
+
+ @Test
+ public void testNotifyPackageDataDestroyForAll() {
+ // Foo loads its own secondary files.
+ notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0);
+ notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1);
+
+ mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), UserHandle.USER_ALL);
+
+ // Bar should not be around since it was removed for all users.
+ PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+ assertNull(pui);
+ }
+
private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) {
for (String dex : secondaries) {
@@ -317,5 +426,12 @@ public class DexManagerTests {
}
return paths;
}
+
+ String replaceLastSplit() {
+ int length = mPackageInfo.applicationInfo.splitSourceDirs.length;
+ // Add an extra bogus dex extension to simulate a new split name.
+ mPackageInfo.applicationInfo.splitSourceDirs[length - 1] += ".dex";
+ return mPackageInfo.applicationInfo.splitSourceDirs[length - 1];
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
index 19e0bcf6ba56..2e99433149ea 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
@@ -257,6 +257,30 @@ public class PackageDexUsageTests {
}
@Test
+ public void testRemovePackage() {
+ // Record Bar secondaries for two different users.
+ assertTrue(record(mBarSecondary1User0));
+ assertTrue(record(mBarSecondary2User1));
+
+ // Remove the package.
+ assertTrue(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
+ // Assert that we can't find the package anymore.
+ assertNull(mPackageDexUsage.getPackageUseInfo(mBarSecondary1User0.mPackageName));
+ }
+
+ @Test
+ public void testRemoveNonexistentPackage() {
+ // Record Bar secondaries for two different users.
+ assertTrue(record(mBarSecondary1User0));
+
+ // Remove the package.
+ assertTrue(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
+ // Remove the package again. It should return false because the package no longer
+ // has a record in the use info.
+ assertFalse(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
+ }
+
+ @Test
public void testRemoveUserPackage() {
// Record Bar secondaries for two different users.
assertTrue(record(mBarSecondary1User0));
@@ -282,6 +306,32 @@ public class PackageDexUsageTests {
assertPackageDexUsage(null, mBarSecondary2User1);
}
+ @Test
+ public void testClearUsedByOtherApps() {
+ // Write a package which is used by other apps.
+ assertTrue(record(mFooSplit2UsedByOtherApps0));
+ assertTrue(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
+
+ // Check that the package is no longer used by other apps.
+ TestData noLongerUsedByOtherApps = new TestData(
+ mFooSplit2UsedByOtherApps0.mPackageName,
+ mFooSplit2UsedByOtherApps0.mDexFile,
+ mFooSplit2UsedByOtherApps0.mOwnerUserId,
+ mFooSplit2UsedByOtherApps0.mLoaderIsa,
+ /*mIsUsedByOtherApps*/false,
+ mFooSplit2UsedByOtherApps0.mPrimaryOrSplit);
+ assertPackageDexUsage(noLongerUsedByOtherApps);
+ }
+
+ @Test
+ public void testClearUsedByOtherAppsNonexistent() {
+ // Write a package which is used by other apps.
+ assertTrue(record(mFooSplit2UsedByOtherApps0));
+ assertTrue(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
+ // Clearing again should return false as there should be no update on the use info.
+ assertFalse(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
+ }
+
private void assertPackageDexUsage(TestData primary, TestData... secondaries) {
String packageName = primary == null ? secondaries[0].mPackageName : primary.mPackageName;
boolean primaryUsedByOtherApps = primary == null ? false : primary.mUsedByOtherApps;
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index 04e55836a706..2ccaefc4512e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -138,19 +138,18 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
@Test
public void testReparent() throws Exception {
+ final StackWindowController stackController =
+ createStackControllerOnDisplay(sDisplayContent);
final TestTaskWindowContainerController taskController1 =
- new TestTaskWindowContainerController(
- createStackControllerOnDisplay(sDisplayContent));
+ new TestTaskWindowContainerController(stackController);
final TestAppWindowContainerController appWindowController1 = createAppWindowController(
taskController1);
final TestTaskWindowContainerController taskController2 =
- new TestTaskWindowContainerController(
- createStackControllerOnDisplay(sDisplayContent));
+ new TestTaskWindowContainerController(stackController);
final TestAppWindowContainerController appWindowController2 = createAppWindowController(
taskController2);
final TestTaskWindowContainerController taskController3 =
- new TestTaskWindowContainerController(
- createStackControllerOnDisplay(sDisplayContent));
+ new TestTaskWindowContainerController(stackController);
try {
appWindowController1.reparent(taskController1, 0);
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 73ad7c241396..e589bc77d641 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -54,7 +54,7 @@ public class DisplayContentTests extends WindowTestsBase {
sDisplayContent, "exiting app");
final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
exitingAppToken.mIsExiting = true;
- exitingAppToken.mTask.mStack.mExitingAppTokens.add(exitingAppToken);
+ exitingAppToken.getTask().mStack.mExitingAppTokens.add(exitingAppToken);
assertForAllWindowsOrder(Arrays.asList(
sWallpaperWindow,
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 5dff9973f734..58d277b274e8 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -49,7 +49,7 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
final ArraySet<Task> closingTasks = new ArraySet<>();
sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
assertEquals(1, closingTasks.size());
- assertEquals(closingWindow.mAppToken.mTask, closingTasks.valueAt(0));
+ assertEquals(closingWindow.mAppToken.getTask(), closingTasks.valueAt(0));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index b9c2eedfa215..440362d5c1b4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -167,7 +167,7 @@ class WindowTestsBase {
final TestTaskWindowContainerController taskController =
new TestTaskWindowContainerController(stackController);
TestAppWindowToken appWinToken = new TestAppWindowToken(sDisplayContent);
- appWinToken.mTask = taskController.mContainer;
+ appWinToken.setTask(taskController.mContainer);
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, name);
win.mAppToken = appWinToken;
return win;
@@ -280,6 +280,7 @@ class WindowTestsBase {
/* Used so we can gain access to some protected members of the {@link WindowToken} class */
static class TestWindowToken extends WindowToken {
+ int adj = 0;
TestWindowToken(int type, DisplayContent dc) {
this(type, dc, false /* persistOnEmpty */);
@@ -297,6 +298,11 @@ class WindowTestsBase {
boolean hasWindow(WindowState w) {
return mChildren.contains(w);
}
+
+ @Override
+ int getAnimLayerAdjustment() {
+ return adj;
+ }
}
/** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 0c053b90b757..babb6d9db31f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -102,14 +102,28 @@ public class WindowTokenTests extends WindowTestsBase {
final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3");
- final int adj = 50;
- final int window2StartLayer = window2.mLayer = 100;
- final int window3StartLayer = window3.mLayer = 200;
- final int highestLayer = token.adjustAnimLayer(adj);
-
- assertEquals(adj, window1.mWinAnimator.mAnimLayer);
- assertEquals(adj, window11.mWinAnimator.mAnimLayer);
- assertEquals(adj, window12.mWinAnimator.mAnimLayer);
+ window2.mLayer = 100;
+ window3.mLayer = 200;
+
+ // We assign layers once, to get the base values computed by
+ // the controller.
+ sLayersController.assignWindowLayers(sDisplayContent);
+
+ final int window1StartLayer = window1.mWinAnimator.mAnimLayer;
+ final int window11StartLayer = window11.mWinAnimator.mAnimLayer;
+ final int window12StartLayer = window12.mWinAnimator.mAnimLayer;
+ final int window2StartLayer = window2.mWinAnimator.mAnimLayer;
+ final int window3StartLayer = window3.mWinAnimator.mAnimLayer;
+
+ // Then we set an adjustment, and assign them again, they should
+ // be offset.
+ int adj = token.adj = 50;
+ sLayersController.assignWindowLayers(sDisplayContent);
+ final int highestLayer = token.getHighestAnimLayer();
+
+ assertEquals(window1StartLayer + adj, window1.mWinAnimator.mAnimLayer);
+ assertEquals(window11StartLayer + adj, window11.mWinAnimator.mAnimLayer);
+ assertEquals(window12StartLayer + adj, window12.mWinAnimator.mAnimLayer);
assertEquals(window2StartLayer + adj, window2.mWinAnimator.mAnimLayer);
assertEquals(window3StartLayer + adj, window3.mWinAnimator.mAnimLayer);
assertEquals(window3StartLayer + adj, highestLayer);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 469a8f144cb3..ab988b2a50d8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -60,6 +60,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -96,6 +97,8 @@ public class UsageStatsService extends SystemService implements
UserUsageStatsService.StatsUpdatedListener {
static final String TAG = "UsageStatsService";
+ public static final boolean ENABLE_TIME_CHANGE_CORRECTION
+ = SystemProperties.getBoolean("debug.time_change_correction", true);
static final boolean DEBUG = false; // Never submit with true
static final boolean COMPRESS_TIME = false;
@@ -658,7 +661,8 @@ public class UsageStatsService extends SystemService implements
final long actualRealtime = SystemClock.elapsedRealtime();
final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot;
final long diffSystemTime = actualSystemTime - expectedSystemTime;
- if (Math.abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
+ if (Math.abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS
+ && ENABLE_TIME_CHANGE_CORRECTION) {
// The time has changed.
Slog.i(TAG, "Time changed in UsageStats by " + (diffSystemTime / 1000) + " seconds");
final int userCount = mUserState.size();
diff --git a/services/usb/java/com/android/server/usb/MtpNotificationManager.java b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
index 5c46222b2feb..db7b3853d06e 100644
--- a/services/usb/java/com/android/server/usb/MtpNotificationManager.java
+++ b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
@@ -20,7 +20,6 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -32,6 +31,8 @@ import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.UserHandle;
+import com.android.internal.notification.SystemNotificationChannels;
+
/**
* Manager for MTP storage notification.
*/
@@ -77,11 +78,12 @@ class MtpNotificationManager {
device.getProductName());
final String description = resources.getString(
com.android.internal.R.string.usb_mtp_launch_notification_description);
- final Notification.Builder builder = new Notification.Builder(mContext)
- .setContentTitle(title)
- .setContentText(description)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
- .setCategory(Notification.CATEGORY_SYSTEM);
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.USB)
+ .setContentTitle(title)
+ .setContentText(description)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
+ .setCategory(Notification.CATEGORY_SYSTEM);
final Intent intent = new Intent(ACTION_OPEN_IN_APPS);
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 07b4ca12171f..b1df0af100af 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -50,6 +50,7 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.FgThread;
@@ -912,13 +913,13 @@ public class UsbDeviceManager {
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
intent, 0, null, UserHandle.CURRENT);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.USB)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
.setDefaults(0) // please be quiet
- .setPriority(Notification.PRIORITY_MIN)
.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
@@ -951,13 +952,13 @@ public class UsbDeviceManager {
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
intent, 0, null, UserHandle.CURRENT);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
.setDefaults(0) // please be quiet
- .setPriority(Notification.PRIORITY_DEFAULT)
.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index bae7cdc0e397..a923fc354b44 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -117,7 +117,7 @@ public class UsbPortManager {
public UsbPortManager(Context context) {
mContext = context;
try {
- boolean ret = IServiceManager.getService("manager")
+ boolean ret = IServiceManager.getService()
.registerForNotifications("android.hardware.usb@1.0::IUsb",
"", mServiceNotification);
if (!ret) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 4295d401edd4..5bb479fdeea5 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -328,8 +328,15 @@ public final class Call {
*/
public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 0x00000080;
+ /**
+ * Indicates that the call is from a self-managed {@link ConnectionService}.
+ * <p>
+ * See also {@link Connection#PROPERTY_SELF_MANAGED}
+ */
+ public static final int PROPERTY_SELF_MANAGED = 0x00000100;
+
//******************************************************************************************
- // Next PROPERTY value: 0x00000100
+ // Next PROPERTY value: 0x00000200
//******************************************************************************************
private final String mTelecomCallId;
@@ -878,6 +885,7 @@ public final class Call {
* party, if it is active.
*/
public static final class RttCall {
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
public @interface RttAudioMode {}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 6807ef4b0601..359dcb1ec39a 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -373,6 +373,24 @@ public class TelecomManager {
"android.telecom.INCLUDE_EXTERNAL_CALLS";
/**
+ * A boolean meta-data value indicating whether an {@link InCallService} wants to be informed of
+ * calls which have the {@link Call.Details#PROPERTY_SELF_MANAGED} property. A self-managed
+ * call is one which originates from a self-managed {@link ConnectionService} which has chosen
+ * to implement its own call user interface. An {@link InCallService} implementation which
+ * would like to be informed of external calls should set this meta-data to {@code true} in the
+ * manifest registration of their {@link InCallService}. By default, the {@link InCallService}
+ * will NOT be informed about self-managed calls.
+ * <p>
+ * An {@link InCallService} which receives self-managed calls is free to view and control the
+ * state of calls in the self-managed {@link ConnectionService}. An example use-case is
+ * exposing these calls to a wearable or automotive device via its companion app.
+ * <p>
+ * See also {@link Connection#PROPERTY_SELF_MANAGED}.
+ */
+ public static final String METADATA_INCLUDE_SELF_MANAGED_CALLS =
+ "android.telecom.INCLUDE_SELF_MANAGED_CALLS";
+
+ /**
* The dual tone multi-frequency signaling character sent to indicate the dialing system should
* pause for a predefined period.
*/
@@ -1051,10 +1069,12 @@ public class TelecomManager {
/**
* Returns whether there is an ongoing phone call (can be in dialing, ringing, active or holding
- * states).
+ * states) originating from either a manager or self-managed {@link ConnectionService}.
* <p>
* Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
- * </p>
+ *
+ * @return {@code true} if there is an ongoing call in either a managed or self-managed
+ * {@link ConnectionService}, {@code false} otherwise.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public boolean isInCall() {
@@ -1069,6 +1089,31 @@ public class TelecomManager {
}
/**
+ * Returns whether there is an ongoing call originating from a managed
+ * {@link ConnectionService}. An ongoing call can be in dialing, ringing, active or holding
+ * states.
+ * <p>
+ * If you also need to know if there are ongoing self-managed calls, use {@link #isInCall()}
+ * instead.
+ * <p>
+ * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+ *
+ * @return {@code true} if there is an ongoing call in a managed {@link ConnectionService},
+ * {@code false} otherwise.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public boolean isInManagedCall() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecomService().isInManagedCall(mContext.getOpPackageName());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException calling isInManagedCall().", e);
+ }
+ return false;
+ }
+
+ /**
* Returns one of the following constants that represents the current state of Telecom:
*
* {@link TelephonyManager#CALL_STATE_RINGING}
@@ -1079,6 +1124,9 @@ public class TelecomManager {
* {@link android.Manifest.permission#READ_PHONE_STATE} permission. This is intentional, to
* preserve the behavior of {@link TelephonyManager#getCallState()}, which also did not require
* the permission.
+ *
+ * Takes into consideration both managed and self-managed calls.
+ *
* @hide
*/
@SystemApi
@@ -1096,6 +1144,7 @@ public class TelecomManager {
/**
* Returns whether there currently exists is a ringing incoming-call.
*
+ * @return {@code true} if there is a managed or self-managed ringing call.
* @hide
*/
@SystemApi
@@ -1130,18 +1179,22 @@ public class TelecomManager {
/**
* If there is a ringing incoming call, this method accepts the call on behalf of the user.
- * TODO: L-release - need to convert all invocation of ITelecmmService#answerRingingCall to use
- * this method (clockwork & gearhead).
+ *
* If the incoming call is a video call, the call will be answered with the same video state as
* the incoming call requests. This means, for example, that an incoming call requesting
* {@link VideoProfile#STATE_BIDIRECTIONAL} will be answered, accepting that state.
- * @hide
+ *
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
+ * {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
*/
- @SystemApi
+ //TODO: L-release - need to convert all invocation of ITelecmmService#answerRingingCall to use
+ // this method (clockwork & gearhead).
+ @RequiresPermission(anyOf =
+ {Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission.MODIFY_PHONE_STATE})
public void acceptRingingCall() {
try {
if (isServiceConnected()) {
- getTelecomService().acceptRingingCall();
+ getTelecomService().acceptRingingCall(mContext.getPackageName());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#acceptRingingCall", e);
@@ -1152,14 +1205,18 @@ public class TelecomManager {
* If there is a ringing incoming call, this method accepts the call on behalf of the user,
* with the specified video state.
*
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
+ * {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
+ *
* @param videoState The desired video state to answer the call with.
- * @hide
*/
- @SystemApi
+ @RequiresPermission(anyOf =
+ {Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission.MODIFY_PHONE_STATE})
public void acceptRingingCall(int videoState) {
try {
if (isServiceConnected()) {
- getTelecomService().acceptRingingCallWithVideoState(videoState);
+ getTelecomService().acceptRingingCallWithVideoState(
+ mContext.getPackageName(), videoState);
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#acceptRingingCallWithVideoState", e);
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index d9465dce49d2..87402243a452 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -165,6 +165,11 @@ interface ITelecomService {
boolean isInCall(String callingPackage);
/**
+ * @see TelecomServiceImpl#isInManagedCall
+ */
+ boolean isInManagedCall(String callingPackage);
+
+ /**
* @see TelecomServiceImpl#isRinging
*/
boolean isRinging(String callingPackage);
@@ -182,12 +187,12 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#acceptRingingCall
*/
- void acceptRingingCall();
+ void acceptRingingCall(String callingPackage);
/**
* @see TelecomServiceImpl#acceptRingingCallWithVideoState(int)
*/
- void acceptRingingCallWithVideoState(int videoState);
+ void acceptRingingCallWithVideoState(String callingPackage, int videoState);
/**
* @see TelecomServiceImpl#cancelMissedCallsNotification
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index cafa87047d09..932c276de720 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4299,6 +4299,45 @@ public class TelephonyManager {
}
/**
+ * Returns an array of Forbidden PLMNs from the USIM App
+ * Returns null if the query fails.
+ *
+ *
+ * <p>Requires that the caller has READ_PRIVILEGED_PHONE_STATE
+ *
+ * @return an array of forbidden PLMNs or null if not available
+ */
+ public String[] getForbiddenPlmns() {
+ return getForbiddenPlmns(getSubId(), APPTYPE_USIM);
+ }
+
+ /**
+ * Returns an array of Forbidden PLMNs from the specified SIM App
+ * Returns null if the query fails.
+ *
+ *
+ * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
+ *
+ * @param subId subscription ID used for authentication
+ * @param appType the icc application type, like {@link #APPTYPE_USIM}
+ * @return fplmns an array of forbidden PLMNs
+ * @hide
+ */
+ public String[] getForbiddenPlmns(int subId, int appType) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null)
+ return null;
+ return telephony.getForbiddenPlmns(subId, appType);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone starts
+ return null;
+ }
+ }
+
+ /**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
* @return array of P-CSCF address
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 406f01e82c35..f1f683c70735 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -18,6 +18,7 @@ package android.telephony.ims;
import android.app.PendingIntent;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
@@ -43,6 +44,7 @@ import com.android.internal.annotations.VisibleForTesting;
import static android.Manifest.permission.MODIFY_PHONE_STATE;
import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
/**
* Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
@@ -137,7 +139,7 @@ public abstract class ImsService extends ImsServiceBase {
@Override
public boolean isConnected(int slotId, int featureType, int callSessionType, int callType)
throws RemoteException {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, "isConnected");
+ enforceReadPhoneStatePermission("isConnected");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -149,7 +151,7 @@ public abstract class ImsService extends ImsServiceBase {
@Override
public boolean isOpened(int slotId, int featureType) throws RemoteException {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, "isOpened");
+ enforceReadPhoneStatePermission("isOpened");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -161,7 +163,7 @@ public abstract class ImsService extends ImsServiceBase {
@Override
public int getFeatureStatus(int slotId, int featureType) throws RemoteException {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, "getFeatureStatus");
+ enforceReadPhoneStatePermission("getFeatureStatus");
int status = ImsFeature.STATE_NOT_AVAILABLE;
synchronized (mFeatures) {
SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
@@ -178,7 +180,7 @@ public abstract class ImsService extends ImsServiceBase {
@Override
public void addRegistrationListener(int slotId, int featureType,
IImsRegistrationListener listener) throws RemoteException {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, "addRegistrationListener");
+ enforceReadPhoneStatePermission("addRegistrationListener");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -190,7 +192,7 @@ public abstract class ImsService extends ImsServiceBase {
@Override
public void removeRegistrationListener(int slotId, int featureType,
IImsRegistrationListener listener) throws RemoteException {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, "removeRegistrationListener");
+ enforceReadPhoneStatePermission("removeRegistrationListener");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -351,6 +353,8 @@ public abstract class ImsService extends ImsServiceBase {
}
ImsFeature f = makeImsFeature(slotId, featureType);
if (f != null) {
+ f.setContext(this);
+ f.setSlotId(slotId);
f.setImsFeatureStatusCallback(c);
featureMap.put(featureType, f);
}
@@ -434,6 +438,17 @@ public abstract class ImsService extends ImsServiceBase {
}
/**
+ * Check for both READ_PHONE_STATE and READ_PRIVILEGED_PHONE_STATE. READ_PHONE_STATE is a
+ * public permission and READ_PRIVILEGED_PHONE_STATE is only granted to system apps.
+ */
+ private void enforceReadPhoneStatePermission(String fn) {
+ if (checkCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ enforceCallingOrSelfPermission(READ_PHONE_STATE, fn);
+ }
+ }
+
+ /**
* @return An implementation of MMTelFeature that will be used by the system for MMTel
* functionality. Must be able to handle emergency calls at any time as well.
*/
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 8d7d260104e2..988dd588ecad 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -17,7 +17,10 @@
package android.telephony.ims.feature;
import android.annotation.IntDef;
+import android.content.Context;
+import android.content.Intent;
import android.os.RemoteException;
+import android.telephony.SubscriptionManager;
import android.util.Log;
import com.android.ims.internal.IImsFeatureStatusCallback;
@@ -35,6 +38,32 @@ public abstract class ImsFeature {
private static final String LOG_TAG = "ImsFeature";
+ /**
+ * Action to broadcast when ImsService is up.
+ * Internal use only.
+ * Only defined here separately compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String ACTION_IMS_SERVICE_UP =
+ "com.android.ims.IMS_SERVICE_UP";
+
+ /**
+ * Action to broadcast when ImsService is down.
+ * Internal use only.
+ * Only defined here separately for compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String ACTION_IMS_SERVICE_DOWN =
+ "com.android.ims.IMS_SERVICE_DOWN";
+
+ /**
+ * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
+ * A long value; the phone ID corresponding to the IMS service coming up or down.
+ * Only defined here separately for compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String EXTRA_PHONE_ID = "android:phone_id";
+
// Invalid feature value
public static final int INVALID = -1;
// ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
@@ -61,11 +90,21 @@ public abstract class ImsFeature {
private List<INotifyFeatureRemoved> mRemovedListeners = new ArrayList<>();
private IImsFeatureStatusCallback mStatusCallback;
private @ImsState int mState = STATE_NOT_AVAILABLE;
+ private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ private Context mContext;
public interface INotifyFeatureRemoved {
void onFeatureRemoved(int slotId);
}
+ public void setContext(Context context) {
+ mContext = context;
+ }
+
+ public void setSlotId(int slotId) {
+ mSlotId = slotId;
+ }
+
public void addFeatureRemovedListener(INotifyFeatureRemoved listener) {
synchronized (mRemovedListeners) {
mRemovedListeners.add(listener);
@@ -118,6 +157,30 @@ public abstract class ImsFeature {
Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
}
}
+ sendImsServiceIntent(state);
+ }
+
+ /**
+ * Provide backwards compatibility using deprecated service UP/DOWN intents.
+ */
+ private void sendImsServiceIntent(@ImsState int state) {
+ if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ return;
+ }
+ Intent intent;
+ switch (state) {
+ case ImsFeature.STATE_NOT_AVAILABLE:
+ case ImsFeature.STATE_INITIALIZING:
+ intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+ break;
+ case ImsFeature.STATE_READY:
+ intent = new Intent(ACTION_IMS_SERVICE_UP);
+ break;
+ default:
+ intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+ }
+ intent.putExtra(EXTRA_PHONE_ID, mSlotId);
+ mContext.sendBroadcast(intent);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 88daf64fb4ad..e3816b6d1a40 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1278,7 +1278,6 @@ interface ITelephony {
*/
void setPolicyDataEnabled(boolean enabled, int subId);
-
/**
* Get Client request stats which will contain statistical information
* on each request made by client.
@@ -1295,4 +1294,16 @@ interface ITelephony {
* @hide
* */
void setSimPowerStateForSlot(int slotId, boolean powerUp);
+
+ /**
+ * Returns a list of Forbidden PLMNs from the specified SIM App
+ * Returns null if the query fails.
+ *
+ *
+ * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
+ *
+ * @param subId subscription ID used for authentication
+ * @param appType the icc application type, like {@link #APPTYPE_USIM}
+ */
+ String[] getForbiddenPlmns(int subId, int appType);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index c3b740e78757..eafa6b75b7c4 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -411,6 +411,8 @@ cat include/telephony/ril.h | \
int RIL_REQUEST_GET_ACTIVITY_INFO = 135;
int RIL_REQUEST_SET_ALLOWED_CARRIERS = 136;
int RIL_REQUEST_GET_ALLOWED_CARRIERS = 137;
+ int RIL_REQUEST_SEND_DEVICE_STATE = 138;
+ int RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER = 139;
int RIL_REQUEST_SET_SIM_CARD_POWER = 140;
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index d51d75ee9f95..29ba77663fd0 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -365,6 +365,12 @@ public class MockPackageManager extends PackageManager {
/** @hide */
@Override
+ public boolean isInstantApp(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
public int getInstantAppCookieMaxSize() {
throw new UnsupportedOperationException();
}
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index b984bbfddac3..684a101ed4d6 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -36,21 +36,36 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-
-import android.net.ConnectivityManager;
-import android.net.NetworkCapabilities;
-
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Build.VERSION_CODES;
+import android.net.ConnectivityManager.NetworkCallback;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import org.junit.runner.RunWith;
+import org.junit.Before;
import org.junit.Test;
-
-
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ConnectivityManagerTest {
+
+ @Mock Context mCtx;
+ @Mock IConnectivityManager mService;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
static NetworkCapabilities verifyNetworkCapabilities(
int legacyType, int transportType, int... capabilities) {
final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
@@ -173,4 +188,34 @@ public class ConnectivityManagerTest {
verifyUnrestrictedNetworkCapabilities(
ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET);
}
+
+ @Test
+ public void testNoDoubleCallbackRegistration() throws Exception {
+ ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
+ NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+ NetworkCallback callback = new ConnectivityManager.NetworkCallback();
+ ApplicationInfo info = new ApplicationInfo();
+ info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
+
+ when(mCtx.getApplicationInfo()).thenReturn(info);
+ when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt())).thenReturn(request);
+
+ manager.requestNetwork(request, callback);
+
+ // Callback is already registered, reregistration should fail.
+ Class<IllegalArgumentException> wantException = IllegalArgumentException.class;
+ expectThrowable(() -> manager.requestNetwork(request, callback), wantException);
+ }
+
+ static void expectThrowable(Runnable block, Class<? extends Throwable> throwableType) {
+ try {
+ block.run();
+ } catch (Throwable t) {
+ if (t.getClass().equals(throwableType)) {
+ return;
+ }
+ fail("expected exception of type " + throwableType + ", but was " + t.getClass());
+ }
+ fail("expected exception of type " + throwableType);
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index eeaf26f92f47..c05045ebd18d 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -369,6 +369,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
connect(false);
}
+ public void suspend() {
+ mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
public void disconnect() {
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -1054,6 +1059,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
AVAILABLE,
NETWORK_CAPABILITIES,
LINK_PROPERTIES,
+ SUSPENDED,
LOSING,
LOST,
UNAVAILABLE
@@ -1067,7 +1073,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
state = s; network = n; arg = o;
}
public String toString() {
- return String.format("%s (%s)", state, network);
+ return String.format("%s (%s) (%s)", state, network, arg);
}
@Override
public boolean equals(Object o) {
@@ -1105,11 +1111,26 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
@Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
+ setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
+ setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
+ }
+
+ @Override
public void onUnavailable() {
setLastCallback(CallbackState.UNAVAILABLE, null, null);
}
@Override
+ public void onNetworkSuspended(Network network) {
+ setLastCallback(CallbackState.SUSPENDED, network, null);
+ }
+
+ @Override
public void onLosing(Network network, int maxMsToLive) {
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
}
@@ -1132,11 +1153,12 @@ public class ConnectivityServiceTest extends AndroidTestCase {
return cb;
}
- void expectCallback(CallbackState state, MockNetworkAgent mockAgent, int timeoutMs) {
- CallbackInfo expected = new CallbackInfo(
- state, (mockAgent != null) ? mockAgent.getNetwork() : null, 0);
+ CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs) {
+ final Network expectedNetwork = (agent != null) ? agent.getNetwork() : null;
+ CallbackInfo expected = new CallbackInfo(state, expectedNetwork, 0);
CallbackInfo actual = nextCallback(timeoutMs);
assertEquals("Unexpected callback:", expected, actual);
+
if (state == CallbackState.LOSING) {
String msg = String.format(
"Invalid linger time value %d, must be between %d and %d",
@@ -1144,10 +1166,50 @@ public class ConnectivityServiceTest extends AndroidTestCase {
int maxMsToLive = (Integer) actual.arg;
assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= TEST_LINGER_DELAY_MS);
}
+
+ return actual;
}
- void expectCallback(CallbackState state, MockNetworkAgent mockAgent) {
- expectCallback(state, mockAgent, TIMEOUT_MS);
+ CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) {
+ return expectCallback(state, agent, TIMEOUT_MS);
+ }
+
+ void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) {
+ expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
+
+ final boolean HAS_DATASYNC_ON_AVAILABLE = false;
+ if (HAS_DATASYNC_ON_AVAILABLE) {
+ if (expectSuspended) {
+ expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
+ }
+ expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
+ expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
+ }
+ }
+
+ void expectAvailableCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, false, TIMEOUT_MS);
+ }
+
+ void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+ }
+
+ void expectAvailableAndValidatedCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+ expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
+ }
+
+ void expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
+ assertTrue(nc.hasCapability(capability));
+ }
+
+ void expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
+ assertFalse(nc.hasCapability(capability));
}
void assertNoCallback() {
@@ -1184,8 +1246,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1199,8 +1261,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ wifiNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1223,8 +1285,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Test validated networks
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ genericNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1236,9 +1298,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1274,28 +1337,32 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.connect(true);
// We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
// We then get LOSING when wifi validates and cell is outscored.
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mEthernetNetworkAgent);
+ callback.expectAvailableCallbacks(mEthernetNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mEthernetNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
for (int i = 0; i < 4; i++) {
MockNetworkAgent oldNetwork, newNetwork;
@@ -1312,7 +1379,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
callback.expectCallback(CallbackState.LOSING, oldNetwork);
// TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
// longer lingering?
- defaultCallback.expectCallback(CallbackState.AVAILABLE, newNetwork);
+ defaultCallback.expectAvailableCallbacks(newNetwork);
assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
}
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -1320,17 +1387,19 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even
// if the network is still up.
mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
+ // We expect a notification about the capabilities change, and nothing else.
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
+ defaultCallback.assertNoCallback();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Wifi no longer satisfies our listen, which is for an unmetered network.
// But because its score is 55, it's still up (and the default network).
- defaultCallback.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Disconnect our test networks.
mWiFiNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -1346,22 +1415,22 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false); // Score: 10
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 20.
// Cell stays up because it would satisfy the default request if it validated.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false); // Score: 20
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 70.
@@ -1369,31 +1438,33 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.adjustScore(50);
mWiFiNetworkAgent.connect(false); // Score: 70
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Tear down wifi.
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
// it's arguably correct to linger it, since it was the default network before it validated.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -1401,13 +1472,15 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// If a network is lingering, and we add and remove a request from it, resume lingering.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
@@ -1423,7 +1496,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
// Cell is now the default network. Pin it with a cell-specific request.
noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525
@@ -1432,8 +1505,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Now connect wifi, and expect it to become the default network.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
// The default request is lingering on cell, but nothing happens to cell, and we send no
// callbacks for it, because it's kept up by cellRequest.
callback.assertNoCallback();
@@ -1619,7 +1692,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mCellNetworkAgent.connectWithoutInternet();
- networkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ networkCallback.expectAvailableCallbacks(mCellNetworkAgent);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test releasing NetworkRequest disconnects cellular with MMS
cv = mCellNetworkAgent.getDisconnectedCV();
@@ -1645,7 +1718,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mmsNetworkAgent.connectWithoutInternet();
- networkCallback.expectCallback(CallbackState.AVAILABLE, mmsNetworkAgent);
+ networkCallback.expectAvailableCallbacks(mmsNetworkAgent);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
cv = mmsNetworkAgent.getDisconnectedCV();
@@ -1671,7 +1744,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
String firstRedirectUrl = "http://example.com/firstPath";
mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
- captivePortalCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
// Take down network.
@@ -1684,7 +1757,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
String secondRedirectUrl = "http://example.com/secondPath";
mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
- captivePortalCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
// Make captive portal disappear then revalidate.
@@ -1694,7 +1767,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate only sending available callbacks.
+ validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
// Break network connectivity.
// Expect NET_CAPABILITY_VALIDATED onLost callback.
@@ -1739,7 +1814,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
// But there should be no CaptivePortal callback.
captivePortalCallback.assertNoCallback();
}
@@ -1792,14 +1867,14 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Bring up cell and expect CALLBACK_AVAILABLE.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
// Bring up wifi and expect CALLBACK_AVAILABLE.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
// Bring down cell. Expect no default network callback, since it wasn't the default.
mCellNetworkAgent.disconnect();
@@ -1809,7 +1884,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Bring up cell. Expect no default network callback, since it won't be the default.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
// Bring down wifi. Expect the default network callback to notified of LOST wifi
@@ -1817,28 +1892,16 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.disconnect();
cellNetworkCallback.assertNoCallback();
defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
}
- private class TestRequestUpdateCallback extends TestNetworkCallback {
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
- setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
- }
-
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
- setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
- }
- }
-
@SmallTest
- public void testRequestCallbackUpdates() throws Exception {
+ public void testAdditionalStateCallbacks() throws Exception {
// File a network request for mobile.
- final TestNetworkCallback cellNetworkCallback = new TestRequestUpdateCallback();
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
final NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
mCm.requestNetwork(cellRequest, cellNetworkCallback);
@@ -1847,10 +1910,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- // We should get onAvailable().
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- // We should get onCapabilitiesChanged(), when the mobile network successfully validates.
- cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
+ // We should get onAvailable(), onCapabilitiesChanged(), and
+ // onLinkPropertiesChanged() in rapid succession. Additionally, we
+ // should get onCapabilitiesChanged() when the mobile network validates.
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Update LinkProperties.
@@ -1861,20 +1924,28 @@ public class ConnectivityServiceTest extends AndroidTestCase {
cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
+ // Suspend the network.
+ mCellNetworkAgent.suspend();
+ cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+
// Register a garden variety default network request.
- final TestNetworkCallback dfltNetworkCallback = new TestRequestUpdateCallback();
+ final TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
- // Only onAvailable() is called; no other information is delivered.
- dfltNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
+ // as well as onNetworkSuspended() in rapid succession.
+ dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent);
dfltNetworkCallback.assertNoCallback();
// Request a NetworkCapabilities update; only the requesting callback is notified.
+ // TODO: Delete this together with Connectivity{Manager,Service} code.
mCm.requestNetworkCapabilities(dfltNetworkCallback);
dfltNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
dfltNetworkCallback.assertNoCallback();
// Request a LinkProperties update; only the requesting callback is notified.
+ // TODO: Delete this together with Connectivity{Manager,Service} code.
mCm.requestLinkProperties(dfltNetworkCallback);
dfltNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
@@ -1917,18 +1988,20 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ fgCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
// When wifi connects, cell lingers.
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1936,7 +2009,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mService.waitForIdle();
int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
- callback.assertNoCallback();
+ // Expect a network capabilities update sans FOREGROUND.
+ callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1945,9 +2019,15 @@ public class ConnectivityServiceTest extends AndroidTestCase {
.addTransportType(TRANSPORT_CELLULAR).build();
final TestNetworkCallback cellCallback = new TestNetworkCallback();
mCm.requestNetwork(cellRequest, cellCallback);
- cellCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- callback.assertNoCallback(); // Because the network is already up.
+ // NOTE: This request causes the network's capabilities to change. This
+ // is currently delivered before the onAvailable() callbacks.
+ // TODO: Fix this.
+ cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
+ cellCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ // Expect a network capabilities update with FOREGROUND, because the most recent
+ // request causes its state to change.
+ callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1955,7 +2035,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// lingering.
mCm.unregisterNetworkCallback(cellCallback);
fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- callback.assertNoCallback();
+ // Expect a network capabilities update sans FOREGROUND.
+ callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1963,7 +2044,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
mCm.unregisterNetworkCallback(callback);
@@ -2104,7 +2185,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
testFactory.expectAddRequests(2); // Because the cell request changes score twice.
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
testFactory.waitForNetworkRequests(2);
assertFalse(testFactory.getMyStartRequested()); // Because the cell network outscores us.
@@ -2195,20 +2276,22 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Bring up validated cell.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
Network cellNetwork = mCellNetworkAgent.getNetwork();
// Bring up validated wifi.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
// Fail validation on wifi.
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
mCm.reportNetworkConnectivity(wifiNetwork, false);
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Because avoid bad wifi is off, we don't switch to cellular.
@@ -2223,18 +2306,18 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// that we switch back to cell.
tracker.configRestrictsAvoidBadWifi = false;
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// Switch back to a restrictive carrier.
tracker.configRestrictsAvoidBadWifi = true;
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
// Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
mCm.setAvoidUnvalidated(wifiNetwork);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
NET_CAPABILITY_VALIDATED));
assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2245,13 +2328,15 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.disconnect();
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
wifiNetwork = mWiFiNetworkAgent.getNetwork();
// Fail validation on wifi and expect the dialog to appear.
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
mCm.reportNetworkConnectivity(wifiNetwork, false);
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Simulate the user selecting "switch" and checking the don't ask again checkbox.
@@ -2259,7 +2344,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
tracker.reevaluate();
// We now switch to cell.
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
NET_CAPABILITY_VALIDATED));
assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2270,17 +2355,17 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// We switch to wifi and then to cell.
Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// If cell goes down, we switch to wifi.
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
validatedWifiCallback.assertNoCallback();
mCm.unregisterNetworkCallback(cellNetworkCallback);
@@ -2322,7 +2407,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, timeoutMs);
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, timeoutMs);
// pass timeout and validate that UNAVAILABLE is not called
networkCallback.assertNoCallback();
@@ -2343,7 +2428,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
final int assertTimeoutMs = 150;
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, assertTimeoutMs);
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, assertTimeoutMs);
sleepFor(20);
mWiFiNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 0e031e74dd2f..15648bdd1b3b 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -309,6 +309,8 @@ enum {
CATEGORY_ATTR = 0x010103e8,
BANNER_ATTR = 0x10103f2,
ISGAME_ATTR = 0x10103f4,
+ REQUIRED_FEATURE_ATTR = 0x1010557,
+ REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
};
String8 getComponentName(String8 &pkgName, String8 &componentName) {
@@ -366,11 +368,19 @@ static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
printf("\n");
}
-static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
+static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1,
+ const String8& requiredFeature = String8::empty(),
+ const String8& requiredNotFeature = String8::empty()) {
printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
if (maxSdkVersion != -1) {
printf(" maxSdkVersion='%d'", maxSdkVersion);
}
+ if (requiredFeature.length() > 0) {
+ printf(" requiredFeature='%s'", requiredFeature.string());
+ }
+ if (requiredNotFeature.length() > 0) {
+ printf(" requiredNotFeature='%s'", requiredNotFeature.string());
+ }
printf("\n");
if (optional) {
@@ -1545,6 +1555,10 @@ int doDump(Bundle* bundle)
const int32_t maxSdkVersion =
AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, -1);
+ const String8 requiredFeature = AaptXml::getAttribute(tree,
+ REQUIRED_FEATURE_ATTR, &error);
+ const String8 requiredNotFeature = AaptXml::getAttribute(tree,
+ REQUIRED_NOT_FEATURE_ATTR, &error);
if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
hasWriteExternalStoragePermission = true;
@@ -1565,7 +1579,7 @@ int doDump(Bundle* bundle)
printUsesPermission(name,
AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
- maxSdkVersion);
+ maxSdkVersion, requiredFeature, requiredNotFeature);
} else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
diff --git a/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java b/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
index fad35d2102d8..8130bc244e32 100644
--- a/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
+++ b/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
@@ -52,6 +52,8 @@ public class RectShadowPainter {
throw new IllegalArgumentException("Outline is not a rect shadow");
}
+ // TODO replacing the algorithm here to create better shadow
+
float shadowSize = elevationToShadow(elevation);
int saved = modifyCanvas(canvas, shadowSize);
if (saved == -1) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index df3ce19b05e5..04fdae9f2db4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -106,7 +106,7 @@ import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+import static android.os._Original_Build.VERSION_CODES.JELLY_BEAN_MR1;
import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE;
/**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 00394763f1b3..2274b90da49e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -321,6 +321,11 @@ public class BridgePackageManager extends PackageManager {
}
@Override
+ public boolean isInstantApp(String packageName) {
+ return false;
+ }
+
+ @Override
public int getInstantAppCookieMaxSize() {
return 0;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
index 5386b1758682..7f8d9928d7ce 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
@@ -16,13 +16,13 @@
package com.android.layoutlib.bridge.bars;
-import android.os.Build.VERSION_CODES;
+import android.os._Original_Build.VERSION_CODES;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import static android.os.Build.VERSION_CODES.*;
+import static android.os._Original_Build.VERSION_CODES.*;
/**
* Various helper methods to simulate older versions of platform.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index a6e5fb841bff..8bb2c593f7a1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -49,7 +49,7 @@ import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
-import static android.os.Build.VERSION_CODES.LOLLIPOP;
+import static android.os._Original_Build.VERSION_CODES.LOLLIPOP;
/**
* Base "bar" class for the window decor around the the edited layout.
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
new file mode 100644
index 000000000000..4f3ed605dbb1
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml
new file mode 100644
index 000000000000..59dbbec82bf7
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+
+ <Button
+ android:layout_marginLeft="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:elevation="48dp"
+ android:stateListAnimator="@null"/>
+
+ <Button
+ android:layout_marginRight="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:elevation="48dp"
+ android:stateListAnimator="@null"/>
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+
+ <Button
+ android:layout_marginLeft="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:elevation="0dp"
+ android:stateListAnimator="@null"/>
+
+ <Button
+ android:layout_marginRight="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:elevation="100dp"
+ android:stateListAnimator="@null"/>
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+
+ <Button
+ android:layout_marginLeft="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:elevation="12dp"
+ android:stateListAnimator="@null"/>
+
+ <Button
+ android:layout_marginRight="40dp"
+ android:layout_width="48dp"
+ android:layout_height="40dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:elevation="36dp"
+ android:stateListAnimator="@null"/>
+
+ </RelativeLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index b15ee95187e7..c83d2e4ecea3 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -34,7 +34,7 @@ import android.util.BridgeXmlPullAttributesTest;
@SuiteClasses({
RenderTests.class, LayoutParserWrapperTest.class,
BridgeXmlBlockParserTest.class, BridgeXmlPullAttributesTest.class,
- Matrix_DelegateTest.class, TestDelegates.class
+ Matrix_DelegateTest.class, TestDelegates.class, PerformanceTests.class
})
public class Main {
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
index 9e60f0f6d36b..7199781349a6 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
@@ -424,4 +424,9 @@ public class RenderTests extends RenderTestBase {
assertNotEquals(0, outValue.data);
assertTrue(sRenderMessages.isEmpty());
}
+
+ @Test
+ public void testRectangleShadow() throws Exception {
+ renderAndVerify("shadows_test.xml", "shadows_test.png");
+ }
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index bed5806aadad..d59b41980179 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -37,6 +37,7 @@ import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* Class that generates a new JAR from a list of classes, some of which are to be kept as-is
@@ -127,7 +128,10 @@ public class AsmGenerator {
// Create the map of classes to rename.
mRenameClasses = new HashMap<>();
mClassesNotRenamed = new HashSet<>();
- String[] renameClasses = createInfo.getRenamedClasses();
+ String[] renameClasses = Stream.concat(
+ Arrays.stream(createInfo.getRenamedClasses()),
+ Arrays.stream(createInfo.getRefactoredClasses()))
+ .toArray(String[]::new);
int n = renameClasses.length;
for (int i = 0; i < n; i += 2) {
assert i + 1 < n;
@@ -140,7 +144,10 @@ public class AsmGenerator {
// Create a map of classes to be refactored.
mRefactorClasses = new HashMap<>();
- String[] refactorClasses = createInfo.getJavaPkgClasses();
+ String[] refactorClasses = Stream.concat(
+ Arrays.stream(createInfo.getJavaPkgClasses()),
+ Arrays.stream(createInfo.getRefactoredClasses()))
+ .toArray(String[]::new);
n = refactorClasses.length;
for (int i = 0; i < n; i += 2) {
assert i + 1 < n;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index a8582c60bc64..b0aa3c2989a5 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -36,66 +36,42 @@ import java.util.Set;
*/
public final class CreateInfo implements ICreateInfo {
- /**
- * Returns the list of class from layoutlib_create to inject in layoutlib.
- * The list can be empty but must not be null.
- */
@Override
public Class<?>[] getInjectedClasses() {
return INJECTED_CLASSES;
}
- /**
- * Returns the list of methods to rewrite as delegates.
- * The list can be empty but must not be null.
- */
@Override
public String[] getDelegateMethods() {
return DELEGATE_METHODS;
}
- /**
- * Returns the list of classes on which to delegate all native methods.
- * The list can be empty but must not be null.
- */
@Override
public String[] getDelegateClassNatives() {
return DELEGATE_CLASS_NATIVES;
}
- /**
- * Returns the list of classes to rename, must be an even list: the binary FQCN
- * of class to replace followed by the new FQCN.
- * The list can be empty but must not be null.
- */
@Override
public String[] getRenamedClasses() {
return RENAMED_CLASSES;
}
- /**
- * Returns the list of classes for which the methods returning them should be deleted.
- * The array contains a list of null terminated section starting with the name of the class
- * to rename in which the methods are deleted, followed by a list of return types identifying
- * the methods to delete.
- * The list can be empty but must not be null.
- */
@Override
public String[] getDeleteReturns() {
return DELETE_RETURNS;
}
- /**
- * Returns the list of classes to refactor, must be an even list: the binary FQCN of class to
- * replace followed by the new FQCN. All references to the old class should be updated to the
- * new class. The list can be empty but must not be null.
- */
@Override
public String[] getJavaPkgClasses() {
return JAVA_PKG_CLASSES;
}
@Override
+ public String[] getRefactoredClasses() {
+ return REFACTOR_CLASSES;
+ }
+
+ @Override
public Set<String> getExcludedClasses() {
String[] refactoredClasses = getJavaPkgClasses();
int count = refactoredClasses.length / 2 + EXCLUDED_CLASSES.length;
@@ -333,10 +309,22 @@ public final class CreateInfo implements ICreateInfo {
"java.text.SimpleDateFormat", "android.icu.text.SimpleDateFormat",
};
+ /**
+ * List of classes to refactor. This is similar to combining {@link #getRenamedClasses()} and
+ * {@link #getJavaPkgClasses()}.
+ * Classes included here will be renamed and then all their references in any other classes
+ * will be also modified.
+ * FQCN of class to refactor followed by its new FQCN.
+ */
+ private final static String[] REFACTOR_CLASSES =
+ new String[] {
+ "android.os.Build", "android.os._Original_Build",
+ };
+
private final static String[] EXCLUDED_CLASSES =
new String[] {
"android.preference.PreferenceActivity",
- "org.kxml2.io.KXmlParser"
+ "org.kxml2.io.KXmlParser",
};
/**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
index 48abde4517e6..eca1c078faec 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -52,6 +52,15 @@ public interface ICreateInfo {
String[] getRenamedClasses();
/**
+ * List of classes to refactor. This is similar to combining {@link #getRenamedClasses()} and
+ * {@link #getJavaPkgClasses()}.
+ * Classes included here will be renamed and then all their references in any other classes
+ * will be also modified.
+ * FQCN of class to refactor followed by its new FQCN.
+ */
+ String[] getRefactoredClasses();
+
+ /**
* Returns the list of classes for which the methods returning them should be deleted.
* The array contains a list of null terminated section starting with the name of the class
* to rename in which the methods are deleted, followed by a list of return types identifying
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 4d5d5d2c4a6e..e718fb9133ee 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -35,6 +35,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
@@ -54,8 +55,6 @@ import static org.junit.Assert.assertTrue;
* Unit tests for some methods of {@link AsmGenerator}.
*/
public class AsmGeneratorTest {
-
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
private MockLog mLog;
private ArrayList<String> mOsJarPath;
private String mOsDestJar;
@@ -81,6 +80,7 @@ public class AsmGeneratorTest {
@After
public void tearDown() throws Exception {
if (mTempFile != null) {
+ //noinspection ResultOfMethodCallIgnored
mTempFile.delete();
mTempFile = null;
}
@@ -89,23 +89,7 @@ public class AsmGeneratorTest {
@Test
public void testClassRenaming() throws IOException, LogAbortException {
- ICreateInfo ci = new ICreateInfo() {
- @Override
- public Class<?>[] getInjectedClasses() {
- // classes to inject in the final JAR
- return new Class<?>[0];
- }
-
- @Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
- }
-
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public String[] getRenamedClasses() {
// classes to rename (so that we can replace them)
@@ -114,37 +98,6 @@ public class AsmGeneratorTest {
"not.an.actual.ClassName", "anoter.fake.NewClassName",
};
}
-
- @Override
- public String[] getJavaPkgClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Set<String> getExcludedClasses() {
- return null;
- }
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
- return Collections.emptyMap();
- }
};
AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -154,7 +107,7 @@ public class AsmGeneratorTest {
new String[] { // include classes
"**"
},
- Collections.<String>emptySet() /* excluded classes */,
+ Collections.emptySet() /* excluded classes */,
new String[]{} /* include files */);
aa.analyze();
agen.generate();
@@ -165,8 +118,8 @@ public class AsmGeneratorTest {
}
@Test
- public void testClassRefactoring() throws IOException, LogAbortException {
- ICreateInfo ci = new ICreateInfo() {
+ public void testJavaClassRefactoring() throws IOException, LogAbortException {
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Class<?>[] getInjectedClasses() {
// classes to inject in the final JAR
@@ -176,22 +129,6 @@ public class AsmGeneratorTest {
}
@Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getRenamedClasses() {
- // classes to rename (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
public String[] getJavaPkgClasses() {
// classes to refactor (so that we can replace them)
return new String[] {
@@ -203,27 +140,6 @@ public class AsmGeneratorTest {
public Set<String> getExcludedClasses() {
return Collections.singleton("java.lang.JavaClass");
}
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
- return Collections.emptyMap();
- }
};
AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -233,7 +149,7 @@ public class AsmGeneratorTest {
new String[] { // include classes
"**"
},
- Collections.<String>emptySet(),
+ Collections.emptySet(),
new String[] { /* include files */
"mock_android/data/data*"
});
@@ -242,47 +158,64 @@ public class AsmGeneratorTest {
Map<String, ClassReader> output = new TreeMap<>();
Map<String, InputStream> filesFound = new TreeMap<>();
parseZip(mOsDestJar, output, filesFound);
- boolean injectedClassFound = false;
+ RecordingClassVisitor cv = new RecordingClassVisitor();
for (ClassReader cr: output.values()) {
- TestClassVisitor cv = new TestClassVisitor();
cr.accept(cv, 0);
- injectedClassFound |= cv.mInjectedClassFound;
}
- assertTrue(injectedClassFound);
+ assertTrue(cv.mVisitedClasses.contains(
+ "com/android/tools/layoutlib/create/dataclass/JavaClass"));
+ assertFalse(cv.mVisitedClasses.contains(
+ JAVA_CLASS_NAME));
assertArrayEquals(new String[] {"mock_android/data/dataFile"},
filesFound.keySet().toArray());
}
@Test
- public void testClassExclusion() throws IOException, LogAbortException {
- ICreateInfo ci = new ICreateInfo() {
+ public void testClassRefactoring() throws IOException, LogAbortException {
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Class<?>[] getInjectedClasses() {
- return new Class<?>[0];
- }
-
- @Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
+ // classes to inject in the final JAR
+ return new Class<?>[] {
+ com.android.tools.layoutlib.create.dataclass.JavaClass.class
+ };
}
@Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
+ public String[] getRefactoredClasses() {
+ // classes to refactor (so that we can replace them)
+ return new String[] {
+ "mock_android.view.View", "mock_android.view._Original_View",
+ };
}
+ };
- @Override
- public String[] getRenamedClasses() {
- // classes to rename (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
+ AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
- @Override
- public String[] getJavaPkgClasses() {
- // classes to refactor (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
+ AsmAnalyzer aa = new AsmAnalyzer(mLog, mOsJarPath, agen,
+ null, // derived from
+ new String[] { // include classes
+ "**"
+ },
+ Collections.emptySet(),
+ new String[] {});
+ aa.analyze();
+ agen.generate();
+ Map<String, ClassReader> output = new TreeMap<>();
+ parseZip(mOsDestJar, output, new TreeMap<>());
+ RecordingClassVisitor cv = new RecordingClassVisitor();
+ for (ClassReader cr: output.values()) {
+ cr.accept(cv, 0);
+ }
+ assertTrue(cv.mVisitedClasses.contains(
+ "mock_android/view/_Original_View"));
+ assertFalse(cv.mVisitedClasses.contains(
+ "mock_android/view/View"));
+ }
+ @Test
+ public void testClassExclusion() throws IOException, LogAbortException {
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Set<String> getExcludedClasses() {
Set<String> set = new HashSet<>(2);
@@ -290,27 +223,6 @@ public class AsmGeneratorTest {
set.add("java.lang.JavaClass");
return set;
}
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
- return Collections.emptyMap();
- }
};
AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -340,55 +252,7 @@ public class AsmGeneratorTest {
public void testMethodInjection() throws IOException, LogAbortException,
ClassNotFoundException, IllegalAccessException, InstantiationException,
NoSuchMethodException, InvocationTargetException {
- ICreateInfo ci = new ICreateInfo() {
- @Override
- public Class<?>[] getInjectedClasses() {
- return new Class<?>[0];
- }
-
- @Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getRenamedClasses() {
- // classes to rename (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getJavaPkgClasses() {
- // classes to refactor (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Set<String> getExcludedClasses() {
- return Collections.emptySet();
- }
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return Collections.singletonMap("mock_android.util.EmptyArray",
@@ -474,97 +338,94 @@ public class AsmGeneratorTest {
}
}
- private class TestClassVisitor extends ClassVisitor {
+ /**
+ * {@link ClassVisitor} that records every class that sees.
+ */
+ private static class RecordingClassVisitor extends ClassVisitor {
+ private Set<String> mVisitedClasses = new HashSet<>();
- boolean mInjectedClassFound = false;
-
- TestClassVisitor() {
+ private RecordingClassVisitor() {
super(Main.ASM_VERSION);
}
+ private void addClass(String className) {
+ if (className == null) {
+ return;
+ }
+
+ int pos = className.indexOf('$');
+ if (pos > 0) {
+ // For inner classes, add also the base class
+ mVisitedClasses.add(className.substring(0, pos));
+ }
+ mVisitedClasses.add(className);
+ }
+
@Override
- public void visit(int version, int access, String name, String signature,
- String superName, String[] interfaces) {
- assertTrue(!getBase(name).equals(JAVA_CLASS_NAME));
- if (name.equals("com/android/tools/layoutlib/create/dataclass/JavaClass")) {
- mInjectedClassFound = true;
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ addClass(superName);
+ Arrays.stream(interfaces).forEach(this::addClass);
+ }
+
+ private void processType(Type type) {
+ switch (type.getSort()) {
+ case Type.OBJECT:
+ addClass(type.getInternalName());
+ break;
+ case Type.ARRAY:
+ addClass(type.getElementType().getInternalName());
+ break;
+ case Type.METHOD:
+ processType(type.getReturnType());
+ Arrays.stream(type.getArgumentTypes()).forEach(this::processType);
+ break;
}
- super.visit(version, access, name, signature, superName, interfaces);
}
@Override
- public FieldVisitor visitField(int access, String name, String desc,
- String signature, Object value) {
- assertTrue(testType(Type.getType(desc)));
+ public FieldVisitor visitField(int access, String name, String desc, String signature,
+ Object value) {
+ processType(Type.getType(desc));
return super.visitField(access, name, desc, signature, value);
}
- @SuppressWarnings("hiding")
@Override
- public MethodVisitor visitMethod(int access, String name, String desc,
- String signature, String[] exceptions) {
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
return new MethodVisitor(Main.ASM_VERSION, mv) {
@Override
- public void visitFieldInsn(int opcode, String owner, String name,
- String desc) {
- assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
- assertTrue(testType(Type.getType(desc)));
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ addClass(owner);
+ processType(Type.getType(desc));
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitLdcInsn(Object cst) {
if (cst instanceof Type) {
- assertTrue(testType((Type)cst));
+ processType((Type) cst);
}
super.visitLdcInsn(cst);
}
@Override
public void visitTypeInsn(int opcode, String type) {
- assertTrue(!getBase(type).equals(JAVA_CLASS_NAME));
+ addClass(type);
super.visitTypeInsn(opcode, type);
}
@Override
- public void visitMethodInsn(int opcode, String owner, String name,
- String desc, boolean itf) {
- assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
- assertTrue(testType(Type.getType(desc)));
+ public void visitMethodInsn(int opcode, String owner, String name, String desc,
+ boolean itf) {
+ addClass(owner);
+ processType(Type.getType(desc));
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
};
}
-
- private boolean testType(Type type) {
- int sort = type.getSort();
- if (sort == Type.OBJECT) {
- assertTrue(!getBase(type.getInternalName()).equals(JAVA_CLASS_NAME));
- } else if (sort == Type.ARRAY) {
- assertTrue(!getBase(type.getElementType().getInternalName())
- .equals(JAVA_CLASS_NAME));
- } else if (sort == Type.METHOD) {
- boolean r = true;
- for (Type t : type.getArgumentTypes()) {
- r &= testType(t);
- }
- return r & testType(type.getReturnType());
- }
- return true;
- }
-
- private String getBase(String className) {
- if (className == null) {
- return null;
- }
- int pos = className.indexOf('$');
- if (pos > 0) {
- return className.substring(0, pos);
- }
- return className;
- }
}
}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java
new file mode 100644
index 000000000000..ad7cb9a0ed40
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.tools.layoutlib.create;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+class CreateInfoAdapter implements ICreateInfo {
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+ @Override
+ public Class<?>[] getInjectedClasses() {
+ return new Class<?>[0];
+ }
+
+ @Override
+ public String[] getDelegateMethods() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getDelegateClassNatives() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getRenamedClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getRefactoredClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getDeleteReturns() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getJavaPkgClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public Set<String> getExcludedClasses() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public String[] getPromotedFields() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getPromotedClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
+ return Collections.emptyMap();
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index f79033200568..4268f24a0999 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -236,11 +236,11 @@ public class WifiEnterpriseConfig implements Parcelable {
public static final int TTLS = 2;
/** EAP-Password */
public static final int PWD = 3;
- /** EAP-Subscriber Identity Module */
+ /** EAP-Subscriber Identity Module [RFC-4186] */
public static final int SIM = 4;
- /** EAP-Authentication and Key Agreement */
+ /** EAP-Authentication and Key Agreement [RFC-4187] */
public static final int AKA = 5;
- /** EAP-Authentication and Key Agreement Prime */
+ /** EAP-Authentication and Key Agreement Prime [RFC-5448] */
public static final int AKA_PRIME = 6;
/** Hotspot 2.0 r2 OSEN */
public static final int UNAUTH_TLS = 7;
@@ -263,11 +263,11 @@ public class WifiEnterpriseConfig implements Parcelable {
public static final int MSCHAPV2 = 3;
/** Generic Token Card */
public static final int GTC = 4;
- /** EAP-Subscriber Identity Module */
+ /** EAP-Subscriber Identity Module [RFC-4186] */
public static final int SIM = 5;
- /** EAP-Authentication and Key Agreement */
+ /** EAP-Authentication and Key Agreement [RFC-4187] */
public static final int AKA = 6;
- /** EAP-Authentication and Key Agreement Prime */
+ /** EAP-Authentication and Key Agreement Prime [RFC-5448] */
public static final int AKA_PRIME = 7;
private static final String AUTH_PREFIX = "auth=";
private static final String AUTHEAP_PREFIX = "autheap=";
@@ -756,8 +756,8 @@ public class WifiEnterpriseConfig implements Parcelable {
* key entry when the config is saved and removing the key entry when
* the config is removed.
- * @param privateKey
- * @param clientCertificate
+ * @param privateKey a PrivateKey instance for the end certificate.
+ * @param clientCertificate an X509Certificate representing the end certificate.
* @throws IllegalArgumentException for an invalid key or certificate.
*/
public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) {
@@ -775,9 +775,11 @@ public class WifiEnterpriseConfig implements Parcelable {
* with this configuration. The framework takes care of installing the
* key entry when the config is saved and removing the key entry when
* the config is removed.
-
- * @param privateKey
- * @param clientCertificateChain
+ *
+ * @param privateKey a PrivateKey instance for the end certificate.
+ * @param clientCertificateChain an array of X509Certificate instances which starts with
+ * end certificate and continues with additional CA certificates necessary to
+ * link the end certificate with some root certificate known by the authenticator.
* @throws IllegalArgumentException for an invalid key or certificate.
*/
public void setClientKeyEntryWithCertificateChain(PrivateKey privateKey,
@@ -835,7 +837,15 @@ public class WifiEnterpriseConfig implements Parcelable {
}
/**
- * Get the complete client certificate chain
+ * Get the complete client certificate chain in the same order as it was last supplied.
+ *
+ * <p>If the chain was last supplied by a call to
+ * {@link #setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate)}
+ * with a non-null * certificate instance, a single-element array containing the certificate
+ * will be * returned. If {@link #setClientKeyEntryWithCertificateChain(
+ * java.security.PrivateKey, java.security.cert.X509Certificate[])} was last called with a
+ * non-empty array, this array will be returned in the same order as it was supplied.
+ * Otherwise, {@code null} will be returned.
*
* @return X.509 client certificates
*/
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index 57b98e984f17..59fe1ee6bc80 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -31,7 +31,7 @@ import java.lang.ref.WeakReference;
* {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
* class provides functionality common to both publish and subscribe discovery sessions:
* <ul>
- * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])}.
+ * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} method.
* <li>Creating a network-specifier when requesting a Aware connection:
* {@link #createNetworkSpecifier(PeerHandle, byte[])}.
* </ul>
@@ -247,8 +247,8 @@ public class DiscoverySession {
}
/**
- * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
- * WiFi Aware connection to the specified peer. The
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * unencrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
@@ -256,7 +256,58 @@ public class DiscoverySession {
* discovery or communication (in such scenarios the MAC address of the peer is shielded by
* an opaque peer ID handle). If a Aware connection is needed to a peer discovered using other
* OOB (out-of-band) mechanism then use the alternative
- * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
+ * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} method - which uses the
+ * peer's MAC address.
+ * <p>
+ * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
+ * and a Publisher is a RESPONDER.
+ *
+ * @param peerHandle The peer's handle obtained through
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
+ * or
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
+ * On a RESPONDER this value is used to gate the acceptance of a connection
+ * request from only that peer. A RESPONDER may specify a null - indicating
+ * that it will accept connection requests from any device.
+ *
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ *
+ * @hide
+ */
+ public String createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) {
+ if (mTerminated) {
+ Log.w(TAG, "createNetworkSpecifierOpen: called on terminated session");
+ return null;
+ } else {
+ WifiAwareManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.w(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
+ return null;
+ }
+
+ int role = this instanceof SubscribeDiscoverySession
+ ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+ : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
+
+ return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, null);
+ }
+ }
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * encrypted WiFi Aware connection (link) to the specified peer. The
+ * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+ * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
+ * <p>
+ * This method should be used when setting up a connection with a peer discovered through Aware
+ * discovery or communication (in such scenarios the MAC address of the peer is shielded by
+ * an opaque peer ID handle). If a Aware connection is needed to a peer discovered using other
+ * OOB (out-of-band) mechanism then use the alternative
+ * {@link WifiAwareSession#createNetworkSpecifierPmk(int, byte[], byte[])} method - which uses the
* peer's MAC address.
* <p>
* Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
@@ -267,29 +318,34 @@ public class DiscoverySession {
* byte[], java.util.List)} or
* {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
- * from only that peer. A RESPONDER may specified a null - indicating that
+ * from only that peer. A RESPONDER may specify a null - indicating that
* it will accept connection requests from any device.
- * @param token An arbitrary token (message) to be used to match connection initiation request
- * to a responder setup. A RESPONDER is set up with a {@code token} which must
- * be matched by the token provided by the INITIATOR. A null token is permitted
- * on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
- * not the same as a null token and requires the peer token to be empty as well.
+ * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
+ * encrypting the data-path. Use the
+ * {@link #createNetworkSpecifierOpen(PeerHandle)} to specify an open (unencrypted)
+ * link.
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
+ *
+ * @hide
*/
- public String createNetworkSpecifier(@Nullable PeerHandle peerHandle,
- @Nullable byte[] token) {
+ public String createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle,
+ @NonNull byte[] pmk) {
+ if (pmk == null || pmk.length == 0) {
+ throw new IllegalArgumentException("PMK must not be null or empty");
+ }
+
if (mTerminated) {
- Log.w(TAG, "createNetworkSpecifier: called on terminated session");
+ Log.w(TAG, "createNetworkSpecifierPmk: called on terminated session");
return null;
} else {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
- Log.w(TAG, "createNetworkSpecifier: called post GC on WifiAwareManager");
+ Log.w(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
return null;
}
@@ -297,7 +353,30 @@ public class DiscoverySession {
? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
- return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, token);
+ return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, pmk);
}
}
+
+ /**
+ * Place-holder for {@code createNetworkSpecifierOpen(PeerHandle)}. Present to enable
+ * development of replacements CL without causing an API change. Will be removed when new
+ * APIs are exposed.
+ *
+ * @param peerHandle The peer's handle obtained through
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
+ * byte[], java.util.List)} or
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
+ * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
+ * from only that peer. A RESPONDER may specify a null - indicating that
+ * it will accept connection requests from any device.
+ * @param token Deprecated and ignored.
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ */
+ public String createNetworkSpecifier(@Nullable PeerHandle peerHandle, @Nullable byte[] token) {
+ return createNetworkSpecifierOpen(peerHandle);
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 0eb6a3d157c3..3d784ba02fd6 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -130,55 +130,34 @@ public class WifiAwareManager {
*/
/**
- * TYPE_1A: role, client_id, session_id, peer_id, token
+ * TYPE: in band, specific peer: role, client_id, session_id, peer_id, pmk optional
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1A = 0;
+ public static final int NETWORK_SPECIFIER_TYPE_IB = 0;
/**
- * TYPE_1B: role, client_id, session_id, peer_id [only permitted for RESPONDER]
+ * TYPE: in band, any peer: role, client_id, session_id, pmk optional
+ * [only permitted for RESPONDER]
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1B = 1;
+ public static final int NETWORK_SPECIFIER_TYPE_IB_ANY_PEER = 1;
/**
- * TYPE_1C: role, client_id, session_id, token [only permitted for RESPONDER]
+ * TYPE: out-of-band: role, client_id, peer_mac, pmk optional
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1C = 2;
+ public static final int NETWORK_SPECIFIER_TYPE_OOB = 2;
/**
- * TYPE_1C: role, client_id, session_id [only permitted for RESPONDER]
+ * TYPE: out-of-band, any peer: role, client_id, pmk optional
+ * [only permitted for RESPONDER]
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1D = 3;
+ public static final int NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER = 3;
- /**
- * TYPE_2A: role, client_id, peer_mac, token
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2A = 4;
-
- /**
- * TYPE_2B: role, client_id, peer_mac [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2B = 5;
-
- /**
- * TYPE_2C: role, client_id, token [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2C = 6;
-
- /**
- * TYPE_2D: role, client_id [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2D = 7;
/** @hide */
- public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_2D;
+ public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER;
/** @hide */
public static final String NETWORK_SPECIFIER_KEY_TYPE = "type";
@@ -199,7 +178,7 @@ public class WifiAwareManager {
public static final String NETWORK_SPECIFIER_KEY_PEER_MAC = "peer_mac";
/** @hide */
- public static final String NETWORK_SPECIFIER_KEY_TOKEN = "token";
+ public static final String NETWORK_SPECIFIER_KEY_PMK = "pmk";
/**
* Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed.
@@ -494,23 +473,15 @@ public class WifiAwareManager {
/** @hide */
public String createNetworkSpecifier(int clientId, int role, int sessionId,
- PeerHandle peerHandle, byte[] token) {
+ PeerHandle peerHandle, @Nullable byte[] pmk) {
if (VDBG) {
Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId
+ ", peerHandle=" + ((peerHandle == null) ? peerHandle : peerHandle.peerId)
- + ", token=" + token);
+ + ", pmk=" + ((pmk == null) ? "null" : "non-null"));
}
- int type;
- if (token != null && peerHandle != null) {
- type = NETWORK_SPECIFIER_TYPE_1A;
- } else if (token == null && peerHandle != null) {
- type = NETWORK_SPECIFIER_TYPE_1B;
- } else if (token != null && peerHandle == null) {
- type = NETWORK_SPECIFIER_TYPE_1C;
- } else {
- type = NETWORK_SPECIFIER_TYPE_1D;
- }
+ int type = (peerHandle == null) ? NETWORK_SPECIFIER_TYPE_IB_ANY_PEER
+ : NETWORK_SPECIFIER_TYPE_IB;
if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
&& role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
@@ -519,10 +490,6 @@ public class WifiAwareManager {
+ "specifier");
}
if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
- if (token == null) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
- }
if (peerHandle == null) {
throw new IllegalArgumentException(
"createNetworkSpecifier: Invalid peer handle (value of null) - not "
@@ -540,10 +507,11 @@ public class WifiAwareManager {
if (peerHandle != null) {
json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerHandle.peerId);
}
- if (token != null) {
- json.put(NETWORK_SPECIFIER_KEY_TOKEN,
- Base64.encodeToString(token, 0, token.length, Base64.DEFAULT));
+ if (pmk == null) {
+ pmk = new byte[0];
}
+ json.put(NETWORK_SPECIFIER_KEY_PMK,
+ Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT));
} catch (JSONException e) {
return "";
}
@@ -553,21 +521,14 @@ public class WifiAwareManager {
/** @hide */
public String createNetworkSpecifier(int clientId, @DataPathRole int role,
- @Nullable byte[] peer, @Nullable byte[] token) {
+ @Nullable byte[] peer, @Nullable byte[] pmk) {
if (VDBG) {
- Log.v(TAG, "createNetworkSpecifier: role=" + role + ", token=" + token);
+ Log.v(TAG, "createNetworkSpecifier: role=" + role
+ + ", pmk=" + ((pmk == null) ? "null" : "non-null"));
}
- int type;
- if (token != null && peer != null) {
- type = NETWORK_SPECIFIER_TYPE_2A;
- } else if (token == null && peer != null) {
- type = NETWORK_SPECIFIER_TYPE_2B;
- } else if (token != null && peer == null) {
- type = NETWORK_SPECIFIER_TYPE_2C;
- } else { // both are null
- type = NETWORK_SPECIFIER_TYPE_2D;
- }
+ int type = (peer == null) ?
+ NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER : NETWORK_SPECIFIER_TYPE_OOB;
if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
&& role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
@@ -576,20 +537,14 @@ public class WifiAwareManager {
+ "specifier");
}
if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
- if (peer == null || peer.length != 6) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid peer MAC address");
- }
- if (token == null) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
- }
- } else {
- if (peer != null && peer.length != 6) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid peer MAC address");
+ if (peer == null) {
+ throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC "
+ + "address - null not permitted on INITIATOR");
}
}
+ if (peer != null && peer.length != 6) {
+ throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address");
+ }
JSONObject json;
try {
@@ -600,10 +555,11 @@ public class WifiAwareManager {
if (peer != null) {
json.put(NETWORK_SPECIFIER_KEY_PEER_MAC, new String(HexEncoding.encode(peer)));
}
- if (token != null) {
- json.put(NETWORK_SPECIFIER_KEY_TOKEN,
- Base64.encodeToString(token, 0, token.length, Base64.DEFAULT));
+ if (pmk == null) {
+ pmk = new byte[0];
}
+ json.put(NETWORK_SPECIFIER_KEY_PMK,
+ Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT));
} catch (JSONException e) {
return "";
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 86969200bc46..856066efff62 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -183,47 +183,114 @@ public class WifiAwareSession {
}
/**
- * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
- * WiFi Aware connection to the specified peer. The
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * unencrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
- * {@link DiscoverySession#createNetworkSpecifier(PeerHandle,
- * byte[])}.
+ * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)}.
*
* @param role The role of this device:
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
* @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
* value is used to gate the acceptance of a connection request from only that
- * peer. A RESPONDER may specified a null - indicating that it will accept
+ * peer. A RESPONDER may specify a null - indicating that it will accept
* connection requests from any device.
- * @param token An arbitrary token (message) to be used to match connection initiation request
- * to a responder setup. A RESPONDER is set up with a {@code token} which must
- * be matched by the token provided by the INITIATOR. A null token is permitted
- * on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
- * not the same as a null token and requires the peer token to be empty as well.
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
+ *
+ * @hide
*/
- public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
- @Nullable byte[] peer, @Nullable byte[] token) {
+ public String createNetworkSpecifierOpen(@WifiAwareManager.DataPathRole int role,
+ @Nullable byte[] peer) {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
- Log.e(TAG, "createNetworkSpecifier: called post GC on WifiAwareManager");
+ Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
return "";
}
if (mTerminated) {
- Log.e(TAG, "createNetworkSpecifier: called after termination");
+ Log.e(TAG, "createNetworkSpecifierOpen: called after termination");
return "";
}
- return mgr.createNetworkSpecifier(mClientId, role, peer, token);
+ return mgr.createNetworkSpecifier(mClientId, role, peer, null);
+ }
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * encrypted WiFi Aware connection (link) to the specified peer. The
+ * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+ * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
+ * <p>
+ * This API is targeted for applications which can obtain the peer MAC address using OOB
+ * (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
+ * when using Aware discovery use the alternative network specifier method -
+ * {@link DiscoverySession#createNetworkSpecifierPmk(PeerHandle, byte[])}}.
+ *
+ * @param role The role of this device:
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
+ * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
+ * value is used to gate the acceptance of a connection request from only that
+ * peer. A RESPONDER may specify a null - indicating that it will accept
+ * connection requests from any device.
+ * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
+ * encrypting the data-path. Use the {@link #createNetworkSpecifierOpen(int, byte[])}
+ * to specify an open (unencrypted) link.
+ *
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ *
+ * @hide
+ */
+ public String createNetworkSpecifierPmk(@WifiAwareManager.DataPathRole int role,
+ @Nullable byte[] peer, @NonNull byte[] pmk) {
+ WifiAwareManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
+ return "";
+ }
+ if (mTerminated) {
+ Log.e(TAG, "createNetworkSpecifierPmk: called after termination");
+ return "";
+ }
+ if (pmk == null || pmk.length == 0) {
+ throw new IllegalArgumentException("PMK must not be null or empty");
+ }
+ return mgr.createNetworkSpecifier(mClientId, role, peer, pmk);
+ }
+
+ /**
+ * Place-holder for {@code #createNetworkSpecifierOpen(int, byte[])}. Present to enable
+ * development of replacements CL without causing an API change. Will be removed when new
+ * APIs are exposed.
+ *
+ * @param role The role of this device:
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
+ * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
+ * value is used to gate the acceptance of a connection request from only that
+ * peer. A RESPONDER may specify a null - indicating that it will accept
+ * connection requests from any device.
+ * @param token Deprecated and ignored.
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ */
+ public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
+ @Nullable byte[] peer, @Nullable byte[] token) {
+ return createNetworkSpecifierOpen(role, peer);
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index c4d2d32512a2..d0aedbad03b5 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -89,11 +89,29 @@ public class WifiEnterpriseConfigTest {
@Test
public void testSetClientKeyEntryWithNull() {
mEnterpriseConfig.setClientKeyEntry(null, null);
- assertEquals(null, mEnterpriseConfig.getClientCertificateChain());
- assertEquals(null, mEnterpriseConfig.getClientCertificate());
+ assertNull(mEnterpriseConfig.getClientCertificateChain());
+ assertNull(mEnterpriseConfig.getClientCertificate());
mEnterpriseConfig.setClientKeyEntryWithCertificateChain(null, null);
- assertEquals(null, mEnterpriseConfig.getClientCertificateChain());
- assertEquals(null, mEnterpriseConfig.getClientCertificate());
+ assertNull(mEnterpriseConfig.getClientCertificateChain());
+ assertNull(mEnterpriseConfig.getClientCertificate());
+
+ // Setting the client certificate to null should clear the existing chain.
+ PrivateKey clientKey = FakeKeys.RSA_KEY1;
+ X509Certificate clientCert0 = FakeKeys.CLIENT_CERT;
+ X509Certificate clientCert1 = FakeKeys.CA_CERT1;
+ mEnterpriseConfig.setClientKeyEntry(clientKey, clientCert0);
+ assertNotNull(mEnterpriseConfig.getClientCertificate());
+ mEnterpriseConfig.setClientKeyEntry(null, null);
+ assertNull(mEnterpriseConfig.getClientCertificate());
+ assertNull(mEnterpriseConfig.getClientCertificateChain());
+
+ // Setting the chain to null should clear the existing chain.
+ X509Certificate[] clientChain = new X509Certificate[] {clientCert0, clientCert1};
+ mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
+ assertNotNull(mEnterpriseConfig.getClientCertificateChain());
+ mEnterpriseConfig.setClientKeyEntryWithCertificateChain(null, null);
+ assertNull(mEnterpriseConfig.getClientCertificate());
+ assertNull(mEnterpriseConfig.getClientCertificateChain());
}
@Test
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 7f68f6f128da..992958b84e1a 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -973,11 +973,11 @@ public class WifiAwareManagerTest {
final int sessionId = 123;
final PeerHandle peerHandle = new PeerHandle(123412);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
- final String token = "Some arbitrary token string - can really be anything";
+ final byte[] pmk = "Some arbitrary byte array".getBytes();
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
- String tokenB64 = Base64.encodeToString(token.getBytes(), Base64.DEFAULT);
+ String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT);
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
@@ -1008,9 +1008,8 @@ public class WifiAwareManagerTest {
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
- // (3) request a network specifier from the session
- String networkSpecifier = publishSession.getValue().createNetworkSpecifier(peerHandle,
- token.getBytes());
+ // (3) request an open (unencrypted) network specifier from the session
+ String networkSpecifier = publishSession.getValue().createNetworkSpecifierOpen(peerHandle);
// validate format
JSONObject jsonObject = new JSONObject(networkSpecifier);
@@ -1022,8 +1021,22 @@ public class WifiAwareManagerTest {
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID)));
collector.checkThat("peer_id", peerHandle.peerId,
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID)));
- collector.checkThat("token", tokenB64,
- equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_TOKEN)));
+
+ // (4) request an encrypted (PMK) network specifier from the session
+ networkSpecifier = publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk);
+
+ // validate format
+ jsonObject = new JSONObject(networkSpecifier);
+ collector.checkThat("role", role,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
+ collector.checkThat("client_id", clientId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID)));
+ collector.checkThat("session_id", sessionId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID)));
+ collector.checkThat("peer_id", peerHandle.peerId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID)));
+ collector.checkThat("pmk", pmkB64 ,
+ equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK)));
verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
mockPublishSession, mockRttListener);
@@ -1039,9 +1052,9 @@ public class WifiAwareManagerTest {
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final byte[] someMac = HexEncoding.decode("000102030405".toCharArray(), false);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
- final String token = "Some arbitrary token string - can really be anything";
+ final byte[] pmk = "Some arbitrary pmk data".getBytes();
- String tokenB64 = Base64.encodeToString(token.getBytes(), Base64.DEFAULT);
+ String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT);
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
@@ -1060,10 +1073,10 @@ public class WifiAwareManagerTest {
inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
WifiAwareSession session = sessionCaptor.getValue();
- /* (2) request a direct network specifier*/
- String networkSpecifier = session.createNetworkSpecifier(role, someMac, token.getBytes());
+ // (2) request an open (unencrypted) direct network specifier
+ String networkSpecifier = session.createNetworkSpecifierOpen(role, someMac);
- /* validate format*/
+ // validate format
JSONObject jsonObject = new JSONObject(networkSpecifier);
collector.checkThat("role", role,
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
@@ -1072,8 +1085,21 @@ public class WifiAwareManagerTest {
collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode(
jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(),
false)));
- collector.checkThat("token", tokenB64,
- equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_TOKEN)));
+
+ // (3) request an encrypted (PMK) direct network specifier
+ networkSpecifier = session.createNetworkSpecifierPmk(role, someMac, pmk);
+
+ // validate format
+ jsonObject = new JSONObject(networkSpecifier);
+ collector.checkThat("role", role,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
+ collector.checkThat("client_id", clientId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID)));
+ collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode(
+ jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(),
+ false)));
+ collector.checkThat("pmk", pmkB64,
+ equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK)));
verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
mockPublishSession, mockRttListener);