summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt37
-rw-r--r--api/system-current.txt38
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java22
-rw-r--r--core/java/android/accounts/AccountManager.java24
-rw-r--r--core/java/android/accounts/IAccountManager.aidl2
-rw-r--r--core/java/android/animation/AnimatorSet.java107
-rw-r--r--core/java/android/animation/ValueAnimator.java24
-rw-r--r--core/java/android/app/Activity.java6
-rw-r--r--core/java/android/app/ActivityManager.java35
-rw-r--r--core/java/android/app/ActivityManagerInternal.java9
-rw-r--r--core/java/android/app/ActivityView.java2
-rw-r--r--core/java/android/app/ApplicationPackageManager.java56
-rw-r--r--core/java/android/app/AutomaticZenRule.aidl (renamed from packages/SystemUI/res/values-sw600dp-port/dimens.xml)16
-rw-r--r--core/java/android/app/AutomaticZenRule.java190
-rw-r--r--core/java/android/app/INotificationManager.aidl6
-rw-r--r--core/java/android/app/NotificationManager.java100
-rw-r--r--core/java/android/app/StatusBarManager.java3
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java11
-rw-r--r--core/java/android/app/backup/BackupAgent.java14
-rw-r--r--core/java/android/content/Intent.java33
-rw-r--r--core/java/android/content/pm/PackageInstaller.java22
-rw-r--r--core/java/android/content/pm/PackageManager.java111
-rw-r--r--core/java/android/content/res/Resources.java54
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java12
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java12
-rw-r--r--core/java/android/os/BaseBundle.java12
-rw-r--r--core/java/android/os/Binder.java2
-rw-r--r--core/java/android/os/IPowerManager.aidl7
-rw-r--r--core/java/android/os/IUserManager.aidl2
-rw-r--r--core/java/android/os/ParcelableParcel.java10
-rw-r--r--core/java/android/os/Process.java4
-rw-r--r--core/java/android/os/UserHandle.java14
-rw-r--r--core/java/android/os/UserManager.java42
-rw-r--r--core/java/android/preference/SeekBarPreference.java19
-rw-r--r--core/java/android/provider/DocumentsContract.java32
-rw-r--r--core/java/android/provider/Settings.java8
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java8
-rw-r--r--core/java/android/text/Hyphenator.java34
-rw-r--r--core/java/android/text/StaticLayout.java3
-rw-r--r--core/java/android/util/MathUtils.java20
-rw-r--r--core/java/android/view/IWindowManager.aidl1
-rw-r--r--core/java/android/view/LayoutInflater.java51
-rw-r--r--core/java/android/view/ThreadedRenderer.java10
-rw-r--r--core/java/android/view/View.java43
-rw-r--r--core/java/android/view/ViewGroup.java5
-rw-r--r--core/java/android/view/ViewParent.java11
-rw-r--r--core/java/android/view/ViewRootImpl.java94
-rw-r--r--core/java/android/view/Window.java4
-rw-r--r--core/java/android/view/WindowCallbacks.java48
-rw-r--r--core/java/android/widget/AbsListView.java38
-rw-r--r--core/java/android/widget/AbsSeekBar.java5
-rw-r--r--core/java/android/widget/Editor.java13
-rw-r--r--core/java/android/widget/MenuPopupWindow.java12
-rw-r--r--core/java/android/widget/PopupWindow.java54
-rw-r--r--core/java/android/widget/RemoteViews.java41
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java16
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java23
-rw-r--r--core/java/com/android/internal/logging/MetricsLogger.java3
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java19
-rw-r--r--core/java/com/android/internal/os/InstallerConnection.java20
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java4
-rw-r--r--core/java/com/android/internal/policy/DecorContext.java55
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java308
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl4
-rw-r--r--core/java/com/android/internal/view/menu/CascadingMenuPopup.java74
-rw-r--r--core/java/com/android/internal/view/menu/ContextMenuBuilder.java26
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopup.java45
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java45
-rw-r--r--core/java/com/android/internal/view/menu/StandardMenuPopup.java54
-rw-r--r--core/java/com/android/internal/widget/FloatingToolbar.java6
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java2
-rw-r--r--core/java/com/android/internal/widget/NonClientDecorView.java301
-rw-r--r--core/jni/Android.mk4
-rw-r--r--core/jni/android/graphics/Paint.cpp539
-rw-r--r--core/jni/android_text_StaticLayout.cpp16
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp7
-rw-r--r--core/res/AndroidManifest.xml9
-rw-r--r--core/res/res/color/btn_colored_text_material.xml4
-rw-r--r--core/res/res/layout/popup_menu_header_item_layout.xml35
-rw-r--r--core/res/res/values-af/strings.xml20
-rw-r--r--core/res/res/values-cs/strings.xml2
-rw-r--r--core/res/res/values-da/strings.xml8
-rw-r--r--core/res/res/values-eu-rES/strings.xml18
-rw-r--r--core/res/res/values-fa/strings.xml30
-rw-r--r--core/res/res/values-gl-rES/strings.xml2
-rw-r--r--core/res/res/values-gu-rIN/strings.xml20
-rw-r--r--core/res/res/values-it-watch/strings.xml2
-rw-r--r--core/res/res/values-it/strings.xml8
-rw-r--r--core/res/res/values-ja-watch/strings.xml2
-rw-r--r--core/res/res/values-ja/strings.xml4
-rw-r--r--core/res/res/values-kk-rKZ/strings.xml2
-rw-r--r--core/res/res/values-ky-rKG/strings.xml2
-rw-r--r--core/res/res/values-mk-rMK/strings.xml16
-rw-r--r--core/res/res/values-my-rMM/strings.xml2
-rw-r--r--core/res/res/values-pt-rBR/strings.xml12
-rw-r--r--core/res/res/values-pt/strings.xml12
-rw-r--r--core/res/res/values-ro-watch/strings.xml14
-rw-r--r--core/res/res/values-ro/strings.xml92
-rw-r--r--core/res/res/values-ru/strings.xml2
-rw-r--r--core/res/res/values-si-rLK/strings.xml2
-rw-r--r--core/res/res/values-sl/strings.xml2
-rw-r--r--core/res/res/values-sq-rAL/strings.xml2
-rw-r--r--core/res/res/values-sr/strings.xml14
-rw-r--r--core/res/res/values-sv/strings.xml6
-rw-r--r--core/res/res/values-sw/strings.xml2
-rw-r--r--core/res/res/values-uz-rUZ-watch/strings.xml6
-rw-r--r--core/res/res/values-uz-rUZ/strings.xml16
-rw-r--r--core/res/res/values-watch/config.xml3
-rw-r--r--core/res/res/values/attrs.xml12
-rw-r--r--core/res/res/values/colors_holo.xml6
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--core/res/res/values/dimens_material.xml1
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/res/res/values/styles_material.xml10
-rw-r--r--core/res/res/values/styles_micro.xml1
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/res/res/values/themes_material.xml4
-rw-r--r--core/tests/coretests/src/android/widget/TextViewActivityTest.java80
-rw-r--r--core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java49
-rw-r--r--core/tests/coretests/src/android/widget/espresso/TextViewActions.java30
-rw-r--r--core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java49
-rw-r--r--docs/html/tools/support-library/index.jd2
-rw-r--r--graphics/java/android/graphics/Paint.java556
-rw-r--r--graphics/tests/graphicstests/src/android/graphics/PaintTest.java221
-rw-r--r--libs/hwui/DeferredDisplayList.cpp19
-rw-r--r--libs/hwui/DeferredDisplayList.h10
-rw-r--r--libs/hwui/OpenGLRenderer.cpp5
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp61
-rw-r--r--libs/hwui/renderthread/CanvasContext.h6
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp9
-rw-r--r--libs/hwui/renderthread/RenderProxy.h2
-rw-r--r--libs/hwui/utils/TinyHashMap.h70
-rw-r--r--media/java/android/media/Metadata.java10
-rw-r--r--media/java/android/media/SRTRenderer.java4
-rw-r--r--media/java/android/mtp/MtpDevice.java39
-rw-r--r--media/java/android/mtp/MtpEvent.java31
-rw-r--r--media/jni/android_mtp_MtpDevice.cpp78
-rw-r--r--native/graphics/jni/Android.mk2
-rw-r--r--packages/BackupRestoreConfirmation/res/values-ro/strings.xml4
-rw-r--r--packages/DocumentsUI/AndroidManifest.xml16
-rw-r--r--packages/DocumentsUI/res/layout/drawer_layout.xml113
-rw-r--r--packages/DocumentsUI/res/layout/fixed_layout.xml86
-rw-r--r--packages/DocumentsUI/res/layout/single_pane_layout.xml46
-rw-r--r--packages/DocumentsUI/res/menu/activity.xml24
-rw-r--r--packages/DocumentsUI/res/values-af/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-am/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-ar/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-az-rAZ/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-bg/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-bn-rBD/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-ca/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-cs/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-da/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-de/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-el/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-en-rAU/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-en-rGB/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-en-rIN/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-es-rUS/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-es/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-et-rEE/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-eu-rES/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-fa/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-fi/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-fr-rCA/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-fr/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-gl-rES/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-gu-rIN/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-hi/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-hr/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-hu/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-hy-rAM/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-in/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-is-rIS/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-it/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-iw/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-ja/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-ka-rGE/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-kk-rKZ/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-km-rKH/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-kn-rIN/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-ko/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-ky-rKG/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-lo-rLA/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-lt/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-lv/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-mk-rMK/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-ml-rIN/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-mn-rMN/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-mr-rIN/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-ms-rMY/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-my-rMM/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-nb/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-ne-rNP/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-nl/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-pa-rIN/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-pl/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-pt/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-ro/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-ru/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-si-rLK/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-sk/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-sl/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-sq-rAL/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-sr/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-sv/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-sw/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-ta-rIN/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-te-rIN/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-th/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-tl/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-tr/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-uk/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-ur-rPK/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values-uz-rUZ/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-vi/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-zh-rCN/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-zh-rHK/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-zh-rTW/strings.xml3
-rw-r--r--packages/DocumentsUI/res/values-zu/strings.xml2
-rw-r--r--packages/DocumentsUI/res/values/strings.xml4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java120
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/CopyService.java23
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java82
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java50
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java103
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java93
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/Menus.java50
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/Shared.java5
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/Snackbars.java37
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/State.java14
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java2
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java37
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java77
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java17
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java56
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java46
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java22
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java14
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java86
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java5
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java7
-rw-r--r--packages/PrintSpooler/res/values-uz-rUZ/strings.xml2
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java17
-rw-r--r--packages/SystemUI/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/proguard.flags8
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_lock.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_lock_open.xml25
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml24
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml24
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml24
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml24
-rw-r--r--packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml14
-rw-r--r--packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml14
-rw-r--r--packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml14
-rw-r--r--packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml14
-rw-r--r--packages/SystemUI/res/values-af/strings.xml2
-rw-r--r--packages/SystemUI/res/values-am/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml2
-rw-r--r--packages/SystemUI/res/values-az-rAZ/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bn-rBD/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml10
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-da/strings.xml16
-rw-r--r--packages/SystemUI/res/values-de/strings.xml2
-rw-r--r--packages/SystemUI/res/values-el/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en/donottranslate.xml23
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es/strings.xml2
-rw-r--r--packages/SystemUI/res/values-et-rEE/strings.xml2
-rw-r--r--packages/SystemUI/res/values-eu-rES/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml4
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gl-rES/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gu-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hy-rAM/strings.xml2
-rw-r--r--packages/SystemUI/res/values-in/strings.xml2
-rw-r--r--packages/SystemUI/res/values-is-rIS/strings.xml2
-rw-r--r--packages/SystemUI/res/values-it/strings.xml4
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ka-rGE/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kk-rKZ/strings.xml2
-rw-r--r--packages/SystemUI/res/values-km-rKH/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kn-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ky-rKG/strings.xml2
-rw-r--r--packages/SystemUI/res/values-land/config.xml4
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml22
-rw-r--r--packages/SystemUI/res/values-lo-rLA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mk-rMK/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ml-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mn-rMN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mr-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ms-rMY/strings.xml2
-rw-r--r--packages/SystemUI/res/values-my-rMM/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ne-rNP/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pa-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml2
-rw-r--r--packages/SystemUI/res/values-si-rLK/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sq-rAL/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml6
-rw-r--r--packages/SystemUI/res/values-sw600dp/config.xml5
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml10
-rw-r--r--packages/SystemUI/res/values-sw720dp/config.xml19
-rw-r--r--packages/SystemUI/res/values-sw720dp/dimens.xml33
-rw-r--r--packages/SystemUI/res/values-ta-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-te-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-th/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ur-rPK/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uz-rUZ/strings.xml6
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml2
-rw-r--r--packages/SystemUI/res/values/colors.xml3
-rw-r--r--packages/SystemUI/res/values/config.xml22
-rw-r--r--packages/SystemUI/res/values/dimens.xml39
-rw-r--r--packages/SystemUI/res/values/donottranslate.xml6
-rw-r--r--packages/SystemUI/res/values/strings.xml6
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java464
-rw-r--r--[-rwxr-xr-x]packages/SystemUI/src/com/android/systemui/BatteryMeterView.java490
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java)68
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java107
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java)31
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/Stroke.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTile.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java96
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java88
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java164
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java103
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java346
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java844
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java129
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerService.java4
-rw-r--r--rs/jni/android_renderscript_RenderScript.cpp8
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java21
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AutoclickController.java19
-rw-r--r--services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java43
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java26
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java117
-rw-r--r--services/core/java/com/android/server/GestureLauncherService.java11
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java35
-rw-r--r--services/core/java/com/android/server/ThermalObserver.java146
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java29
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java47
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java83
-rw-r--r--services/core/java/com/android/server/am/TaskPersister.java12
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java2
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java67
-rw-r--r--services/core/java/com/android/server/audio/RotationHelper.java209
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java66
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java2
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java75
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java198
-rw-r--r--services/core/java/com/android/server/pm/Installer.java44
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java35
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java18
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java25
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java82
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java38
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java2
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java35
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java5
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java29
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java98
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java22
-rw-r--r--services/core/java/com/android/server/wm/Task.java48
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java158
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java145
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java48
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java30
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java19
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java788
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java16
-rw-r--r--services/java/com/android/server/SystemServer.java5
-rw-r--r--services/net/java/android/net/dhcp/DhcpClient.java5
-rw-r--r--services/net/java/android/net/ip/IpReachabilityMonitor.java70
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java135
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java245
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java260
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java86
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java50
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java43
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java37
-rw-r--r--tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java2
-rw-r--r--tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java3
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java2
-rw-r--r--tests/WindowAnimationJank/Android.mk31
-rw-r--r--tests/WindowAnimationJank/AndroidManifest.xml40
-rw-r--r--tests/WindowAnimationJank/res/layout/flowlayout.xml21
-rw-r--r--tests/WindowAnimationJank/src/android/windowanimationjank/ElementLayoutActivity.java159
-rw-r--r--tests/WindowAnimationJank/src/android/windowanimationjank/FlowLayout.java111
-rw-r--r--tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java53
-rw-r--r--tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java118
-rw-r--r--tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java56
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java10
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeResources.java2
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java8
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java72
-rw-r--r--tools/layoutlib/bridge/src/android/view/BridgeInflater.java2
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java5
-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.java22
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutParserWrapper.java377
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java19
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/impl/LayoutParserWrapperTest.java183
503 files changed, 11807 insertions, 4670 deletions
diff --git a/api/current.txt b/api/current.txt
index 758851c79abe..77c64d7e570f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -414,6 +414,7 @@ package android {
field public static final int contentInsetRight = 16843862; // 0x1010456
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contextClickable = 16844007; // 0x10104e7
+ field public static final int contextPopupMenuStyle = 16844032; // 0x1010500
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1220,6 +1221,7 @@ package android {
field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
field public static final int textAppearanceMedium = 16842817; // 0x1010041
field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
+ field public static final int textAppearancePopupMenuHeader = 16844033; // 0x1010501
field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -4014,6 +4016,23 @@ package android.app {
field public java.lang.String serviceDetails;
}
+ public class AutomaticZenRule implements android.os.Parcelable {
+ ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
+ ctor public AutomaticZenRule(android.os.Parcel);
+ method public int describeContents();
+ method public android.net.Uri getConditionId();
+ method public int getInterruptionFilter();
+ method public java.lang.String getName();
+ method public android.content.ComponentName getOwner();
+ method public boolean isEnabled();
+ method public void setConditionId(android.net.Uri);
+ method public void setEnabled(boolean);
+ method public void setInterruptionFilter(int);
+ method public void setName(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR;
+ }
+
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
@@ -5059,15 +5078,20 @@ package android.app {
}
public class NotificationManager {
+ method public boolean addOrUpdateAutomaticZenRule(android.app.AutomaticZenRule);
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
+ method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
+ method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
method public void notify(java.lang.String, int, android.app.Notification);
+ method public boolean removeAutomaticZenRule(java.lang.String);
+ method public boolean renameAutomaticZenRule(java.lang.String, java.lang.String);
method public final void setInterruptionFilter(int);
method public void setNotificationPolicy(android.app.NotificationManager.Policy);
field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
@@ -9211,6 +9235,7 @@ package android.content.pm {
method public void setAppLabel(java.lang.CharSequence);
method public void setAppPackageName(java.lang.String);
method public void setInstallLocation(int);
+ method public void setOriginatingUid(int);
method public void setOriginatingUri(android.net.Uri);
method public void setReferrerUri(android.net.Uri);
method public void setSize(long);
@@ -18131,6 +18156,7 @@ package android.mtp {
method public boolean importFile(int, java.lang.String);
method public boolean importFile(int, android.os.ParcelFileDescriptor);
method public boolean open(android.hardware.usb.UsbDeviceConnection);
+ method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
}
@@ -18142,6 +18168,11 @@ package android.mtp {
method public final java.lang.String getVersion();
}
+ public class MtpEvent {
+ ctor public MtpEvent();
+ method public int getEventCode();
+ }
+
public final class MtpObjectInfo {
method public final int getAssociationDesc();
method public final int getAssociationType();
@@ -23559,7 +23590,7 @@ package android.os {
method public static final int myPid();
method public static final int myTid();
method public static final int myUid();
- method public static final android.os.UserHandle myUserHandle();
+ method public static android.os.UserHandle myUserHandle();
method public static final void sendSignal(int, int);
method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
@@ -36541,6 +36572,7 @@ package android.view {
method public void setY(float);
method public void setZ(float);
method public boolean showContextMenu();
+ method public boolean showContextMenu(float, float);
method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
method public void startAnimation(android.view.animation.Animation);
@@ -37007,6 +37039,7 @@ package android.view {
method public void setTransitionGroup(boolean);
method public boolean shouldDelayChildPressedState();
method public boolean showContextMenuForChild(android.view.View);
+ method public boolean showContextMenuForChild(android.view.View, float, float);
method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
method public void startLayoutAnimation();
@@ -37128,6 +37161,7 @@ package android.view {
method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public abstract void requestTransparentRegion(android.view.View);
method public abstract boolean showContextMenuForChild(android.view.View);
+ method public abstract boolean showContextMenuForChild(android.view.View, float, float);
method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
}
@@ -40906,6 +40940,7 @@ package android.widget {
method public int getInputMethodMode();
method public int getMaxAvailableHeight(android.view.View);
method public int getMaxAvailableHeight(android.view.View, int);
+ method public int getMaxAvailableHeight(android.view.View, int, boolean);
method public boolean getOverlapAnchor();
method public int getSoftInputMode();
method public int getWidth();
diff --git a/api/system-current.txt b/api/system-current.txt
index 256824010308..cff0055cba2f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -506,6 +506,7 @@ package android {
field public static final int contentInsetRight = 16843862; // 0x1010456
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contextClickable = 16844007; // 0x10104e7
+ field public static final int contextPopupMenuStyle = 16844032; // 0x1010500
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1316,6 +1317,7 @@ package android {
field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
field public static final int textAppearanceMedium = 16842817; // 0x1010041
field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
+ field public static final int textAppearancePopupMenuHeader = 16844033; // 0x1010501
field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -4125,6 +4127,23 @@ package android.app {
field public java.lang.String serviceDetails;
}
+ public class AutomaticZenRule implements android.os.Parcelable {
+ ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
+ ctor public AutomaticZenRule(android.os.Parcel);
+ method public int describeContents();
+ method public android.net.Uri getConditionId();
+ method public int getInterruptionFilter();
+ method public java.lang.String getName();
+ method public android.content.ComponentName getOwner();
+ method public boolean isEnabled();
+ method public void setConditionId(android.net.Uri);
+ method public void setEnabled(boolean);
+ method public void setInterruptionFilter(int);
+ method public void setName(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR;
+ }
+
public class BroadcastOptions {
method public static android.app.BroadcastOptions makeBasic();
method public void setTemporaryAppWhitelistDuration(long);
@@ -5176,15 +5195,20 @@ package android.app {
}
public class NotificationManager {
+ method public boolean addOrUpdateAutomaticZenRule(android.app.AutomaticZenRule);
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
+ method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
+ method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
method public void notify(java.lang.String, int, android.app.Notification);
+ method public boolean removeAutomaticZenRule(java.lang.String);
+ method public boolean renameAutomaticZenRule(java.lang.String, java.lang.String);
method public final void setInterruptionFilter(int);
method public void setNotificationPolicy(android.app.NotificationManager.Policy);
field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
@@ -9494,6 +9518,7 @@ package android.content.pm {
method public void setAppPackageName(java.lang.String);
method public void setGrantedRuntimePermissions(java.lang.String[]);
method public void setInstallLocation(int);
+ method public void setOriginatingUid(int);
method public void setOriginatingUri(android.net.Uri);
method public void setReferrerUri(android.net.Uri);
method public void setSize(long);
@@ -19643,6 +19668,7 @@ package android.mtp {
method public boolean importFile(int, java.lang.String);
method public boolean importFile(int, android.os.ParcelFileDescriptor);
method public boolean open(android.hardware.usb.UsbDeviceConnection);
+ method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
}
@@ -19654,6 +19680,11 @@ package android.mtp {
method public final java.lang.String getVersion();
}
+ public class MtpEvent {
+ ctor public MtpEvent();
+ method public int getEventCode();
+ }
+
public final class MtpObjectInfo {
method public final int getAssociationDesc();
method public final int getAssociationType();
@@ -25511,7 +25542,7 @@ package android.os {
method public static final int myPid();
method public static final int myTid();
method public static final int myUid();
- method public static final android.os.UserHandle myUserHandle();
+ method public static android.os.UserHandle myUserHandle();
method public static final void sendSignal(int, int);
method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
@@ -32862,6 +32893,7 @@ package android.telecom {
field public static final java.lang.String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED";
field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
+ field public static final java.lang.String ACTION_PHONE_ACCOUNT_UNREGISTERED = "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED";
field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
field public static final java.lang.String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
@@ -38835,6 +38867,7 @@ package android.view {
method public void setY(float);
method public void setZ(float);
method public boolean showContextMenu();
+ method public boolean showContextMenu(float, float);
method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
method public void startAnimation(android.view.animation.Animation);
@@ -39301,6 +39334,7 @@ package android.view {
method public void setTransitionGroup(boolean);
method public boolean shouldDelayChildPressedState();
method public boolean showContextMenuForChild(android.view.View);
+ method public boolean showContextMenuForChild(android.view.View, float, float);
method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
method public void startLayoutAnimation();
@@ -39422,6 +39456,7 @@ package android.view {
method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public abstract void requestTransparentRegion(android.view.View);
method public abstract boolean showContextMenuForChild(android.view.View);
+ method public abstract boolean showContextMenuForChild(android.view.View, float, float);
method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
}
@@ -43514,6 +43549,7 @@ package android.widget {
method public int getInputMethodMode();
method public int getMaxAvailableHeight(android.view.View);
method public int getMaxAvailableHeight(android.view.View, int);
+ method public int getMaxAvailableHeight(android.view.View, int, boolean);
method public boolean getOverlapAnchor();
method public int getSoftInputMode();
method public int getWidth();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 3f0a4445fdce..ebf508514b3c 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -22,11 +22,13 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+import android.accounts.IAccountManager;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.PackageInstallObserver;
import android.content.ComponentName;
+import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
@@ -92,6 +94,7 @@ public final class Pm {
IPackageManager mPm;
IPackageInstaller mInstaller;
IUserManager mUm;
+ IAccountManager mAm;
private WeakHashMap<String, Resources> mResourceCache
= new WeakHashMap<String, Resources>();
@@ -122,9 +125,10 @@ public final class Pm {
if (args.length < 1) {
return showUsage();
}
-
- mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
+ mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
+ mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+
if (mPm == null) {
System.err.println(PM_NOT_RUNNING_ERR);
return 1;
@@ -1381,6 +1385,8 @@ public final class Pm {
}
} else if ("--managed".equals(opt)) {
flags |= UserInfo.FLAG_MANAGED_PROFILE;
+ } else if ("--restricted".equals(opt)) {
+ flags |= UserInfo.FLAG_RESTRICTED;
} else {
System.err.println("Error: unknown option " + opt);
showUsage();
@@ -1394,12 +1400,18 @@ public final class Pm {
}
name = arg;
try {
- UserInfo info = null;
- if (userId < 0) {
+ UserInfo info;
+ if ((flags & UserInfo.FLAG_RESTRICTED) != 0) {
+ // In non-split user mode, userId can only be SYSTEM
+ int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
+ info = mUm.createRestrictedProfile(name, parentUserId);
+ mAm.addSharedAccountsFromParentUser(userId, parentUserId);
+ } else if (userId < 0) {
info = mUm.createUser(name, flags);
} else {
info = mUm.createProfileForUser(name, flags, userId);
}
+
if (info != null) {
System.out.println("Success: created user id " + info.id);
return 1;
@@ -2122,7 +2134,7 @@ public final class Pm {
System.err.println(" pm get-install-location");
System.err.println(" pm set-permission-enforced PERMISSION [true|false]");
System.err.println(" pm trim-caches DESIRED_FREE_SPACE [internal|UUID]");
- System.err.println(" pm create-user [--profileOf USER_ID] [--managed] USER_NAME");
+ System.err.println(" pm create-user [--profileOf USER_ID] [--managed] [--restricted] USER_NAME");
System.err.println(" pm remove-user USER_ID");
System.err.println(" pm get-max-users");
System.err.println("");
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index d751f96f65f6..0a7568a8c876 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -16,6 +16,7 @@
package android.accounts;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.Size;
import android.app.Activity;
@@ -423,6 +424,7 @@ public class AccountManager {
* @return An array of {@link Account}, one for each account. Empty
* (never null) if no accounts have been added.
*/
+ @NonNull
@RequiresPermission(GET_ACCOUNTS)
public Account[] getAccounts() {
try {
@@ -448,6 +450,7 @@ public class AccountManager {
* @return An array of {@link Account}, one for each account. Empty
* (never null) if no accounts have been added.
*/
+ @NonNull
@RequiresPermission(GET_ACCOUNTS)
public Account[] getAccountsAsUser(int userId) {
try {
@@ -466,6 +469,7 @@ public class AccountManager {
* @param uid the uid of the calling app.
* @return the accounts that are available to this package and user.
*/
+ @NonNull
public Account[] getAccountsForPackage(String packageName, int uid) {
try {
return mService.getAccountsForPackage(packageName, uid, mContext.getOpPackageName());
@@ -483,6 +487,7 @@ public class AccountManager {
* @return An array of {@link Account}, one per matching account. Empty
* (never null) if no accounts of the specified type have been added.
*/
+ @NonNull
public Account[] getAccountsByTypeForPackage(String type, String packageName) {
try {
return mService.getAccountsByTypeForPackage(type, packageName,
@@ -515,12 +520,14 @@ public class AccountManager {
* @return An array of {@link Account}, one per matching account. Empty
* (never null) if no accounts of the specified type have been added.
*/
+ @NonNull
@RequiresPermission(GET_ACCOUNTS)
public Account[] getAccountsByType(String type) {
return getAccountsByTypeAsUser(type, Process.myUserHandle());
}
/** @hide Same as {@link #getAccountsByType(String)} but for a specific user. */
+ @NonNull
public Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) {
try {
return mService.getAccountsAsUser(type, userHandle.getIdentifier(),
@@ -1537,23 +1544,22 @@ public class AccountManager {
}.start();
}
+
/**
- * Adds a shared account from the primary user to a secondary user. Adding the shared account
+ * Adds shared accounts from a parent user to a secondary user. Adding the shared account
* doesn't take effect immediately. When the target user starts up, any pending shared accounts
* are attempted to be copied to the target user from the primary via calls to the
* authenticator.
- * @param account the account to share
- * @param user the target user
- * @return
+ * @param parentUser parent user
+ * @param user target user
* @hide
*/
- public boolean addSharedAccount(final Account account, UserHandle user) {
+ public void addSharedAccountsFromParentUser(UserHandle parentUser, UserHandle user) {
try {
- boolean val = mService.addSharedAccountAsUser(account, user.getIdentifier());
- return val;
+ mService.addSharedAccountsFromParentUser(parentUser.getIdentifier(),
+ user.getIdentifier());
} catch (RemoteException re) {
- // won't ever happen
- throw new RuntimeException(re);
+ throw new IllegalStateException(re);
}
}
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 4378df408d10..0d95db1d8302 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -74,9 +74,9 @@ interface IAccountManager {
String authTokenType);
/* Shared accounts */
- boolean addSharedAccountAsUser(in Account account, int userId);
Account[] getSharedAccountsAsUser(int userId);
boolean removeSharedAccountAsUser(in Account account, int userId);
+ void addSharedAccountsFromParentUser(int parentUserId, int userId);
/* Account renaming. */
void renameAccount(in IAccountManagerResponse response, in Account accountToRename, String newName);
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 16f825da6f31..d444638c715a 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -603,7 +603,17 @@ public final class AnimatorSet extends Animator {
createDependencyGraph();
// Now that all dependencies are set up, start the animations that should be started.
- start(mRootNode);
+ boolean setIsEmpty = false;
+ if (mStartDelay > 0) {
+ start(mRootNode);
+ } else if (mNodes.size() > 1) {
+ // No delay, but there are other animators in the set
+ onChildAnimatorEnded(mDelayAnim);
+ } else {
+ // Set is empty, no delay, no other animation. Skip to end in this case
+ setIsEmpty = true;
+ }
+
if (mListeners != null) {
ArrayList<AnimatorListener> tmpListeners =
(ArrayList<AnimatorListener>) mListeners.clone();
@@ -612,18 +622,9 @@ public final class AnimatorSet extends Animator {
tmpListeners.get(i).onAnimationStart(this);
}
}
- if (mNodes.size() == 0 && mStartDelay == 0) {
- // Handle unusual case where empty AnimatorSet is started - should send out
- // end event immediately since the event will not be sent out at all otherwise
- mStarted = false;
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationEnd(this);
- }
- }
+ if (setIsEmpty) {
+ // In the case of empty AnimatorSet, we will trigger the onAnimationEnd() right away.
+ onChildAnimatorEnded(mDelayAnim);
}
}
@@ -751,44 +752,7 @@ public final class AnimatorSet extends Animator {
public void onAnimationEnd(Animator animation) {
animation.removeListener(this);
mAnimatorSet.mPlayingSet.remove(animation);
- Node animNode = mAnimatorSet.mNodeMap.get(animation);
- animNode.mEnded = true;
-
- if (!mAnimatorSet.mTerminated) {
- List<Node> children = animNode.mChildNodes;
- // Start children animations, if any.
- int childrenSize = children == null ? 0 : children.size();
- for (int i = 0; i < childrenSize; i++) {
- if (children.get(i).mLatestParent == animNode) {
- mAnimatorSet.start(children.get(i));
- }
- }
- // Listeners are already notified of the AnimatorSet ending in cancel() or
- // end(); the logic below only kicks in when animations end normally
- boolean allDone = true;
- // Traverse the tree and find if there's any unfinished node
- int size = mAnimatorSet.mNodes.size();
- for (int i = 0; i < size; i++) {
- if (!mAnimatorSet.mNodes.get(i).mEnded) {
- allDone = false;
- break;
- }
- }
- if (allDone) {
- // If this was the last child animation to end, then notify listeners that this
- // AnimatorSet has ended
- if (mAnimatorSet.mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mAnimatorSet.mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
- }
- }
- mAnimatorSet.mStarted = false;
- mAnimatorSet.mPaused = false;
- }
- }
+ mAnimatorSet.onChildAnimatorEnded(animation);
}
// Nothing to do
@@ -801,6 +765,47 @@ public final class AnimatorSet extends Animator {
}
+ private void onChildAnimatorEnded(Animator animation) {
+ Node animNode = mNodeMap.get(animation);
+ animNode.mEnded = true;
+
+ if (!mTerminated) {
+ List<Node> children = animNode.mChildNodes;
+ // Start children animations, if any.
+ int childrenSize = children == null ? 0 : children.size();
+ for (int i = 0; i < childrenSize; i++) {
+ if (children.get(i).mLatestParent == animNode) {
+ start(children.get(i));
+ }
+ }
+ // Listeners are already notified of the AnimatorSet ending in cancel() or
+ // end(); the logic below only kicks in when animations end normally
+ boolean allDone = true;
+ // Traverse the tree and find if there's any unfinished node
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ if (!mNodes.get(i).mEnded) {
+ allDone = false;
+ break;
+ }
+ }
+ if (allDone) {
+ // If this was the last child animation to end, then notify listeners that this
+ // AnimatorSet has ended
+ if (mListeners != null) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onAnimationEnd(this);
+ }
+ }
+ mStarted = false;
+ mPaused = false;
+ }
+ }
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index da9a8c8d8900..1995ef58e499 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -669,6 +669,10 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
* The frame delay may be ignored when the animation system uses an external timing
* source, such as the display refresh rate (vsync), to govern animations.
*
+ * Note that this method should be called from the same thread that {@link #start()} is
+ * called in order to check the frame delay for that animation. A runtime exception will be
+ * thrown if the calling thread does not have a Looper.
+ *
* @return the requested time between frames, in milliseconds
*/
public static long getFrameDelay() {
@@ -685,6 +689,10 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
* The frame delay may be ignored when the animation system uses an external timing
* source, such as the display refresh rate (vsync), to govern animations.
*
+ * Note that this method should be called from the same thread that {@link #start()} is
+ * called in order to have the new frame delay take effect on that animation. A runtime
+ * exception will be thrown if the calling thread does not have a Looper.
+ *
* @param frameDelay the requested time between frames, in milliseconds
*/
public static void setFrameDelay(long frameDelay) {
@@ -924,6 +932,13 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
updateScaledDuration(); // in case the scale factor has changed since creation time
AnimationHandler animationHandler = AnimationHandler.getInstance();
animationHandler.addAnimationFrameCallback(this, mStartDelay);
+
+ if (mStartDelay == 0) {
+ // If there's no start delay, init the animation and notify start listeners right away
+ // Otherwise, postpone this until the first frame after the start delay.
+ startAnimation();
+ setCurrentFraction(mSeekFraction == -1 ? 0 : mSeekFraction);
+ }
}
@Override
@@ -1067,6 +1082,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
mStartListenersCalled = false;
mPlayingBackwards = false;
mReversing = false;
+ mLastFrameTime = 0;
mCurrentIteration = 0;
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
@@ -1176,12 +1192,13 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
* @hide
*/
public final void doAnimationFrame(long frameTime) {
- mLastFrameTime = frameTime;
AnimationHandler handler = AnimationHandler.getInstance();
- if (!mRunning) {
+ if (mLastFrameTime == 0) {
// First frame
handler.addOneShotCommitCallback(this);
- startAnimation();
+ if (mStartDelay > 0) {
+ startAnimation();
+ }
if (mSeekFraction < 0) {
mStartTime = frameTime;
} else {
@@ -1191,6 +1208,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
}
mStartTimeCommitted = false; // allow start time to be compensated for jank
}
+ mLastFrameTime = frameTime;
if (mPaused) {
if (mPauseTime < 0) {
mPauseTime = frameTime;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4997dc751082..f60250cc6eb1 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3742,6 +3742,12 @@ public class Activity extends ContextThemeWrapper
}
@Override
+ public void setTheme(int resid) {
+ super.setTheme(resid);
+ mWindow.setTheme(resid);
+ }
+
+ @Override
protected void onApplyThemeResource(Resources.Theme theme, @StyleRes int resid,
boolean first) {
if (mParent == null) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4191dce79be8..61a9a84a5965 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -468,28 +468,51 @@ public class ActivityManager {
*/
public static final int DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT = 1;
-
/**
* Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates
- * that the resize is from the window manager (instead of the user).
+ * that the resize doesn't need to preserve the window, and can be skipped if bounds
+ * is unchanged. This mode is used by window manager in most cases.
* @hide
*/
public static final int RESIZE_MODE_SYSTEM = 0;
/**
* Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates
- * that the resize is initiated by the user (most likely via a drag action on the
- * window's edge or corner).
+ * that the resize should preserve the window if possible.
* @hide
*/
- public static final int RESIZE_MODE_USER = 1;
+ public static final int RESIZE_MODE_PRESERVE_WINDOW = (0x1 << 0);
/**
* Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates
* that the resize should be performed even if the bounds appears unchanged.
* @hide
*/
- public static final int RESIZE_MODE_FORCED = 2;
+ public static final int RESIZE_MODE_FORCED = (0x1 << 1);
+
+ /**
+ * Input parameter to {@link android.app.IActivityManager#resizeTask} used by window
+ * manager during a screen rotation.
+ * @hide
+ */
+ public static final int RESIZE_MODE_SYSTEM_SCREEN_ROTATION = RESIZE_MODE_PRESERVE_WINDOW;
+
+ /**
+ * Input parameter to {@link android.app.IActivityManager#resizeTask} used when the
+ * resize is due to a drag action.
+ * @hide
+ */
+ public static final int RESIZE_MODE_USER = RESIZE_MODE_PRESERVE_WINDOW;
+
+ /**
+ * Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates
+ * that the resize should preserve the window if possible, and should not be skipped
+ * even if the bounds is unchanged. Usually used to force a resizing when a drag action
+ * is ending.
+ * @hide
+ */
+ public static final int RESIZE_MODE_USER_FORCED =
+ RESIZE_MODE_PRESERVE_WINDOW | RESIZE_MODE_FORCED;
/** @hide */
public int getFrontActivityScreenCompatMode() {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 40eb799f26b9..373a23fa7422 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -55,4 +55,13 @@ public abstract class ActivityManagerInternal {
* @param userId ID of the user or {@link android.os.UserHandle#USER_ALL}
*/
public abstract ComponentName getHomeActivityForUser(int userId);
+
+ /**
+ * Called when a user has been deleted. This can happen during normal device usage
+ * or just at startup, when partially removed users are purged. Any state persisted by the
+ * ActivityManager should be purged now.
+ *
+ * @param userId The user being cleaned up.
+ */
+ public abstract void onUserRemoved(int userId);
}
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 9c0d93123d77..371c92393d17 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -239,6 +239,8 @@ public class ActivityView extends ViewGroup {
}
mTextureView.setSurfaceTextureListener(null);
+
+ mThread.quit();
}
private void attachToSurfaceWhenReady() {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 5544a7150625..f29dba263a5c 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -126,8 +126,14 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public PackageInfo getPackageInfo(String packageName, int flags)
throws NameNotFoundException {
+ return getPackageInfoAsUser(packageName, flags, mContext.getUserId());
+ }
+
+ @Override
+ public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+ throws NameNotFoundException {
try {
- PackageInfo pi = mPM.getPackageInfo(packageName, flags, mContext.getUserId());
+ PackageInfo pi = mPM.getPackageInfo(packageName, flags, userId);
if (pi != null) {
return pi;
}
@@ -1338,7 +1344,7 @@ public class ApplicationPackageManager extends PackageManager {
final VerificationParams verificationParams = new VerificationParams(null, null,
null, VerificationParams.NO_UID, null);
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
- installerPackageName, verificationParams, null);
+ installerPackageName, verificationParams, null, mContext.getUserId());
}
@Override
@@ -1348,7 +1354,7 @@ public class ApplicationPackageManager extends PackageManager {
final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
null, VerificationParams.NO_UID, manifestDigest);
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
- installerPackageName, verificationParams, encryptionParams);
+ installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
}
@Override
@@ -1356,15 +1362,23 @@ public class ApplicationPackageManager extends PackageManager {
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
- installerPackageName, verificationParams, encryptionParams);
+ installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
}
@Override
public void installPackage(Uri packageURI, PackageInstallObserver observer,
int flags, String installerPackageName) {
+ installPackageAsUser(packageURI, observer, flags, installerPackageName,
+ mContext.getUserId());
+ }
+
+ @Override
+ public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer, int flags,
+ String installerPackageName, int userId) {
final VerificationParams verificationParams = new VerificationParams(null, null,
null, VerificationParams.NO_UID, null);
- installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null);
+ installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null,
+ userId);
}
@Override
@@ -1375,7 +1389,7 @@ public class ApplicationPackageManager extends PackageManager {
final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
null, VerificationParams.NO_UID, manifestDigest);
installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
- encryptionParams);
+ encryptionParams, mContext.getUserId());
}
@Override
@@ -1383,12 +1397,13 @@ public class ApplicationPackageManager extends PackageManager {
PackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
- encryptionParams);
+ encryptionParams, mContext.getUserId());
}
private void installCommon(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
- VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+ VerificationParams verificationParams, ContainerEncryptionParams encryptionParams,
+ int userId) {
if (!"file".equals(packageURI.getScheme())) {
throw new UnsupportedOperationException("Only file:// URIs are supported");
}
@@ -1398,17 +1413,22 @@ public class ApplicationPackageManager extends PackageManager {
final String originPath = packageURI.getPath();
try {
- mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName,
- verificationParams, null);
+ mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
+ verificationParams, null, userId);
} catch (RemoteException ignored) {
}
}
@Override
- public int installExistingPackage(String packageName)
+ public int installExistingPackage(String packageName) throws NameNotFoundException {
+ return installExistingPackageAsUser(packageName, mContext.getUserId());
+ }
+
+ @Override
+ public int installExistingPackageAsUser(String packageName, int userId)
throws NameNotFoundException {
try {
- int res = mPM.installExistingPackageAsUser(packageName, UserHandle.myUserId());
+ int res = mPM.installExistingPackageAsUser(packageName, userId);
if (res == INSTALL_FAILED_INVALID_URI) {
throw new NameNotFoundException("Package " + packageName + " doesn't exist");
}
@@ -1706,8 +1726,14 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
+ deletePackageAsUser(packageName, observer, flags, mContext.getUserId());
+ }
+
+ @Override
+ public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags,
+ int userId) {
try {
- mPM.deletePackageAsUser(packageName, observer, UserHandle.myUserId(), flags);
+ mPM.deletePackageAsUser(packageName, observer, userId, flags);
} catch (RemoteException e) {
// Should never happen!
}
@@ -1812,7 +1838,7 @@ public class ApplicationPackageManager extends PackageManager {
public void replacePreferredActivity(IntentFilter filter,
int match, ComponentName[] set, ComponentName activity) {
try {
- mPM.replacePreferredActivity(filter, match, set, activity, UserHandle.myUserId());
+ mPM.replacePreferredActivity(filter, match, set, activity, mContext.getUserId());
} catch (RemoteException e) {
// Should never happen!
}
@@ -2143,7 +2169,7 @@ public class ApplicationPackageManager extends PackageManager {
}
private UserInfo getUserIfProfile(int userHandle) {
- List<UserInfo> userProfiles = getUserManager().getProfiles(UserHandle.myUserId());
+ List<UserInfo> userProfiles = getUserManager().getProfiles(mContext.getUserId());
for (UserInfo user : userProfiles) {
if (user.id == userHandle) {
return user;
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/core/java/android/app/AutomaticZenRule.aidl
index 7dc91d164e2e..feb21d657c6a 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/core/java/android/app/AutomaticZenRule.aidl
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2012, The Android Open Source Project
+/**
+ * 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.
@@ -13,9 +12,8 @@
* 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>
- <!-- Recent Applications parameters -->
- <dimen name="status_bar_recents_app_label_width">140dip</dimen>
-</resources>
+ */
+
+package android.app;
+
+parcelable AutomaticZenRule; \ No newline at end of file
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
new file mode 100644
index 000000000000..fea5624411ad
--- /dev/null
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -0,0 +1,190 @@
+/**
+ * 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.app;
+
+import android.content.ComponentName;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Rule instance information for zen mode.
+ */
+public class AutomaticZenRule implements Parcelable {
+
+ private boolean enabled = false;
+ private String name;
+ private int interruptionFilter;
+ private Uri conditionId;
+ private ComponentName owner;
+
+ /**
+ * Creates an automatic zen rule.
+ *
+ * @param name The name of the rule.
+ * @param owner The Condition Provider service that owns this rule.
+ * @param conditionId A representation of the state that should cause the Condition Provider
+ * service to apply the interruption filter.
+ * @param interruptionFilter The interruption filter defines which notifications are allowed to
+ * interrupt the user (e.g. via sound &amp; vibration) while this rule
+ * is active.
+ * @param enabled Whether the rule is enabled.
+ */
+ public AutomaticZenRule(String name, ComponentName owner, Uri conditionId,
+ int interruptionFilter, boolean enabled) {
+ this.name = name;
+ this.owner = owner;
+ this.conditionId = conditionId;
+ this.interruptionFilter = interruptionFilter;
+ this.enabled = enabled;
+ }
+
+ public AutomaticZenRule(Parcel source) {
+ enabled = source.readInt() == 1;
+ if (source.readInt() == 1) {
+ name = source.readString();
+ }
+ interruptionFilter = source.readInt();
+ conditionId = source.readParcelable(null);
+ owner = source.readParcelable(null);
+ }
+
+ /**
+ * Returns the {@link ComponentName} of the condition provider service that owns this rule.
+ */
+ public ComponentName getOwner() {
+ return owner;
+ }
+
+ /**
+ * Returns the representation of the state that causes this rule to become active.
+ */
+ public Uri getConditionId() {
+ return conditionId;
+ }
+
+ /**
+ * Returns the interruption filter that is applied when this rule is active.
+ */
+ public int getInterruptionFilter() {
+ return interruptionFilter;
+ }
+
+ /**
+ * Returns the name of this rule.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns whether this rule is enabled.
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Sets the representation of the state that causes this rule to become active.
+ */
+ public void setConditionId(Uri conditionId) {
+ this.conditionId = conditionId;
+ }
+
+ /**
+ * Sets the interruption filter that is applied when this rule is active.
+ * @param interruptionFilter One of the INTERRUPTION_FILTER_ constants in NotificationManager.
+ */
+ public void setInterruptionFilter(int interruptionFilter) {
+ this.interruptionFilter = interruptionFilter;
+ }
+
+ /**
+ * Sets the name of this rule.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Enables this rule.
+ */
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(enabled ? 1 : 0);
+ if (name != null) {
+ dest.writeInt(1);
+ dest.writeString(name);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(interruptionFilter);
+ dest.writeParcelable(conditionId, 0);
+ dest.writeParcelable(owner, 0);
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(AutomaticZenRule.class.getSimpleName()).append('[')
+ .append("enabled=").append(enabled)
+ .append(",name=").append(name)
+ .append(",interruptionFilter=").append(interruptionFilter)
+ .append(",conditionId=").append(conditionId)
+ .append(",owner=").append(owner)
+ .append(']').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof AutomaticZenRule)) return false;
+ if (o == this) return true;
+ final AutomaticZenRule other = (AutomaticZenRule) o;
+ return other.enabled == enabled
+ && Objects.equals(other.name, name)
+ && other.interruptionFilter == interruptionFilter
+ && Objects.equals(other.conditionId, conditionId)
+ && Objects.equals(other.owner, owner);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(enabled, name, interruptionFilter, conditionId, owner);
+ }
+
+ public static final Parcelable.Creator<AutomaticZenRule> CREATOR
+ = new Parcelable.Creator<AutomaticZenRule>() {
+ @Override
+ public AutomaticZenRule createFromParcel(Parcel source) {
+ return new AutomaticZenRule(source);
+ }
+ @Override
+ public AutomaticZenRule[] newArray(int size) {
+ return new AutomaticZenRule[size];
+ }
+ };
+} \ No newline at end of file
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index f78fb47e5f5e..920fbe9cfc1c 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -30,6 +30,7 @@ import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
import android.service.notification.StatusBarNotification;
+import android.app.AutomaticZenRule;
import android.service.notification.ZenModeConfig;
/** {@hide} */
@@ -92,6 +93,11 @@ interface INotificationManager
String[] getPackagesRequestingNotificationPolicyAccess();
boolean isNotificationPolicyAccessGrantedForPackage(String pkg);
void setNotificationPolicyAccessGranted(String pkg, boolean granted);
+ AutomaticZenRule getAutomaticZenRule(String name);
+ List<AutomaticZenRule> getAutomaticZenRules();
+ boolean addOrUpdateAutomaticZenRule(in AutomaticZenRule automaticZenRule);
+ boolean renameAutomaticZenRule(String oldName, String newName);
+ boolean removeAutomaticZenRule(String name);
byte[] getBackupPayload(int user);
void applyRestore(in byte[] payload, int user);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 605c00613087..cbf198bb9415 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -420,6 +420,106 @@ public class NotificationManager
}
/**
+ * Returns AutomaticZenRules owned by the caller.
+ *
+ * <p>
+ * Only available if policy access is granted to this package.
+ * See {@link #isNotificationPolicyAccessGranted}.
+ */
+ public List<AutomaticZenRule> getAutomaticZenRules() {
+ INotificationManager service = getService();
+ try {
+ return service.getAutomaticZenRules();
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Returns the AutomaticZenRule with the given name, if it exists and the caller has access.
+ *
+ * <p>
+ * Only available if policy access is granted to this package.
+ * See {@link #isNotificationPolicyAccessGranted}.
+ *
+ * <p>
+ * Returns null if there are no zen rules that match the given name, or if the calling package
+ * doesn't own the matching rule. See {@link AutomaticZenRule#getOwner}.
+ */
+ public AutomaticZenRule getAutomaticZenRule(String name) {
+ INotificationManager service = getService();
+ try {
+ return service.getAutomaticZenRule(name);
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Creates or updates the given zen rule.
+ *
+ * <p>
+ * Only available if policy access is granted to this package.
+ * See {@link #isNotificationPolicyAccessGranted}.
+ *
+ * <p>
+ * Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}.
+ * @param automaticZenRule the rule to create or update.
+ * @return Whether the rule was successfully created or updated.
+ */
+ public boolean addOrUpdateAutomaticZenRule(AutomaticZenRule automaticZenRule) {
+ INotificationManager service = getService();
+ try {
+ return service.addOrUpdateAutomaticZenRule(automaticZenRule);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ /**
+ * Renames a zen rule.
+ *
+ * <p>
+ * Only available if policy access is granted to this package.
+ * See {@link #isNotificationPolicyAccessGranted}.
+ *
+ * <p>
+ * Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}.
+ * @param oldName The name of the rule to update.
+ * @param newName The new name for the rule.
+ * @return Whether the rule was successfully updated.
+ */
+ public boolean renameAutomaticZenRule(String oldName, String newName) {
+ INotificationManager service = getService();
+ try {
+ return service.renameAutomaticZenRule(oldName, newName);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ /**
+ * Deletes the automatic zen rule with the given name.
+ *
+ * <p>
+ * Only available if policy access is granted to this package.
+ * See {@link #isNotificationPolicyAccessGranted}.
+ *
+ * <p>
+ * Callers can only delete rules that they own. See {@link AutomaticZenRule#getOwner}.
+ * @param name the name of the rule to delete.
+ * @return Whether the rule was successfully deleted.
+ */
+ public boolean removeAutomaticZenRule(String name) {
+ INotificationManager service = getService();
+ try {
+ return service.removeAutomaticZenRule(name);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ /**
* Checks the ability to read/modify notification policy for the calling package.
*
* <p>
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 31d1ab7b92ac..5e8ad68957b2 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -90,6 +90,9 @@ public class StatusBarManager {
public static final int WINDOW_STATE_HIDING = 1;
public static final int WINDOW_STATE_HIDDEN = 2;
+ public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0;
+ public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1;
+
private Context mContext;
private IStatusBarService mService;
private IBinder mToken = new Binder();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e6484e965ee0..a118f167ae5c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2438,6 +2438,17 @@ public class DevicePolicyManager {
}
/**
+ * Determine whether or not creating a guest user has been disabled for the device
+ *
+ * @hide
+ */
+ public boolean getGuestUserDisabled(@Nullable ComponentName admin) {
+ // Currently guest users can always be created if multi-user is enabled
+ // TODO introduce a policy for guest user creation
+ return false;
+ }
+
+ /**
* Called by a device/profile owner to set whether the screen capture is disabled. Disabling
* screen capture also prevents the content from being shown on display devices that do not have
* a secure video output. See {@link android.view.Display#FLAG_SECURE} for more details about
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 689283c8e550..aa4a631ea76a 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -533,6 +533,14 @@ public abstract class BackupAgent extends ContextWrapper {
File file = scanQueue.remove(0);
String filePath;
try {
+ // Ignore symlinks outright
+ StructStat stat = Os.lstat(file.getPath());
+ if (OsConstants.S_ISLNK(stat.st_mode)) {
+ if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
+ continue;
+ }
+
+ // For all other verification, look at the canonicalized path
filePath = file.getCanonicalPath();
// prune this subtree?
@@ -544,11 +552,7 @@ public abstract class BackupAgent extends ContextWrapper {
}
// If it's a directory, enqueue its contents for scanning.
- StructStat stat = Os.lstat(filePath);
- if (OsConstants.S_ISLNK(stat.st_mode)) {
- if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
- continue;
- } else if (OsConstants.S_ISDIR(stat.st_mode)) {
+ if (OsConstants.S_ISDIR(stat.st_mode)) {
File[] contents = file.listFiles();
if (contents != null) {
for (File entry : contents) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index b08db20c2eea..670ca803a367 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3033,6 +3033,39 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_PROCESS_TEXT_READONLY =
"android.intent.extra.PROCESS_TEXT_READONLY";
+ /**
+ * Broadcast action: reports when a new thermal event has been reached. When the device
+ * is reaching its maximum temperatue, the thermal level reported
+ * {@hide}
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_THERMAL_EVENT = "android.intent.action.THERMAL_EVENT";
+
+ /** {@hide} */
+ public static final String EXTRA_THERMAL_STATE = "android.intent.extra.THERMAL_STATE";
+
+ /**
+ * Thermal state when the device is normal. This state is sent in the
+ * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+ * {@hide}
+ */
+ public static final int EXTRA_THERMAL_STATE_NORMAL = 0;
+
+ /**
+ * Thermal state where the device is approaching its maximum threshold. This state is sent in
+ * the {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+ * {@hide}
+ */
+ public static final int EXTRA_THERMAL_STATE_WARNING = 1;
+
+ /**
+ * Thermal state where the device has reached its maximum threshold. This state is sent in the
+ * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+ * {@hide}
+ */
+ public static final int EXTRA_THERMAL_STATE_EXCEEDED = 2;
+
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 9341be16c28f..32830053fae2 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -868,6 +868,9 @@ public class PackageInstaller {
public static final int MODE_INHERIT_EXISTING = 2;
/** {@hide} */
+ public static final int UID_UNKNOWN = -1;
+
+ /** {@hide} */
public int mode = MODE_INVALID;
/** {@hide} */
public int installFlags;
@@ -886,6 +889,8 @@ public class PackageInstaller {
/** {@hide} */
public Uri originatingUri;
/** {@hide} */
+ public int originatingUid = UID_UNKNOWN;
+ /** {@hide} */
public Uri referrerUri;
/** {@hide} */
public String abiOverride;
@@ -915,6 +920,7 @@ public class PackageInstaller {
appIcon = source.readParcelable(null);
appLabel = source.readString();
originatingUri = source.readParcelable(null);
+ originatingUid = source.readInt();
referrerUri = source.readParcelable(null);
abiOverride = source.readString();
volumeUuid = source.readString();
@@ -983,6 +989,15 @@ public class PackageInstaller {
}
/**
+ * Sets the UID that initiated package installation. Used for verification purposes.
+ *
+ * @see PackageManager#EXTRA_VERIFICATION_INSTALLER_UID
+ */
+ public void setOriginatingUid(int originatingUid) {
+ this.originatingUid = originatingUid;
+ }
+
+ /**
* Optionally set the URI that referred you to install this package. Used
* for verification purposes.
*
@@ -1022,6 +1037,11 @@ public class PackageInstaller {
}
/** {@hide} */
+ public void setInstallFlagsForcePermissionPrompt() {
+ installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT;
+ }
+
+ /** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
pw.printHexPair("installFlags", installFlags);
@@ -1031,6 +1051,7 @@ public class PackageInstaller {
pw.printPair("appIcon", (appIcon != null));
pw.printPair("appLabel", appLabel);
pw.printPair("originatingUri", originatingUri);
+ pw.printPair("originatingUid", originatingUid);
pw.printPair("referrerUri", referrerUri);
pw.printPair("abiOverride", abiOverride);
pw.printPair("volumeUuid", volumeUuid);
@@ -1053,6 +1074,7 @@ public class PackageInstaller {
dest.writeParcelable(appIcon, flags);
dest.writeString(appLabel);
dest.writeParcelable(originatingUri, flags);
+ dest.writeInt(originatingUid);
dest.writeParcelable(referrerUri, flags);
dest.writeString(abiOverride);
dest.writeString(volumeUuid);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c8e9402e6442..82cbbbeb39fc 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -422,6 +422,15 @@ public abstract class PackageManager {
public static final int INSTALL_FORCE_VOLUME_UUID = 0x00000200;
/**
+ * Flag parameter for {@link #installPackage} to indicate that we always want to force
+ * the prompt for permission approval. This overrides any special behaviour for internal
+ * components.
+ *
+ * @hide
+ */
+ public static final int INSTALL_FORCE_PERMISSION_PROMPT = 0x00000400;
+
+ /**
* Flag parameter for
* {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
* that you don't want to kill the app containing the component. Be careful when you set this
@@ -2010,7 +2019,7 @@ public abstract class PackageManager {
* {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
* {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to
* modify the data returned.
- * @return Returns a PackageInfo object containing information about the
+ * @return A PackageInfo object containing information about the
* package. If flag GET_UNINSTALLED_PACKAGES is set and if the
* package is not found in the list of installed applications, the
* package information is retrieved from the list of uninstalled
@@ -2032,6 +2041,46 @@ public abstract class PackageManager {
throws NameNotFoundException;
/**
+ * @hide
+ * Retrieve overall information about an application package that is
+ * installed on the system.
+ * <p>
+ * Throws {@link NameNotFoundException} if a package with the given name can
+ * not be found on the system.
+ *
+ * @param packageName The full name (i.e. com.google.apps.contacts) of the
+ * desired package.
+ * @param flags Additional option flags. Use any combination of
+ * {@link #GET_ACTIVITIES}, {@link #GET_GIDS},
+ * {@link #GET_CONFIGURATIONS}, {@link #GET_INSTRUMENTATION},
+ * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+ * {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+ * {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to
+ * modify the data returned.
+ * @param userId The user id.
+ * @return A PackageInfo object containing information about the
+ * package. If flag GET_UNINSTALLED_PACKAGES is set and if the
+ * package is not found in the list of installed applications, the
+ * package information is retrieved from the list of uninstalled
+ * applications (which includes installed applications as well as
+ * applications with data directory i.e. applications which had been
+ * deleted with {@code DONT_DELETE_DATA} flag set).
+ * @see #GET_ACTIVITIES
+ * @see #GET_GIDS
+ * @see #GET_CONFIGURATIONS
+ * @see #GET_INSTRUMENTATION
+ * @see #GET_PERMISSIONS
+ * @see #GET_PROVIDERS
+ * @see #GET_RECEIVERS
+ * @see #GET_SERVICES
+ * @see #GET_SIGNATURES
+ * @see #GET_UNINSTALLED_PACKAGES
+ */
+ @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+ public abstract PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+ throws NameNotFoundException;
+
+ /**
* Map from the current package names in use on the device to whatever
* the current canonical name of that package is.
* @param names Array of current names to be mapped.
@@ -3689,6 +3738,31 @@ public abstract class PackageManager {
Uri packageURI, PackageInstallObserver observer,
int flags, String installerPackageName);
+
+ /**
+ * @hide
+ * Install a package. Since this may take a little while, the result will be
+ * posted back to the given observer. An installation will fail if the package named
+ * in the package file's manifest is already installed, or if there's no space
+ * available on the device.
+ * @param packageURI The location of the package file to install. This can be a 'file:' or a
+ * 'content:' URI.
+ * @param observer An observer callback to get notified when the package installation is
+ * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
+ * called when that happens. This parameter must not be null.
+ * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
+ * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
+ * @param installerPackageName Optional package name of the application that is performing the
+ * installation. This identifies which market the package came from.
+ * @param userId The user id.
+ */
+ @RequiresPermission(anyOf = {
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+ public abstract void installPackageAsUser(
+ Uri packageURI, PackageInstallObserver observer, int flags,
+ String installerPackageName, int userId);
+
/**
* Similar to
* {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
@@ -3752,7 +3826,17 @@ public abstract class PackageManager {
* @hide
*/
// @SystemApi
- public abstract int installExistingPackage(String packageName)
+ public abstract int installExistingPackage(String packageName) throws NameNotFoundException;
+
+ /**
+ * If there is already an application with the given package name installed
+ * on the system for other users, also install it for the specified user.
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+ public abstract int installExistingPackageAsUser(String packageName, int userId)
throws NameNotFoundException;
/**
@@ -3958,7 +4042,7 @@ public abstract class PackageManager {
* @param observer An observer callback to get notified when the package deletion is
* complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
* called when that happens. observer may be null to indicate that no callback is desired.
- * @param flags - possible values: {@link #DELETE_KEEP_DATA},
+ * @param flags Possible values: {@link #DELETE_KEEP_DATA},
* {@link #DELETE_ALL_USERS}.
*
* @hide
@@ -3968,6 +4052,27 @@ public abstract class PackageManager {
String packageName, IPackageDeleteObserver observer, int flags);
/**
+ * Attempts to delete a package. Since this may take a little while, the result will
+ * be posted back to the given observer. A deletion will fail if the named package cannot be
+ * found, or if the named package is a "system package".
+ * (TODO: include pointer to documentation on "system packages")
+ *
+ * @param packageName The name of the package to delete
+ * @param observer An observer callback to get notified when the package deletion is
+ * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
+ * called when that happens. observer may be null to indicate that no callback is desired.
+ * @param flags Possible values: {@link #DELETE_KEEP_DATA}, {@link #DELETE_ALL_USERS}.
+ * @param userId The user Id
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+ public abstract void deletePackageAsUser(
+ String packageName, IPackageDeleteObserver observer, int flags, int userId);
+
+ /**
* Retrieve the package name of the application that installed a package. This identifies
* which market the package came from.
*
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index e29bd2cc53e0..0606e35a081e 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,24 +16,14 @@
package android.content.res;
-import android.annotation.AttrRes;
-import android.annotation.ColorInt;
-import android.annotation.StyleRes;
-import android.annotation.StyleableRes;
-import android.graphics.drawable.DrawableInflater;
-import android.icu.text.PluralRules;
-import com.android.internal.util.GrowingArrayUtils;
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.animation.Animator;
import android.animation.StateListAnimator;
import android.annotation.AnimRes;
import android.annotation.AnyRes;
import android.annotation.ArrayRes;
+import android.annotation.AttrRes;
import android.annotation.BoolRes;
+import android.annotation.ColorInt;
import android.annotation.ColorRes;
import android.annotation.DimenRes;
import android.annotation.DrawableRes;
@@ -45,18 +35,23 @@ import android.annotation.Nullable;
import android.annotation.PluralsRes;
import android.annotation.RawRes;
import android.annotation.StringRes;
+import android.annotation.StyleRes;
+import android.annotation.StyleableRes;
import android.annotation.XmlRes;
import android.content.pm.ActivityInfo;
import android.graphics.Movie;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
+import android.graphics.drawable.DrawableInflater;
+import android.icu.text.PluralRules;
import android.os.Build;
import android.os.Bundle;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.LocaleList;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.Pools.SynchronizedPool;
@@ -65,6 +60,12 @@ import android.util.TypedValue;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
+import com.android.internal.util.GrowingArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
@@ -372,7 +373,7 @@ public class Resources {
private PluralRules getPluralRule() {
synchronized (sSync) {
if (mPluralRule == null) {
- mPluralRule = PluralRules.forLocale(mConfiguration.locale);
+ mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
}
return mPluralRule;
}
@@ -435,7 +436,7 @@ public class Resources {
@NonNull
public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
final String raw = getString(id);
- return String.format(mConfiguration.locale, raw, formatArgs);
+ return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
}
/**
@@ -466,7 +467,7 @@ public class Resources {
public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
throws NotFoundException {
String raw = getQuantityText(id, quantity).toString();
- return String.format(mConfiguration.locale, raw, formatArgs);
+ return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
}
/**
@@ -1971,9 +1972,10 @@ public class Resources {
mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
final int configChanges = calcConfigChanges(config);
- if (mConfiguration.locale == null) {
- mConfiguration.locale = Locale.getDefault();
- mConfiguration.setLayoutDirection(mConfiguration.locale);
+ LocaleList locales = mConfiguration.getLocales();
+ if (locales.isEmpty()) {
+ locales = LocaleList.getDefault();
+ mConfiguration.setLocales(locales);
}
if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
mMetrics.densityDpi = mConfiguration.densityDpi;
@@ -1981,11 +1983,6 @@ public class Resources {
}
mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
- String locale = null;
- if (mConfiguration.locale != null) {
- locale = adjustLanguageTag(mConfiguration.locale.toLanguageTag());
- }
-
final int width, height;
if (mMetrics.widthPixels >= mMetrics.heightPixels) {
width = mMetrics.widthPixels;
@@ -2005,8 +2002,10 @@ public class Resources {
keyboardHidden = mConfiguration.keyboardHidden;
}
+ // TODO: Pass the whole locale list to setConfiguration()
mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
- locale, mConfiguration.orientation,
+ adjustLanguageTag(locales.getPrimary().toLanguageTag()),
+ mConfiguration.orientation,
mConfiguration.touchscreen,
mConfiguration.densityDpi, mConfiguration.keyboard,
keyboardHidden, mConfiguration.navigation, width, height,
@@ -2030,7 +2029,7 @@ public class Resources {
}
synchronized (sSync) {
if (mPluralRule != null) {
- mPluralRule = PluralRules.forLocale(config.locale);
+ mPluralRule = PluralRules.forLocale(config.getLocales().getPrimary());
}
}
}
@@ -2049,9 +2048,8 @@ public class Resources {
mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
- if (mTmpConfig.locale == null) {
- mTmpConfig.locale = Locale.getDefault();
- mTmpConfig.setLayoutDirection(mTmpConfig.locale);
+ if (mTmpConfig.getLocales().isEmpty()) {
+ mTmpConfig.setLocales(LocaleList.getDefault());
}
configChanges = mConfiguration.updateFrom(mTmpConfig);
configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index e965d654fcc7..3f566eb92756 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1545,7 +1545,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
/**
* <p>Whether video stabilization is
* active.</p>
- * <p>Video stabilization automatically translates and scales images from
+ * <p>Video stabilization automatically warps images from
* the camera in order to stabilize motion between consecutive frames.</p>
* <p>If enabled, video stabilization can modify the
* {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p>
@@ -1555,6 +1555,15 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* the video stabilization modes in the first several capture results may
* still be "OFF", and it will become "ON" when the initialization is
* done.</p>
+ * <p>In addition, not all recording sizes or frame rates may be supported for
+ * stabilization by a device that reports stabilization support. It is guaranteed
+ * that an output targeting a MediaRecorder or MediaCodec will be stabilized if
+ * the recording resolution is less than or equal to 1920 x 1080 (width less than
+ * or equal to 1920, height less than or equal to 1080), and the recording
+ * frame rate is less than or equal to 30fps. At other sizes, the CaptureResult
+ * {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode} field will return
+ * OFF if the recording output is not stabilized, or if there are no output
+ * Surface types that can be stabilized.</p>
* <p>If a camera device supports both this mode and OIS
* ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may
* produce undesirable interaction, so it is recommended not to enable
@@ -1566,6 +1575,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* </ul></p>
* <p>This key is available on all devices.</p>
*
+ * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
* @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 46eddb3f6651..b3acf2b09784 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2056,7 +2056,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>Whether video stabilization is
* active.</p>
- * <p>Video stabilization automatically translates and scales images from
+ * <p>Video stabilization automatically warps images from
* the camera in order to stabilize motion between consecutive frames.</p>
* <p>If enabled, video stabilization can modify the
* {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p>
@@ -2066,6 +2066,15 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* the video stabilization modes in the first several capture results may
* still be "OFF", and it will become "ON" when the initialization is
* done.</p>
+ * <p>In addition, not all recording sizes or frame rates may be supported for
+ * stabilization by a device that reports stabilization support. It is guaranteed
+ * that an output targeting a MediaRecorder or MediaCodec will be stabilized if
+ * the recording resolution is less than or equal to 1920 x 1080 (width less than
+ * or equal to 1920, height less than or equal to 1080), and the recording
+ * frame rate is less than or equal to 30fps. At other sizes, the CaptureResult
+ * {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode} field will return
+ * OFF if the recording output is not stabilized, or if there are no output
+ * Surface types that can be stabilized.</p>
* <p>If a camera device supports both this mode and OIS
* ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may
* produce undesirable interaction, so it is recommended not to enable
@@ -2077,6 +2086,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* </ul></p>
* <p>This key is available on all devices.</p>
*
+ * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
* @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index c3733085caf6..cd483b104489 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -19,6 +19,7 @@ package android.os;
import android.annotation.Nullable;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.MathUtils;
import java.io.Serializable;
import java.util.ArrayList;
@@ -1345,18 +1346,19 @@ public class BaseBundle {
*/
void readFromParcelInner(Parcel parcel) {
int length = parcel.readInt();
- if (length < 0) {
- throw new RuntimeException("Bad length in parcel: " + length);
- }
readFromParcelInner(parcel, length);
}
private void readFromParcelInner(Parcel parcel, int length) {
- if (length == 0) {
+ if (length < 0) {
+ throw new RuntimeException("Bad length in parcel: " + length);
+
+ } else if (length == 0) {
// Empty Bundle or end of data.
mParcelledData = EMPTY_PARCEL;
return;
}
+
int magic = parcel.readInt();
if (magic != BUNDLE_MAGIC) {
//noinspection ThrowableInstanceNeverThrown
@@ -1366,7 +1368,7 @@ public class BaseBundle {
// Advance within this Parcel
int offset = parcel.dataPosition();
- parcel.setDataPosition(offset + length);
+ parcel.setDataPosition(MathUtils.addOrThrow(offset, length));
Parcel p = Parcel.obtain();
p.setDataPosition(0);
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index cfa6164b0454..c4501bade098 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -157,7 +157,7 @@ public class Binder implements IBinder {
* incoming transaction, then its own UserHandle is returned.
*/
public static final UserHandle getCallingUserHandle() {
- return new UserHandle(UserHandle.getUserId(getCallingUid()));
+ return UserHandle.of(UserHandle.getUserId(getCallingUid()));
}
/**
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index c4f62baab4a1..9fdbec39b2bd 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -23,8 +23,11 @@ import android.os.WorkSource;
interface IPowerManager
{
- // WARNING: The first five methods must remain the first five methods because their
- // transaction numbers must not change unless IPowerManager.cpp is also updated.
+ // WARNING: When methods are inserted or deleted, the transaction IDs in
+ // frameworks/native/include/powermanager/IPowerManager.h must be updated to match the order in this file.
+ //
+ // When a method's argument list is changed, BnPowerManager's corresponding serialization code (if any) in
+ // frameworks/native/services/powermanager/IPowerManager.cpp must be updated.
void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws,
String historyTag);
void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName,
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index aeb5d4517e6c..4c19ddda19bd 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -35,6 +35,7 @@ interface IUserManager {
UserInfo createUser(in String name, int flags);
UserInfo createProfileForUser(in String name, int flags, int userHandle);
+ UserInfo createRestrictedProfile(String name, int parentUserId);
void setUserEnabled(int userHandle);
boolean removeUser(int userHandle);
void setUserName(int userHandle, String name);
@@ -48,6 +49,7 @@ interface IUserManager {
UserInfo getUserInfo(int userHandle);
long getUserCreationTime(int userHandle);
boolean isRestricted();
+ boolean canHaveRestrictedProfile(int userId);
int getUserSerialNumber(int userHandle);
int getUserHandle(int userSerialNumber);
Bundle getUserRestrictions(int userHandle);
diff --git a/core/java/android/os/ParcelableParcel.java b/core/java/android/os/ParcelableParcel.java
index 11785f1072fd..5bbe6488d514 100644
--- a/core/java/android/os/ParcelableParcel.java
+++ b/core/java/android/os/ParcelableParcel.java
@@ -16,6 +16,8 @@
package android.os;
+import android.util.MathUtils;
+
/**
* Parcelable containing a raw Parcel of data.
* @hide
@@ -33,9 +35,13 @@ public class ParcelableParcel implements Parcelable {
mParcel = Parcel.obtain();
mClassLoader = loader;
int size = src.readInt();
+ if (size < 0) {
+ throw new IllegalArgumentException("Negative size read from parcel");
+ }
+
int pos = src.dataPosition();
- mParcel.appendFrom(src, src.dataPosition(), size);
- src.setDataPosition(pos + size);
+ src.setDataPosition(MathUtils.addOrThrow(pos, size));
+ mParcel.appendFrom(src, pos, size);
}
public Parcel getParcel() {
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7234e985757a..4ac361d00682 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -797,8 +797,8 @@ public class Process {
* {@link #myUid()} in that a particular user will have multiple
* distinct apps running under it each with their own uid.
*/
- public static final UserHandle myUserHandle() {
- return new UserHandle(UserHandle.getUserId(myUid()));
+ public static UserHandle myUserHandle() {
+ return UserHandle.of(UserHandle.getUserId(myUid()));
}
/**
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 213e0831c0f2..796addc4c3bc 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -17,7 +17,6 @@
package android.os;
import android.annotation.SystemApi;
-import android.util.SparseArray;
import java.io.PrintWriter;
@@ -83,8 +82,6 @@ public final class UserHandle implements Parcelable {
final int mHandle;
- private static final SparseArray<UserHandle> userHandles = new SparseArray<UserHandle>();
-
/**
* Checks to see if the user id is the same for the two uids, i.e., they belong to the same
* user.
@@ -144,15 +141,8 @@ public final class UserHandle implements Parcelable {
}
/** @hide */
- public static UserHandle getCallingUserHandle() {
- int userId = getUserId(Binder.getCallingUid());
- UserHandle userHandle = userHandles.get(userId);
- // Intentionally not synchronized to save time
- if (userHandle == null) {
- userHandle = new UserHandle(userId);
- userHandles.put(userId, userHandle);
- }
- return userHandle;
+ public static UserHandle of(int userId) {
+ return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId);
}
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 64e2505b5006..d178d20ac14c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -15,10 +15,12 @@
*/
package android.os;
+import android.accounts.AccountManager;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.UserInfo;
import android.content.res.Resources;
@@ -631,6 +633,19 @@ public class UserManager {
}
/**
+ * Checks if specified user can have restricted profile.
+ * @hide
+ */
+ public boolean canHaveRestrictedProfile(int userId) {
+ try {
+ return mService.canHaveRestrictedProfile(userId);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not check if user can have restricted profile", re);
+ return false;
+ }
+ }
+
+ /**
* Checks if the calling app is running as a guest user.
* @return whether the caller is a guest user.
* @hide
@@ -927,7 +942,8 @@ public class UserManager {
}
/**
- * Creates a restricted profile with the specified name.
+ * Creates a restricted profile with the specified name. This method also sets necessary
+ * restrictions and adds shared accounts.
*
* @param name profile's name
* @return UserInfo object for the created user, or null if the user could not be created.
@@ -935,13 +951,14 @@ public class UserManager {
*/
public UserInfo createRestrictedProfile(String name) {
try {
- if (isSplitSystemUser()) {
- return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
- UserHandle.getCallingUserId());
- } else {
- return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
- UserHandle.USER_SYSTEM);
+ UserHandle parentUserHandle = Process.myUserHandle();
+ UserInfo user = mService.createRestrictedProfile(name,
+ parentUserHandle.getIdentifier());
+ if (user != null) {
+ AccountManager.get(mContext).addSharedAccountsFromParentUser(parentUserHandle,
+ UserHandle.of(user.id));
}
+ return user;
} catch (RemoteException e) {
Log.w(TAG, "Could not create a restricted profile", e);
}
@@ -1321,12 +1338,15 @@ public class UserManager {
}
/**
- * Returns true if the user switcher should be shown, this will be if there
- * are multiple users that aren't managed profiles.
+ * Returns true if the user switcher should be shown, this will be if device supports multi-user
+ * and there are at least 2 users available that are not managed profiles.
* @hide
* @return true if user switcher should be shown.
*/
public boolean isUserSwitcherEnabled() {
+ if (!supportsMultipleUsers()) {
+ return false;
+ }
List<UserInfo> users = getUsers(true);
if (users == null) {
return false;
@@ -1337,8 +1357,8 @@ public class UserManager {
++switchableUserCount;
}
}
- final boolean guestEnabled = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.GUEST_USER_ENABLED, 0) == 1;
+ final boolean guestEnabled = !mContext.getSystemService(DevicePolicyManager.class)
+ .getGuestUserDisabled(null);
return switchableUserCount > 1 || guestEnabled;
}
diff --git a/core/java/android/preference/SeekBarPreference.java b/core/java/android/preference/SeekBarPreference.java
index 67f64090db16..5414f0007970 100644
--- a/core/java/android/preference/SeekBarPreference.java
+++ b/core/java/android/preference/SeekBarPreference.java
@@ -96,18 +96,15 @@ public class SeekBarPreference extends Preference
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (event.getAction() != KeyEvent.ACTION_UP) {
- if (keyCode == KeyEvent.KEYCODE_PLUS
- || keyCode == KeyEvent.KEYCODE_EQUALS) {
- setProgress(getProgress() + 1);
- return true;
- }
- if (keyCode == KeyEvent.KEYCODE_MINUS) {
- setProgress(getProgress() - 1);
- return true;
- }
+ if (event.getAction() != KeyEvent.ACTION_DOWN) {
+ return false;
+ }
+
+ SeekBar seekBar = (SeekBar) v.findViewById(com.android.internal.R.id.seekbar);
+ if (seekBar == null) {
+ return false;
}
- return false;
+ return seekBar.onKeyDown(keyCode, event);
}
public void setMax(int max) {
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 1a83cd567dc0..241e6db91756 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -19,6 +19,7 @@ package android.provider;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.system.OsConstants.SEEK_SET;
+import android.annotation.Nullable;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
@@ -136,6 +137,9 @@ public final class DocumentsContract {
*/
private static final int THUMBNAIL_BUFFER_SIZE = (int) (128 * KB_IN_BYTES);
+ /** {@hide} */
+ public static final String PACKAGE_DOCUMENTS_UI = "com.android.documentsui";
+
/**
* Constants related to a document, including {@link Cursor} column names
* and flags.
@@ -761,19 +765,33 @@ public final class DocumentsContract {
* @see #buildDocumentUri(String, String)
* @see #buildDocumentUriUsingTree(Uri, String)
*/
- public static boolean isDocumentUri(Context context, Uri uri) {
- final List<String> paths = uri.getPathSegments();
- if (paths.size() == 2 && PATH_DOCUMENT.equals(paths.get(0))) {
- return isDocumentsProvider(context, uri.getAuthority());
+ public static boolean isDocumentUri(Context context, @Nullable Uri uri) {
+ if (isContentUri(uri) && isDocumentsProvider(context, uri.getAuthority())) {
+ final List<String> paths = uri.getPathSegments();
+ if (paths.size() == 2) {
+ return PATH_DOCUMENT.equals(paths.get(0));
+ } else if (paths.size() == 4) {
+ return PATH_TREE.equals(paths.get(0)) && PATH_DOCUMENT.equals(paths.get(2));
+ }
}
- if (paths.size() == 4 && PATH_TREE.equals(paths.get(0))
- && PATH_DOCUMENT.equals(paths.get(2))) {
- return isDocumentsProvider(context, uri.getAuthority());
+ return false;
+ }
+
+ /** {@hide} */
+ public static boolean isRootUri(Context context, @Nullable Uri uri) {
+ if (isContentUri(uri) && isDocumentsProvider(context, uri.getAuthority())) {
+ final List<String> paths = uri.getPathSegments();
+ return (paths.size() == 2 && PATH_ROOT.equals(paths.get(0)));
}
return false;
}
/** {@hide} */
+ public static boolean isContentUri(@Nullable Uri uri) {
+ return uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme());
+ }
+
+ /** {@hide} */
public static boolean isTreeUri(Uri uri) {
final List<String> paths = uri.getPathSegments();
return (paths.size() >= 2 && PATH_TREE.equals(paths.get(0)));
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 225f0cf97c2e..d601831b863c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7689,14 +7689,6 @@ public final class Settings {
public static final String DEVICE_NAME = "device_name";
/**
- * Whether it should be possible to create a guest user on the device.
- * <p>
- * Type: int (0 for disabled, 1 for enabled)
- * @hide
- */
- public static final String GUEST_USER_ENABLED = "guest_user_enabled";
-
- /**
* Whether the NetworkScoringService has been first initialized.
* <p>
* Type: int (0 for false, 1 for true)
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 631057013e50..4de903efff18 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -755,6 +755,10 @@ public class ZenModeConfig implements Parcelable {
return rt;
}
+ public static ComponentName getScheduleConditionProvider() {
+ return new ComponentName(SYSTEM_AUTHORITY, "ScheduleConditionProvider");
+ }
+
public static class ScheduleInfo {
public int[] days;
public int startHour;
@@ -827,6 +831,10 @@ public class ZenModeConfig implements Parcelable {
return rt;
}
+ public static ComponentName getEventConditionProvider() {
+ return new ComponentName(SYSTEM_AUTHORITY, "EventConditionProvider");
+ }
+
public static class EventInfo {
public static final int REPLY_ANY_EXCEPT_NO = 0;
public static final int REPLY_YES_OR_MAYBE = 1;
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 1665c752752f..f2b6041457de 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -16,15 +16,17 @@
package android.text;
-import com.android.internal.annotations.GuardedBy;
-
import android.annotation.Nullable;
import android.util.Log;
-import libcore.io.IoUtils;
+import com.android.internal.annotations.GuardedBy;
import java.io.File;
import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.Locale;
@@ -45,12 +47,18 @@ public class Hyphenator {
@GuardedBy("sLock")
final static HashMap<Locale, Hyphenator> sMap = new HashMap<Locale, Hyphenator>();
- final static Hyphenator sEmptyHyphenator = new Hyphenator(StaticLayout.nLoadHyphenator(""));
+ final static Hyphenator sEmptyHyphenator =
+ new Hyphenator(StaticLayout.nLoadHyphenator(null, 0), null);
final private long mNativePtr;
- private Hyphenator(long nativePtr) {
+ // We retain a reference to the buffer to keep the memory mapping valid
+ @SuppressWarnings("unused")
+ final private ByteBuffer mBuffer;
+
+ private Hyphenator(long nativePtr, ByteBuffer b) {
mNativePtr = nativePtr;
+ mBuffer = b;
}
public long getNativePtr() {
@@ -94,12 +102,18 @@ public class Hyphenator {
}
private static Hyphenator loadHyphenator(String languageTag) {
- String patternFilename = "hyph-"+languageTag.toLowerCase(Locale.US)+".pat.txt";
+ String patternFilename = "hyph-" + languageTag.toLowerCase(Locale.US) + ".hyb";
File patternFile = new File(getSystemHyphenatorLocation(), patternFilename);
try {
- String patternData = IoUtils.readFileAsString(patternFile.getAbsolutePath());
- long nativePtr = StaticLayout.nLoadHyphenator(patternData);
- return new Hyphenator(nativePtr);
+ RandomAccessFile f = new RandomAccessFile(patternFile, "r");
+ try {
+ FileChannel fc = f.getChannel();
+ MappedByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
+ long nativePtr = StaticLayout.nLoadHyphenator(buf, 0);
+ return new Hyphenator(nativePtr, buf);
+ } finally {
+ f.close();
+ }
} catch (IOException e) {
Log.e(TAG, "error loading hyphenation " + patternFile, e);
return null;
@@ -152,7 +166,7 @@ public class Hyphenator {
sMap.put(null, null);
// TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
- String[] availableLanguages = {"en-US", "eu", "hu", "hy", "nb", "nn", "sa", "und-Ethi"};
+ String[] availableLanguages = {"en-US", "eu", "hu", "hy", "nb", "nn", "und-Ethi"};
for (int i = 0; i < availableLanguages.length; i++) {
String languageTag = availableLanguages[i];
Hyphenator h = loadHyphenator(languageTag);
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 79c4a55a737c..6ece09131a26 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -29,6 +29,7 @@ import android.util.Pools.SynchronizedPool;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
+import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Locale;
@@ -1244,7 +1245,7 @@ public class StaticLayout extends Layout {
private static native void nFreeBuilder(long nativePtr);
private static native void nFinishBuilder(long nativePtr);
- /* package */ static native long nLoadHyphenator(String patternData);
+ /* package */ static native long nLoadHyphenator(ByteBuffer buf, int offset);
private static native void nSetLocale(long nativePtr, String locale, long nativeHyphenator);
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
index 8b57d3d3d6c4..acca3edc98cf 100644
--- a/core/java/android/util/MathUtils.java
+++ b/core/java/android/util/MathUtils.java
@@ -185,4 +185,24 @@ public final class MathUtils {
public static void randomSeed(long seed) {
sRandom.setSeed(seed);
}
+
+ /**
+ * Returns the sum of the two parameters, or throws an exception if the resulting sum would
+ * cause an overflow or underflow.
+ * @throws IllegalArgumentException when overflow or underflow would occur.
+ */
+ public static int addOrThrow(int a, int b) throws IllegalArgumentException {
+ if (b == 0) {
+ return a;
+ }
+
+ if (b > 0 && a <= (Integer.MAX_VALUE - b)) {
+ return a + b;
+ }
+
+ if (b < 0 && a >= (Integer.MIN_VALUE - b)) {
+ return a + b;
+ }
+ throw new IllegalArgumentException("Addition overflow: " + a + " + " + b);
+ }
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 32ef99582ac9..7adfa8dbae4f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -144,7 +144,6 @@ interface IWindowManager
void setAppStartingWindow(IBinder token, String pkg, int theme,
in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
- void setAppWillBeHidden(IBinder token);
void setAppVisibility(IBinder token, boolean visible);
void startAppFreezingScreen(IBinder token, int configChanges);
void stopAppFreezingScreen(IBinder token, boolean force);
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 37312d064948..e200bef7ec52 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -72,6 +72,9 @@ public abstract class LayoutInflater {
private static final String TAG = LayoutInflater.class.getSimpleName();
private static final boolean DEBUG = false;
+ /** Empty stack trace used to avoid log spam in re-throw exceptions. */
+ private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
+
/**
* This field should be made private, so it is hidden from the SDK.
* {@hide}
@@ -532,15 +535,14 @@ public abstract class LayoutInflater {
}
} catch (XmlPullParserException e) {
- InflateException ex = new InflateException(e.getMessage());
- ex.initCause(e);
- throw ex;
+ final InflateException ie = new InflateException(e.getMessage(), e);
+ ie.setStackTrace(EMPTY_STACK_TRACE);
+ throw ie;
} catch (Exception e) {
- InflateException ex = new InflateException(
- parser.getPositionDescription()
- + ": " + e.getMessage());
- ex.initCause(e);
- throw ex;
+ final InflateException ie = new InflateException(parser.getPositionDescription()
+ + ": " + e.getMessage(), e);
+ ie.setStackTrace(EMPTY_STACK_TRACE);
+ throw ie;
} finally {
// Don't retain static reference on context.
mConstructorArgs[0] = lastContext;
@@ -625,27 +627,25 @@ public abstract class LayoutInflater {
return view;
} catch (NoSuchMethodException e) {
- InflateException ie = new InflateException(attrs.getPositionDescription()
- + ": Error inflating class "
- + (prefix != null ? (prefix + name) : name));
- ie.initCause(e);
+ final InflateException ie = new InflateException(attrs.getPositionDescription()
+ + ": Error inflating class " + (prefix != null ? (prefix + name) : name), e);
+ ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} catch (ClassCastException e) {
// If loaded class is not a View subclass
- InflateException ie = new InflateException(attrs.getPositionDescription()
- + ": Class is not a View "
- + (prefix != null ? (prefix + name) : name));
- ie.initCause(e);
+ final InflateException ie = new InflateException(attrs.getPositionDescription()
+ + ": Class is not a View " + (prefix != null ? (prefix + name) : name), e);
+ ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} catch (ClassNotFoundException e) {
// If loadClass fails, we should propagate the exception.
throw e;
} catch (Exception e) {
- InflateException ie = new InflateException(attrs.getPositionDescription()
- + ": Error inflating class "
- + (clazz == null ? "<unknown>" : clazz.getName()));
- ie.initCause(e);
+ final InflateException ie = new InflateException(
+ attrs.getPositionDescription() + ": Error inflating class "
+ + (clazz == null ? "<unknown>" : clazz.getName()), e);
+ ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
@@ -657,8 +657,7 @@ public abstract class LayoutInflater {
*/
private void failNotAllowed(String name, String prefix, AttributeSet attrs) {
throw new InflateException(attrs.getPositionDescription()
- + ": Class not allowed to be inflated "
- + (prefix != null ? (prefix + name) : name));
+ + ": Class not allowed to be inflated "+ (prefix != null ? (prefix + name) : name));
}
/**
@@ -774,14 +773,14 @@ public abstract class LayoutInflater {
} catch (ClassNotFoundException e) {
final InflateException ie = new InflateException(attrs.getPositionDescription()
- + ": Error inflating class " + name);
- ie.initCause(e);
+ + ": Error inflating class " + name, e);
+ ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} catch (Exception e) {
final InflateException ie = new InflateException(attrs.getPositionDescription()
- + ": Error inflating class " + name);
- ie.initCause(e);
+ + ": Error inflating class " + name, e);
+ ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
}
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index dcef14267b7f..304e9c048b60 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -349,7 +349,7 @@ public class ThreadedRenderer extends HardwareRenderer {
* @param right The right side of the protected bounds.
* @param bottom The bottom side of the protected bounds.
*/
- public void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) {
+ public void setContentDrawBounds(int left, int top, int right, int bottom) {
mStagedContentBounds.set(left, top, right, bottom);
}
@@ -370,9 +370,9 @@ public class ThreadedRenderer extends HardwareRenderer {
// renderer.
if (!mCurrentContentBounds.equals(mStagedContentBounds)) {
mCurrentContentBounds.set(mStagedContentBounds);
- nSetContentOverdrawProtectionBounds(mNativeProxy, mCurrentContentBounds.left,
- mCurrentContentBounds.top, mCurrentContentBounds.right,
- mCurrentContentBounds.bottom);
+ nSetContentDrawBounds(mNativeProxy, mCurrentContentBounds.left,
+ mCurrentContentBounds.top, mCurrentContentBounds.right,
+ mCurrentContentBounds.bottom);
}
attachInfo.mIgnoreDirtyState = false;
@@ -600,6 +600,6 @@ public class ThreadedRenderer extends HardwareRenderer {
boolean placeFront);
private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode);
private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
- private static native void nSetContentOverdrawProtectionBounds(long nativeProxy, int left,
+ private static native void nSetContentDrawBounds(long nativeProxy, int left,
int top, int right, int bottom);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2a1d757feb7b..2c7a43648f2c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5388,7 +5388,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
protected boolean performButtonActionOnTouchDown(MotionEvent event) {
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE &&
(event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) {
- showContextMenu(event.getX(), event.getY(), event.getMetaState());
+ showContextMenu(event.getX(), event.getY());
mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT;
return true;
}
@@ -5409,13 +5409,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @param x The referenced x coordinate.
* @param y The referenced y coordinate.
- * @param metaState The keyboard modifiers that were pressed.
* @return Whether a context menu was displayed.
- *
- * @hide
*/
- public boolean showContextMenu(float x, float y, int metaState) {
- return showContextMenu();
+ public boolean showContextMenu(float x, float y) {
+ return getParent().showContextMenuForChild(this, x, y);
}
/**
@@ -6652,12 +6649,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Sets a delegate for implementing accessibility support via composition as
- * opposed to inheritance. The delegate's primary use is for implementing
- * backwards compatible widgets. For more details see {@link AccessibilityDelegate}.
- *
- * @param delegate The delegate instance.
+ * Sets a delegate for implementing accessibility support via composition
+ * (as opposed to inheritance). For more details, see
+ * {@link AccessibilityDelegate}.
+ * <p>
+ * <strong>Note:</strong> On platform versions prior to
+ * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on
+ * views in the {@code android.widget.*} package are called <i>before</i>
+ * host methods. This prevents certain properties such as class name from
+ * being modified by overriding
+ * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)},
+ * as any changes will be overwritten by the host class.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate
+ * methods are called <i>after</i> host methods, which all properties to be
+ * modified without being overwritten by the host class.
*
+ * @param delegate the object to which accessibility method calls should be
+ * delegated
* @see AccessibilityDelegate
*/
public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) {
@@ -22280,6 +22289,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* corresponding delegate method without altering the behavior of the rest
* accessibility related methods of the host view.
* </p>
+ * <p>
+ * <strong>Note:</strong> On platform versions prior to
+ * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on
+ * views in the {@code android.widget.*} package are called <i>before</i>
+ * host methods. This prevents certain properties such as class name from
+ * being modified by overriding
+ * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)},
+ * as any changes will be overwritten by the host class.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate
+ * methods are called <i>after</i> host methods, which all properties to be
+ * modified without being overwritten by the host class.
*/
public static class AccessibilityDelegate {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index bdcd998de7c7..475ce2feed50 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -767,6 +767,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
return mParent != null && mParent.showContextMenuForChild(originalView);
}
+ @Override
+ public boolean showContextMenuForChild(View originalView, float x, float y) {
+ return mParent != null && mParent.showContextMenuForChild(originalView, x, y);
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 15b86d1245b2..07f1e2cbdb4f 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -182,6 +182,17 @@ public interface ViewParent {
public boolean showContextMenuForChild(View originalView);
/**
+ * Bring up a context menu for the specified view at the given x/y offset from
+ * the top left corner.
+ *
+ * @param originalView
+ * @param x The x offset at which to open the menu
+ * @param y The y offset at which to open the menu
+ * @return true if a context menu was displayed
+ */
+ public boolean showContextMenuForChild(View originalView, float x, float y);
+
+ /**
* Have the parent populate the specified context menu if it has anything to
* add (and then recurse on its parent).
*
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8403c46e85bc..7cf23e717f6e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -73,6 +73,7 @@ import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
+import android.view.WindowCallbacks;
import android.widget.Scroller;
import com.android.internal.R;
@@ -115,6 +116,12 @@ public final class ViewRootImpl implements ViewParent,
private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
/**
+ * Set to false if we do not want to use the multi threaded renderer. Note that by disabling
+ * this, WindowCallbacks will not fire.
+ */
+ private static final boolean USE_MT_RENDERER = true;
+
+ /**
* Set this system property to true to force the view hierarchy to render
* at 60 Hz. This can be used to measure the potential framerate.
*/
@@ -132,11 +139,11 @@ public final class ViewRootImpl implements ViewParent,
static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
- static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
+ static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
static boolean sFirstDrawComplete = false;
+ static final ArrayList<WindowCallbacks> sWindowCallbacks = new ArrayList();
- static final ArrayList<ComponentCallbacks> sConfigCallbacks
- = new ArrayList<ComponentCallbacks>();
+ static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList();
final Context mContext;
final IWindowSession mWindowSession;
@@ -417,6 +424,22 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ public static void addWindowCallbacks(WindowCallbacks callback) {
+ if (USE_MT_RENDERER) {
+ synchronized (sWindowCallbacks) {
+ sWindowCallbacks.add(callback);
+ }
+ }
+ }
+
+ public static void removeWindowCallbacks(WindowCallbacks callback) {
+ if (USE_MT_RENDERER) {
+ synchronized (sWindowCallbacks) {
+ sWindowCallbacks.remove(callback);
+ }
+ }
+ }
+
// FIXME for perf testing only
private boolean mProfile = false;
@@ -1378,6 +1401,7 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mWindowVisibility = viewVisibility;
host.dispatchWindowVisibilityChanged(viewVisibility);
if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
+ endDragResizing();
destroyHardwareResources();
}
if (viewVisibility == View.GONE) {
@@ -1701,14 +1725,20 @@ public final class ViewRootImpl implements ViewParent,
final boolean dragResizing = (relayoutResult
& WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING) != 0;
if (mDragResizing != dragResizing) {
- mDragResizing = dragResizing;
- mFullRedrawNeeded = true;
+ if (dragResizing) {
+ startDragResizing(frame);
+ } else {
+ // We shouldn't come here, but if we come we should end the resize.
+ endDragResizing();
+ }
}
- if (dragResizing) {
- mCanvasOffsetX = mWinFrame.left;
- mCanvasOffsetY = mWinFrame.top;
- } else {
- mCanvasOffsetX = mCanvasOffsetY = 0;
+ if (!USE_MT_RENDERER) {
+ if (dragResizing) {
+ mCanvasOffsetX = mWinFrame.left;
+ mCanvasOffsetY = mWinFrame.top;
+ } else {
+ mCanvasOffsetX = mCanvasOffsetY = 0;
+ }
}
} catch (RemoteException e) {
}
@@ -6240,6 +6270,11 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
+ public boolean showContextMenuForChild(View originalView, float x, float y) {
+ return false;
+ }
+
+ @Override
public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
return null;
}
@@ -6630,6 +6665,15 @@ public final class ViewRootImpl implements ViewParent,
Configuration newConfig) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
+ // Tell all listeners that we are resizing the window so that the chrome can get
+ // updated as fast as possible on a separate thread,
+ if (mViewAncestor.get().mDragResizing) {
+ synchronized (sWindowCallbacks) {
+ for (int i = sWindowCallbacks.size() - 1; i >= 0; i--) {
+ sWindowCallbacks.get(i).onWindowSizeIsChanging(frame);
+ }
+ }
+ }
viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
visibleInsets, stableInsets, outsets, reportDraw, newConfig);
}
@@ -6799,6 +6843,36 @@ public final class ViewRootImpl implements ViewParent,
}
/**
+ * Start a drag resizing which will inform all listeners that a window resize is taking place.
+ */
+ private void startDragResizing(Rect initialBounds) {
+ if (!mDragResizing) {
+ mDragResizing = true;
+ synchronized (sWindowCallbacks) {
+ for (int i = sWindowCallbacks.size() - 1; i >= 0; i--) {
+ sWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds);
+ }
+ }
+ mFullRedrawNeeded = true;
+ }
+ }
+
+ /**
+ * End a drag resize which will inform all listeners that a window resize has ended.
+ */
+ private void endDragResizing() {
+ if (mDragResizing) {
+ mDragResizing = false;
+ synchronized (sWindowCallbacks) {
+ for (int i = sWindowCallbacks.size() - 1; i >= 0; i--) {
+ sWindowCallbacks.get(i).onWindowDragResizeEnd();
+ }
+ }
+ mFullRedrawNeeded = true;
+ }
+ }
+
+ /**
* Class for managing the accessibility interaction connection
* based on the global accessibility state.
*/
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 0e7089ff7a8c..5f4e7af9390e 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -2016,4 +2016,8 @@ public abstract class Window {
public boolean hasNonClientDecorView() {
return false;
}
+
+ /** @hide */
+ public void setTheme(int resId) {
+ }
}
diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java
new file mode 100644
index 000000000000..cb6e98353a59
--- /dev/null
+++ b/core/java/android/view/WindowCallbacks.java
@@ -0,0 +1,48 @@
+/*
+ * 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.view;
+
+import android.graphics.Rect;
+
+/**
+ * These callbacks are used to communicate window configuration changes while the user is performing
+ * window changes.
+ * @hide
+ */
+public interface WindowCallbacks {
+ /**
+ * Called by the system when the window got changed by the user, before the layouter got called.
+ * It can be used to perform a "quick and dirty" resize which should never take more then 4ms to
+ * complete.
+ *
+ * <p>At the time the layouting has not happened yet.
+ *
+ * @param newBounds The new window frame bounds.
+ */
+ void onWindowSizeIsChanging(Rect newBounds);
+
+ /**
+ * Called when a drag resize starts.
+ * @param initialBounds The initial bounds where the window will be.
+ */
+ void onWindowDragResizeStart(Rect initialBounds);
+
+ /**
+ * Called when a drag resize ends.
+ */
+ void onWindowDragResizeEnd();
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 5724f526918b..b8faf0c6cf98 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3080,6 +3080,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
private class CheckForLongPress extends WindowRunnnable implements Runnable {
+ private static final int INVALID_COORD = -1;
+ private float mX = INVALID_COORD;
+ private float mY = INVALID_COORD;
+
+ private void setCoords(float x, float y) {
+ mX = x;
+ mY = y;
+ }
+
@Override
public void run() {
final int motionPosition = mMotionPosition;
@@ -3090,7 +3099,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
boolean handled = false;
if (sameWindow() && !mDataChanged) {
- handled = performLongPress(child, longPressPosition, longPressId);
+ if (mX != INVALID_COORD && mY != INVALID_COORD) {
+ handled = performLongPress(child, longPressPosition, longPressId, mX, mY);
+ } else {
+ handled = performLongPress(child, longPressPosition, longPressId);
+ }
}
if (handled) {
mTouchMode = TOUCH_MODE_REST;
@@ -3146,6 +3159,16 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
boolean performLongPress(final View child,
final int longPressPosition, final long longPressId) {
+ return performLongPress(
+ child,
+ longPressPosition,
+ longPressId,
+ CheckForLongPress.INVALID_COORD,
+ CheckForLongPress.INVALID_COORD);
+ }
+
+ boolean performLongPress(final View child,
+ final int longPressPosition, final long longPressId, float x, float y) {
// CHOICE_MODE_MULTIPLE_MODAL takes over long press.
if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
if (mChoiceActionMode == null &&
@@ -3163,7 +3186,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
if (!handled) {
mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
- handled = super.showContextMenuForChild(AbsListView.this);
+ if (x != CheckForLongPress.INVALID_COORD && y != CheckForLongPress.INVALID_COORD) {
+ handled = super.showContextMenuForChild(AbsListView.this, x, y);
+ } else {
+ handled = super.showContextMenuForChild(AbsListView.this);
+ }
}
if (handled) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
@@ -3178,17 +3205,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
/** @hide */
@Override
- public boolean showContextMenu(float x, float y, int metaState) {
+ public boolean showContextMenu(float x, float y) {
final int position = pointToPosition((int)x, (int)y);
if (position != INVALID_POSITION) {
final long id = mAdapter.getItemId(position);
View child = getChildAt(position - mFirstPosition);
if (child != null) {
mContextMenuInfo = createContextMenuInfo(child, position, id);
- return super.showContextMenuForChild(AbsListView.this);
+ return super.showContextMenuForChild(AbsListView.this, x, y);
}
}
- return super.showContextMenu(x, y, metaState);
+ return super.showContextMenu(x, y);
}
@Override
@@ -3341,6 +3368,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mPendingCheckForLongPress == null) {
mPendingCheckForLongPress = new CheckForLongPress();
}
+ mPendingCheckForLongPress.setCoords(x, y);
mPendingCheckForLongPress.rememberWindowAttachCount();
postDelayed(mPendingCheckForLongPress, longPressTimeout);
} else {
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 68855ff72531..10aefe4eb714 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -666,7 +666,7 @@ public abstract class AbsSeekBar extends ProgressBar {
progress += scale * max;
setHotspot(x, (int) event.getY());
- setProgress((int) progress, true);
+ setProgressInternal((int) progress, true, false);
}
/**
@@ -706,9 +706,12 @@ public abstract class AbsSeekBar extends ProgressBar {
int increment = mKeyProgressIncrement;
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_MINUS:
increment = -increment;
// fallthrough
case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_PLUS:
+ case KeyEvent.KEYCODE_EQUALS:
increment = isLayoutRtl() ? -increment : increment;
if (setProgressInternal(getProgress() + increment, true, true)) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index fddc40fc77b7..f53aa38a4c7a 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2645,6 +2645,8 @@ public class Editor {
private SuggestionAdapter mSuggestionsAdapter;
private final Comparator<SuggestionSpan> mSuggestionSpanComparator;
private final HashMap<SuggestionSpan, Integer> mSpansLengths;
+ private final TextAppearanceSpan mHighlightSpan = new TextAppearanceSpan(
+ mTextView.getContext(), android.R.style.TextAppearance_SuggestionHighlight);
private class CustomPopupWindow extends PopupWindow {
public CustomPopupWindow(Context context, int defStyleAttr) {
@@ -2710,8 +2712,6 @@ public class Editor {
SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
int suggestionIndex; // the index of this suggestion inside suggestionSpan
SpannableStringBuilder text = new SpannableStringBuilder();
- TextAppearanceSpan highlightSpan = new TextAppearanceSpan(mTextView.getContext(),
- android.R.style.TextAppearance_SuggestionHighlight);
}
private class SuggestionAdapter extends BaseAdapter {
@@ -2948,7 +2948,7 @@ public class Editor {
suggestionInfo.suggestionIndex = ADD_TO_DICTIONARY;
suggestionInfo.text.replace(0, suggestionInfo.text.length(), mTextView.
getContext().getString(com.android.internal.R.string.addToDictionary));
- suggestionInfo.text.setSpan(suggestionInfo.highlightSpan, 0, 0,
+ suggestionInfo.text.setSpan(mHighlightSpan, 0, 0,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mNumberOfSuggestions++;
@@ -2961,8 +2961,7 @@ public class Editor {
suggestionInfo.suggestionIndex = DELETE_TEXT;
suggestionInfo.text.replace(0, suggestionInfo.text.length(),
mTextView.getContext().getString(com.android.internal.R.string.deleteText));
- suggestionInfo.text.setSpan(suggestionInfo.highlightSpan, 0, 0,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ suggestionInfo.text.setSpan(mHighlightSpan, 0, 0, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mNumberOfSuggestions++;
if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
@@ -2993,8 +2992,8 @@ public class Editor {
suggestionInfo.suggestionEnd = suggestionInfo.suggestionStart
+ suggestionInfo.text.length();
- suggestionInfo.text.setSpan(suggestionInfo.highlightSpan, 0,
- suggestionInfo.text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ suggestionInfo.text.setSpan(mHighlightSpan, 0, suggestionInfo.text.length(),
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// Add the text before and after the span.
final String textAsString = text.toString();
diff --git a/core/java/android/widget/MenuPopupWindow.java b/core/java/android/widget/MenuPopupWindow.java
index eac3a0b51758..1fb62d0fa6c9 100644
--- a/core/java/android/widget/MenuPopupWindow.java
+++ b/core/java/android/widget/MenuPopupWindow.java
@@ -152,8 +152,16 @@ public class MenuPopupWindow extends ListPopupWindow implements MenuItemHoverLis
boolean superVal = super.onHoverEvent(ev);
if (dispatchHover && mHoverListener != null) {
- mHoverListener.onItemHovered(
- ((MenuAdapter) getAdapter()).getAdapterMenu(), position);
+ ListAdapter adapter = getAdapter();
+ MenuAdapter menuAdapter;
+ if (adapter instanceof HeaderViewListAdapter) {
+ menuAdapter = (MenuAdapter) ((HeaderViewListAdapter) adapter)
+ .getWrappedAdapter();
+ } else {
+ menuAdapter = (MenuAdapter) adapter;
+ }
+
+ mHoverListener.onItemHovered(menuAdapter.getAdapterMenu(), position);
}
return superVal;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index f9fa0272f147..7b9de7967db3 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -18,6 +18,7 @@ package android.widget;
import com.android.internal.R;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -1449,11 +1450,13 @@ public class PopupWindow {
anchor.getLocationOnScreen(mScreenLocation);
onTop = (displayFrame.bottom - mScreenLocation[1] - anchorHeight - yoff) <
(mScreenLocation[1] - yoff - displayFrame.top);
- if (onTop) {
- p.gravity = Gravity.LEFT | Gravity.BOTTOM;
- p.y = root.getHeight() - mDrawingLocation[1] + yoff;
- } else {
- p.y = mDrawingLocation[1] + anchorHeight + yoff;
+ if (!mOverlapAnchor) {
+ if (onTop) {
+ p.gravity = Gravity.LEFT | Gravity.BOTTOM;
+ p.y = root.getHeight() - mDrawingLocation[1] + yoff;
+ } else {
+ p.y = mDrawingLocation[1] + anchorHeight + yoff;
+ }
}
}
@@ -1469,13 +1472,21 @@ public class PopupWindow {
p.width = Math.min(p.width, displayFrameWidth);
}
- if (onTop) {
- final int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
- if (popupTop < 0) {
- p.y += popupTop;
+ if (mOverlapAnchor) {
+ final int displayFrameHeight = displayFrame.bottom - displayFrame.top;
+ final int bottom = p.y + p.height;
+ if (bottom > displayFrame.bottom) {
+ p.y -= bottom - displayFrameHeight;
}
} else {
- p.y = Math.max(p.y, displayFrame.top);
+ if (onTop) {
+ final int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
+ if (popupTop < 0) {
+ p.y += popupTop;
+ }
+ } else {
+ p.y = Math.max(p.y, displayFrame.top);
+ }
}
}
@@ -1494,7 +1505,7 @@ public class PopupWindow {
* @return The maximum available height for the popup to be completely
* shown.
*/
- public int getMaxAvailableHeight(View anchor) {
+ public int getMaxAvailableHeight(@NonNull View anchor) {
return getMaxAvailableHeight(anchor, 0);
}
@@ -1509,7 +1520,7 @@ public class PopupWindow {
* @return The maximum available height for the popup to be completely
* shown.
*/
- public int getMaxAvailableHeight(View anchor, int yOffset) {
+ public int getMaxAvailableHeight(@NonNull View anchor, int yOffset) {
return getMaxAvailableHeight(anchor, yOffset, false);
}
@@ -1527,22 +1538,29 @@ public class PopupWindow {
* bottom decorations
* @return The maximum available height for the popup to be completely
* shown.
- *
- * @hide Pending API council approval.
*/
- public int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
+ public int getMaxAvailableHeight(
+ @NonNull View anchor, int yOffset, boolean ignoreBottomDecorations) {
final Rect displayFrame = new Rect();
anchor.getWindowVisibleDisplayFrame(displayFrame);
final int[] anchorPos = mDrawingLocation;
anchor.getLocationOnScreen(anchorPos);
- int bottomEdge = displayFrame.bottom;
+ final int bottomEdge;
if (ignoreBottomDecorations) {
- Resources res = anchor.getContext().getResources();
+ final Resources res = anchor.getContext().getResources();
bottomEdge = res.getDisplayMetrics().heightPixels;
+ } else {
+ bottomEdge = displayFrame.bottom;
+ }
+
+ final int distanceToBottom;
+ if (mOverlapAnchor) {
+ distanceToBottom = bottomEdge - anchorPos[1] - yOffset;
+ } else {
+ distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
}
- final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
// anchorPos[1] is distance from anchor to top of screen
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7ca333947918..ca1b211bc291 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -31,6 +31,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.Rect;
@@ -55,6 +56,8 @@ import android.view.ViewGroup;
import android.widget.AdapterView.OnItemClickListener;
import libcore.util.Objects;
+import com.android.internal.R;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -206,14 +209,22 @@ public class RemoteViews implements Parcelable, Filter {
/** @hide */
public static class OnClickHandler {
+
+ private int mEnterAnimationId;
+
public boolean onClickHandler(View view, PendingIntent pendingIntent,
Intent fillInIntent) {
try {
// TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
Context context = view.getContext();
- ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
- 0, 0,
- view.getMeasuredWidth(), view.getMeasuredHeight());
+ ActivityOptions opts;
+ if (mEnterAnimationId != 0) {
+ opts = ActivityOptions.makeCustomAnimation(context, mEnterAnimationId, 0);
+ } else {
+ opts = ActivityOptions.makeScaleUpAnimation(view,
+ 0, 0,
+ view.getMeasuredWidth(), view.getMeasuredHeight());
+ }
context.startIntentSender(
pendingIntent.getIntentSender(), fillInIntent,
Intent.FLAG_ACTIVITY_NEW_TASK,
@@ -228,6 +239,10 @@ public class RemoteViews implements Parcelable, Filter {
}
return true;
}
+
+ public void setEnterAnimationId(int enterAnimationId) {
+ mEnterAnimationId = enterAnimationId;
+ }
}
/**
@@ -2761,11 +2776,31 @@ public class RemoteViews implements Parcelable, Filter {
inflater.setFilter(this);
result = inflater.inflate(rvToApply.getLayoutId(), parent, false);
+ loadTransitionOverride(context, handler);
+
rvToApply.performApply(result, parent, handler);
return result;
}
+ private static void loadTransitionOverride(Context context,
+ RemoteViews.OnClickHandler handler) {
+ if (handler != null && context.getResources().getBoolean(
+ com.android.internal.R.bool.config_overrideRemoteViewsActivityTransition)) {
+ TypedArray windowStyle = context.getTheme().obtainStyledAttributes(
+ com.android.internal.R.styleable.Window);
+ int windowAnimations = windowStyle.getResourceId(
+ com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
+ TypedArray windowAnimationStyle = context.obtainStyledAttributes(
+ windowAnimations, com.android.internal.R.styleable.WindowAnimation);
+ handler.setEnterAnimationId(windowAnimationStyle.getResourceId(
+ com.android.internal.R.styleable.
+ WindowAnimation_activityOpenRemoteViewsEnterAnimation, 0));
+ windowStyle.recycle();
+ windowAnimationStyle.recycle();
+ }
+ }
+
/**
* Applies all of the actions to the provided view.
*
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 2172b5c57893..f0e216fc7873 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -40,6 +40,7 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.DocumentsContract;
import android.service.chooser.ChooserTarget;
import android.service.chooser.ChooserTargetService;
import android.service.chooser.IChooserTargetResult;
@@ -269,7 +270,20 @@ public class ChooserActivity extends ResolverActivity {
}
@Override
- boolean shouldAutoLaunchSingleChoice() {
+ boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
+ final Intent intent = target.getResolvedIntent();
+ final ResolveInfo resolve = target.getResolveInfo();
+
+ // When GET_CONTENT is handled by the DocumentsUI system component,
+ // we're okay automatically launching it, since it offers it's own
+ // intent disambiguation UI.
+ if (intent != null && Intent.ACTION_GET_CONTENT.equals(intent.getAction())
+ && resolve != null && resolve.priority > 0
+ && resolve.activityInfo != null && DocumentsContract.PACKAGE_DOCUMENTS_UI
+ .equals(resolve.activityInfo.packageName)) {
+ return true;
+ }
+
return false;
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ef9d1cebff57..17104894310e 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -796,7 +796,7 @@ public class ResolverActivity extends Activity {
return false;
}
- boolean shouldAutoLaunchSingleChoice() {
+ boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
return true;
}
@@ -837,18 +837,21 @@ public class ResolverActivity extends Activity {
mAlwaysUseOption = alwaysUseOption;
int count = mAdapter.getUnfilteredCount();
- if ((!shouldAutoLaunchSingleChoice() && count > 0)
- || count > 1
- || (count == 1 && mAdapter.getOtherProfile() != null)) {
+ if (count == 1 && mAdapter.getOtherProfile() == null) {
+ // Only one target, so we're a candidate to auto-launch!
+ final TargetInfo target = mAdapter.targetInfoForPosition(0, false);
+ if (shouldAutoLaunchSingleChoice(target)) {
+ safelyStartActivity(target);
+ mPackageMonitor.unregister();
+ mRegistered = false;
+ finish();
+ return true;
+ }
+ }
+ if (count > 0) {
setContentView(layoutId);
mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
onPrepareAdapterView(mAdapterView, mAdapter, alwaysUseOption);
- } else if (count == 1) {
- safelyStartActivity(mAdapter.targetInfoForPosition(0, false));
- mPackageMonitor.unregister();
- mRegistered = false;
- finish();
- return true;
} else {
setContentView(R.layout.resolver_list);
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index b6240e48a1fd..c25db65b342b 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -46,6 +46,9 @@ public class MetricsLogger implements MetricsConstants {
public static final int ACTION_FINGERPRINT_RENAME = 254;
public static final int ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
public static final int ACTION_WIGGLE_CAMERA_GESTURE = 256;
+ public static final int QS_LOCK_TILE = 257;
+ public static final int QS_USER_TILE = 258;
+ public static final int QS_BATTERY_TILE = 259;
public static void visible(Context context, int category) throws IllegalArgumentException {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index e39bf607e53e..64b7768c8337 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -105,7 +105,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 131 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 132 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -5704,6 +5704,8 @@ public final class BatteryStatsImpl extends BatteryStats {
cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
}
+ } else {
+ mCpuClusterSpeed[cluster] = null;
}
}
} else {
@@ -9382,13 +9384,14 @@ public final class BatteryStatsImpl extends BatteryStats {
u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][];
for (int cluster = 0; cluster < numClusters; cluster++) {
- int NSB = in.readInt();
- if (mPowerProfile != null &&
- mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) {
- throw new ParcelFormatException("File corrupt: too many speed bins " + NSB);
- }
-
if (in.readInt() != 0) {
+ final int NSB = in.readInt();
+ if (mPowerProfile != null &&
+ mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) {
+ throw new ParcelFormatException("File corrupt: too many speed bins " +
+ NSB);
+ }
+
u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[NSB];
for (int speed = 0; speed < NSB; speed++) {
if (in.readInt() != 0) {
@@ -9397,6 +9400,8 @@ public final class BatteryStatsImpl extends BatteryStats {
u.mCpuClusterSpeed[cluster][speed].readSummaryFromParcelLocked(in);
}
}
+ } else {
+ u.mCpuClusterSpeed[cluster] = null;
}
}
} else {
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index db2b41f52b8c..13d046e45070 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -20,6 +20,7 @@ import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.SystemClock;
import android.util.Slog;
+
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -91,32 +92,29 @@ public class InstallerConnection {
}
}
- public int dexopt(String apkPath, int uid, boolean isPublic,
- String instructionSet, int dexoptNeeded, boolean bootComplete) {
- return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded,
- false, false, null, bootComplete);
+ public int dexopt(String apkPath, int uid, String instructionSet,
+ int dexoptNeeded, int dexFlags) {
+ return dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
+ null /*outputPath*/, dexFlags);
}
- public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
- String instructionSet, int dexoptNeeded, boolean vmSafeMode,
- boolean debuggable, String outputPath, boolean bootComplete) {
+ public int dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+ int dexoptNeeded, String outputPath, int dexFlags) {
StringBuilder builder = new StringBuilder("dexopt");
builder.append(' ');
builder.append(apkPath);
builder.append(' ');
builder.append(uid);
- builder.append(isPublic ? " 1" : " 0");
builder.append(' ');
builder.append(pkgName);
builder.append(' ');
builder.append(instructionSet);
builder.append(' ');
builder.append(dexoptNeeded);
- builder.append(vmSafeMode ? " 1" : " 0");
- builder.append(debuggable ? " 1" : " 0");
builder.append(' ');
builder.append(outputPath != null ? outputPath : "!");
- builder.append(bootComplete ? " 1" : " 0");
+ builder.append(' ');
+ builder.append(dexFlags);
return execute(builder.toString());
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index eee8b0812ea0..aaa89df1905d 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -486,8 +486,8 @@ public class ZygoteInit {
final int dexoptNeeded = DexFile.getDexOptNeeded(
classPathElement, "*", instructionSet, false /* defer */);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
- installer.dexopt(classPathElement, Process.SYSTEM_UID, false,
- instructionSet, dexoptNeeded, false /* boot complete */);
+ installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
+ dexoptNeeded, 0 /*dexFlags*/);
}
}
} catch (IOException ioe) {
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
new file mode 100644
index 000000000000..4f17c39ddf81
--- /dev/null
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -0,0 +1,55 @@
+/*
+ * 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.internal.policy;
+
+import android.content.Context;
+import android.view.ContextThemeWrapper;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+
+/**
+ * Context for decor views which can be seeded with pure application context and not depend on the
+ * activity, but still provide some of the facilities that Activity has, e.g. themes.
+ *
+ * @hide
+ */
+class DecorContext extends ContextThemeWrapper {
+ private PhoneWindow mPhoneWindow;
+ private WindowManager mWindowManager;
+
+ public DecorContext(Context context) {
+ super(context, null);
+ }
+
+ void setPhoneWindow(PhoneWindow phoneWindow) {
+ mPhoneWindow = phoneWindow;
+ mWindowManager = null;
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ if (Context.WINDOW_SERVICE.equals(name)) {
+ if (mWindowManager == null) {
+ WindowManagerImpl wm =
+ (WindowManagerImpl) super.getSystemService(Context.WINDOW_SERVICE);
+ mWindowManager = wm.createLocalWindowManager(mPhoneWindow);
+ }
+ return mWindowManager;
+ }
+ return super.getSystemService(name);
+ }
+}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 3353d1669c9f..c9b81190ce38 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -32,6 +32,8 @@ import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.app.ActivityManagerNative;
import android.app.SearchManager;
+import android.content.ContextWrapper;
+import android.content.res.Resources;
import android.os.Build;
import android.os.UserHandle;
@@ -71,6 +73,7 @@ import com.android.internal.view.menu.IconMenuPresenter;
import com.android.internal.view.menu.ListMenuPresenter;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuDialogHelper;
+import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.view.menu.MenuView;
import com.android.internal.widget.ActionBarContextView;
@@ -274,6 +277,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private ContextMenuBuilder mContextMenu;
private MenuDialogHelper mContextMenuHelper;
+ private MenuPopupHelper mContextMenuPopupHelper;
private boolean mClosingActionMenu;
private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
@@ -315,6 +319,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private Rect mOutsets = new Rect();
private boolean mIsStartingWindow;
+ private int mTheme = -1;
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -335,6 +340,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mElevation = preservedWindow.getElevation();
mLoadEleveation = false;
mForceDecorInstall = true;
+ // If we're preserving window, carry over the app token from the preserved
+ // window, as we'll be skipping the addView in handleResumeActivity(), and
+ // the token will not be updated as for a new window.
+ getAttributes().token = preservedWindow.getAttributes().token;
}
}
@@ -1123,6 +1132,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mContextMenuHelper.dismiss();
mContextMenuHelper = null;
}
+ if (mContextMenuPopupHelper != null) {
+ mContextMenuPopupHelper.dismiss();
+ mContextMenuPopupHelper = null;
+ }
}
@Override
@@ -2292,7 +2305,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
- private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
+ private static final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
/* package */int mDefaultOpacity = PixelFormat.OPAQUE;
@@ -2362,6 +2375,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private int mRootScrollY = 0;
+ private PhoneWindow mWindow;
+
public DecorView(Context context, int featureId) {
super(context);
mFeatureId = featureId;
@@ -2383,7 +2398,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public void onDraw(Canvas c) {
super.onDraw(c);
- mBackgroundFallback.draw(mContentRoot, c, mContentParent);
+ mBackgroundFallback.draw(mWindow.mContentRoot, c, mWindow.mContentParent);
}
@Override
@@ -2395,7 +2410,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (isDown && (event.getRepeatCount() == 0)) {
// First handle chording of panel key: if a panel key is held
// but not released, try to execute a shortcut in it.
- if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) {
+ if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
boolean handled = dispatchKeyShortcutEvent(event);
if (handled) {
return true;
@@ -2404,15 +2419,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// If a panel is open, perform a shortcut on it without the
// chorded panel key
- if ((mPreparedPanel != null) && mPreparedPanel.isOpen) {
- if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) {
+ if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
+ if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event, 0)) {
return true;
}
}
}
- if (!isDestroyed()) {
- final Callback cb = getCallback();
+ if (!mWindow.isDestroyed()) {
+ final Callback cb = mWindow.getCallback();
final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
: super.dispatchKeyEvent(event);
if (handled) {
@@ -2420,28 +2435,28 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
- return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
- : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
+ return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
+ : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
}
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent ev) {
// If the panel is already prepared, then perform the shortcut using it.
boolean handled;
- if (mPreparedPanel != null) {
- handled = performPanelShortcut(mPreparedPanel, ev.getKeyCode(), ev,
+ if (mWindow.mPreparedPanel != null) {
+ handled = mWindow.performPanelShortcut(mWindow.mPreparedPanel, ev.getKeyCode(), ev,
Menu.FLAG_PERFORM_NO_CLOSE);
if (handled) {
- if (mPreparedPanel != null) {
- mPreparedPanel.isHandled = true;
+ if (mWindow.mPreparedPanel != null) {
+ mWindow.mPreparedPanel.isHandled = true;
}
return true;
}
}
// Shortcut not handled by the panel. Dispatch to the view hierarchy.
- final Callback cb = getCallback();
- handled = cb != null && !isDestroyed() && mFeatureId < 0
+ final Callback cb = mWindow.getCallback();
+ handled = cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchKeyShortcutEvent(ev) : super.dispatchKeyShortcutEvent(ev);
if (handled) {
return true;
@@ -2451,10 +2466,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// combination such as Control+C. Temporarily prepare the panel then mark it
// unprepared again when finished to ensure that the panel will again be prepared
// the next time it is shown for real.
- PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
- if (st != null && mPreparedPanel == null) {
- preparePanel(st, ev);
- handled = performPanelShortcut(st, ev.getKeyCode(), ev,
+ PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
+ if (st != null && mWindow.mPreparedPanel == null) {
+ mWindow.preparePanel(st, ev);
+ handled = mWindow.performPanelShortcut(st, ev.getKeyCode(), ev,
Menu.FLAG_PERFORM_NO_CLOSE);
st.isPrepared = false;
if (handled) {
@@ -2466,23 +2481,23 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
- final Callback cb = getCallback();
- return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
- : super.dispatchTouchEvent(ev);
+ final Callback cb = mWindow.getCallback();
+ return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
+ ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
@Override
public boolean dispatchTrackballEvent(MotionEvent ev) {
- final Callback cb = getCallback();
- return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTrackballEvent(ev)
- : super.dispatchTrackballEvent(ev);
+ final Callback cb = mWindow.getCallback();
+ return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
+ ? cb.dispatchTrackballEvent(ev) : super.dispatchTrackballEvent(ev);
}
@Override
public boolean dispatchGenericMotionEvent(MotionEvent ev) {
- final Callback cb = getCallback();
- return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchGenericMotionEvent(ev)
- : super.dispatchGenericMotionEvent(ev);
+ final Callback cb = mWindow.getCallback();
+ return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
+ ? cb.dispatchGenericMotionEvent(ev) : super.dispatchGenericMotionEvent(ev);
}
public boolean superDispatchKeyEvent(KeyEvent event) {
@@ -2534,7 +2549,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
int action = event.getAction();
- if (mHasNonClientDecor && mNonClientDecorView.mVisible) {
+ if (mHasNonClientDecor && mWindow.mNonClientDecorView.mVisible) {
// Don't dispatch ACTION_DOWN to the non client decor if the window is
// resizable and the event was (starting) outside the window.
// Window resizing events should be handled by WindowManager.
@@ -2557,7 +2572,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
int x = (int)event.getX();
int y = (int)event.getY();
if (isOutOfBounds(x, y)) {
- closePanel(mFeatureId);
+ mWindow.closePanel(mFeatureId);
return true;
}
}
@@ -2583,7 +2598,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (action == MotionEvent.ACTION_MOVE) {
if (y > (mDownY+30)) {
Log.i(TAG, "Closing!");
- closePanel(mFeatureId);
+ mWindow.closePanel(mFeatureId);
mWatchingForMenu = false;
return true;
}
@@ -2599,8 +2614,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (action == MotionEvent.ACTION_DOWN) {
int y = (int)event.getY();
- if (y >= (getHeight()-5) && !hasChildren()) {
- Log.i(TAG, "Watchiing!");
+ if (y >= (getHeight()-5) && !mWindow.hasChildren()) {
+ Log.i(TAG, "Watching!");
mWatchingForMenu = true;
}
return false;
@@ -2614,7 +2629,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (action == MotionEvent.ACTION_MOVE) {
if (y < (getHeight()-30)) {
Log.i(TAG, "Opening!");
- openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent(
+ mWindow.openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent(
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
mWatchingForMenu = false;
return true;
@@ -2648,8 +2663,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
- final Callback cb = getCallback();
- if (cb != null && !isDestroyed()) {
+ final Callback cb = mWindow.getCallback();
+ if (cb != null && !mWindow.isDestroyed()) {
if (cb.dispatchPopulateAccessibilityEvent(event)) {
return true;
}
@@ -2686,7 +2701,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (SWEEP_OPEN_MENU) {
if (mMenuBackground == null && mFeatureId < 0
- && getAttributes().height
+ && mWindow.getAttributes().height
== WindowManager.LayoutParams.MATCH_PARENT) {
mMenuBackground = getContext().getDrawable(
R.drawable.menu_background);
@@ -2711,7 +2726,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
boolean fixedWidth = false;
if (widthMode == AT_MOST) {
- final TypedValue tvw = isPortrait ? mFixedWidthMinor : mFixedWidthMajor;
+ final TypedValue tvw = isPortrait ? mWindow.mFixedWidthMinor
+ : mWindow.mFixedWidthMajor;
if (tvw != null && tvw.type != TypedValue.TYPE_NULL) {
final int w;
if (tvw.type == TypedValue.TYPE_DIMENSION) {
@@ -2732,7 +2748,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
if (heightMode == AT_MOST) {
- final TypedValue tvh = isPortrait ? mFixedHeightMajor : mFixedHeightMinor;
+ final TypedValue tvh = isPortrait ? mWindow.mFixedHeightMajor
+ : mWindow.mFixedHeightMinor;
if (tvh != null && tvh.type != TypedValue.TYPE_NULL) {
final int h;
if (tvh.type == TypedValue.TYPE_DIMENSION) {
@@ -2750,21 +2767,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
- getOutsets(mOutsets);
- if (mOutsets.top > 0 || mOutsets.bottom > 0) {
+ getOutsets(mWindow.mOutsets);
+ if (mWindow.mOutsets.top > 0 || mWindow.mOutsets.bottom > 0) {
int mode = MeasureSpec.getMode(heightMeasureSpec);
if (mode != MeasureSpec.UNSPECIFIED) {
int height = MeasureSpec.getSize(heightMeasureSpec);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- height + mOutsets.top + mOutsets.bottom, mode);
+ height + mWindow.mOutsets.top + mWindow.mOutsets.bottom, mode);
}
}
- if (mOutsets.left > 0 || mOutsets.right > 0) {
+ if (mWindow.mOutsets.left > 0 || mWindow.mOutsets.right > 0) {
int mode = MeasureSpec.getMode(widthMeasureSpec);
if (mode != MeasureSpec.UNSPECIFIED) {
int width = MeasureSpec.getSize(widthMeasureSpec);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- width + mOutsets.left + mOutsets.right, mode);
+ width + mWindow.mOutsets.left + mWindow.mOutsets.right, mode);
}
}
@@ -2776,7 +2793,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
if (!fixedWidth && widthMode == AT_MOST) {
- final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor;
+ final TypedValue tv = isPortrait ? mWindow.mMinWidthMinor : mWindow.mMinWidthMajor;
if (tv.type != TypedValue.TYPE_NULL) {
final int min;
if (tv.type == TypedValue.TYPE_DIMENSION) {
@@ -2804,12 +2821,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- getOutsets(mOutsets);
- if (mOutsets.left > 0) {
- offsetLeftAndRight(-mOutsets.left);
+ getOutsets(mWindow.mOutsets);
+ if (mWindow.mOutsets.left > 0) {
+ offsetLeftAndRight(-mWindow.mOutsets.left);
}
- if (mOutsets.top > 0) {
- offsetTopAndBottom(-mOutsets.top);
+ if (mWindow.mOutsets.top > 0) {
+ offsetTopAndBottom(-mWindow.mOutsets.top);
}
}
@@ -2825,23 +2842,46 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public boolean showContextMenuForChild(View originalView) {
// Reuse the context menu builder
- if (mContextMenu == null) {
- mContextMenu = new ContextMenuBuilder(getContext());
- mContextMenu.setCallback(mContextMenuCallback);
+ if (mWindow.mContextMenu == null) {
+ mWindow.mContextMenu = new ContextMenuBuilder(getContext());
+ mWindow.mContextMenu.setCallback(mWindow.mContextMenuCallback);
} else {
- mContextMenu.clearAll();
+ mWindow.mContextMenu.clearAll();
}
- final MenuDialogHelper helper = mContextMenu.show(originalView,
+ final MenuDialogHelper helper = mWindow.mContextMenu.show(originalView,
originalView.getWindowToken());
if (helper != null) {
- helper.setPresenterCallback(mContextMenuCallback);
- } else if (mContextMenuHelper != null) {
+ helper.setPresenterCallback(mWindow.mContextMenuCallback);
+ } else if (mWindow.mContextMenuHelper != null) {
+ // No menu to show, but if we have a menu currently showing it just became blank.
+ // Close it.
+ mWindow.mContextMenuHelper.dismiss();
+ }
+ mWindow.mContextMenuHelper = helper;
+ return helper != null;
+ }
+
+ @Override
+ public boolean showContextMenuForChild(View originalView, float x, float y) {
+ // Reuse the context menu builder
+ if (mWindow.mContextMenu == null) {
+ mWindow.mContextMenu = new ContextMenuBuilder(getContext());
+ mWindow.mContextMenu.setCallback(mWindow.mContextMenuCallback);
+ } else {
+ mWindow.mContextMenu.clearAll();
+ }
+
+ final MenuPopupHelper helper = mWindow.mContextMenu.showPopup(
+ getContext(), originalView, x, y);
+ if (helper != null) {
+ helper.setCallback(mWindow.mContextMenuCallback);
+ } else if (mWindow.mContextMenuPopupHelper != null) {
// No menu to show, but if we have a menu currently showing it just became blank.
// Close it.
- mContextMenuHelper.dismiss();
+ mWindow.mContextMenuPopupHelper.dismiss();
}
- mContextMenuHelper = helper;
+ mWindow.mContextMenuPopupHelper = helper;
return helper != null;
}
@@ -2871,14 +2911,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
View originatingView, ActionMode.Callback callback, int type) {
ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
ActionMode mode = null;
- if (getCallback() != null && !isDestroyed()) {
+ if (mWindow.getCallback() != null && !mWindow.isDestroyed()) {
try {
- mode = getCallback().onWindowStartingActionMode(wrappedCallback, type);
+ mode = mWindow.getCallback().onWindowStartingActionMode(wrappedCallback, type);
} catch (AbstractMethodError ame) {
// Older apps might not implement the typed version of this method.
if (type == ActionMode.TYPE_PRIMARY) {
try {
- mode = getCallback().onWindowStartingActionMode(wrappedCallback);
+ mode = mWindow.getCallback().onWindowStartingActionMode(
+ wrappedCallback);
} catch (AbstractMethodError ame2) {
// Older apps might not implement this callback method at all.
}
@@ -2903,9 +2944,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mode = null;
}
}
- if (mode != null && getCallback() != null && !isDestroyed()) {
+ if (mode != null && mWindow.getCallback() != null && !mWindow.isDestroyed()) {
try {
- getCallback().onActionModeStarted(mode);
+ mWindow.getCallback().onActionModeStarted(mode);
} catch (AbstractMethodError ame) {
// Older apps might not implement this callback method.
}
@@ -2994,10 +3035,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
private WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
- WindowManager.LayoutParams attrs = getAttributes();
+ WindowManager.LayoutParams attrs = mWindow.getAttributes();
int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
- if (!mIsFloating && ActivityManager.isHighEndGfx()) {
+ if (!mWindow.mIsFloating && ActivityManager.isHighEndGfx()) {
boolean disallowAnimate = !isLaidOut();
disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
& FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
@@ -3029,14 +3070,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
boolean navBarToRightEdge = mLastBottomInset == 0 && mLastRightInset > 0;
int navBarSize = navBarToRightEdge ? mLastRightInset : mLastBottomInset;
- updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor,
- navBarSize, navBarToRightEdge, 0 /* rightInset */,
- animate && !disallowAnimate);
+ updateColorViewInt(mNavigationColorViewState, sysUiVisibility,
+ mWindow.mNavigationBarColor, navBarSize, navBarToRightEdge,
+ 0 /* rightInset */, animate && !disallowAnimate);
boolean statusBarNeedsRightInset = navBarToRightEdge
&& mNavigationColorViewState.present;
int statusBarRightInset = statusBarNeedsRightInset ? mLastRightInset : 0;
- updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor,
+ updateColorViewInt(mStatusColorViewState, sysUiVisibility, mWindow.mStatusBarColor,
mLastTopInset, false /* matchVertical */, statusBarRightInset,
animate && !disallowAnimate);
}
@@ -3053,13 +3094,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
int consumedRight = consumingNavBar ? mLastRightInset : 0;
int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
- if (mContentRoot != null
- && mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
- MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
+ if (mWindow.mContentRoot != null
+ && mWindow.mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
+ MarginLayoutParams lp = (MarginLayoutParams) mWindow.mContentRoot.getLayoutParams();
if (lp.rightMargin != consumedRight || lp.bottomMargin != consumedBottom) {
lp.rightMargin = consumedRight;
lp.bottomMargin = consumedBottom;
- mContentRoot.setLayoutParams(lp);
+ mWindow.mContentRoot.setLayoutParams(lp);
if (insets == null) {
// The insets have changed, but we're not currently in the process
@@ -3097,11 +3138,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
int size, boolean verticalBar, int rightMargin, boolean animate) {
state.present = size > 0 && (sysUiVis & state.systemUiHideFlag) == 0
- && (getAttributes().flags & state.hideWindowFlag) == 0
- && (getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+ && (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
+ && (mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
boolean show = state.present
&& (color & Color.BLACK) != 0
- && (getAttributes().flags & state.translucentFlag) == 0;
+ && (mWindow.getAttributes().flags & state.translucentFlag) == 0;
boolean visibilityChanged = false;
View view = state.view;
@@ -3193,14 +3234,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mPrimaryActionModeView.getLayoutParams();
boolean mlpChanged = false;
if (mPrimaryActionModeView.isShown()) {
- if (mTempRect == null) {
- mTempRect = new Rect();
+ if (mWindow.mTempRect == null) {
+ mWindow.mTempRect = new Rect();
}
- final Rect rect = mTempRect;
+ final Rect rect = mWindow.mTempRect;
// If the parent doesn't consume the insets, manually
// apply the default system window insets.
- mContentParent.computeSystemWindowInsets(insets, rect);
+ mWindow.mContentParent.computeSystemWindowInsets(insets, rect);
final int newMargin = rect.top == 0 ? insets.getSystemWindowInsetTop() : 0;
if (mlp.topMargin != newMargin) {
mlpChanged = true;
@@ -3231,7 +3272,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// mode is overlaid on the app content (e.g. it's
// sitting in a FrameLayout, see
// screen_simple_overlay_action_mode.xml).
- final boolean nonOverlay = (getLocalFeatures()
+ final boolean nonOverlay = (mWindow.getLocalFeatures()
& (1 << FEATURE_ACTION_MODE_OVERLAY)) == 0;
insets = insets.consumeSystemWindowInsets(
false, nonOverlay && showStatusGuard /* top */, false, false);
@@ -3255,14 +3296,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private void updateNavigationGuard(WindowInsets insets) {
// IMEs lay out below the nav bar, but the content view must not (for back compat)
- if (getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
+ if (mWindow.getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
// prevent the content view from including the nav bar height
- if (mContentParent != null) {
- if (mContentParent.getLayoutParams() instanceof MarginLayoutParams) {
+ if (mWindow.mContentParent != null) {
+ if (mWindow.mContentParent.getLayoutParams() instanceof MarginLayoutParams) {
MarginLayoutParams mlp =
- (MarginLayoutParams) mContentParent.getLayoutParams();
+ (MarginLayoutParams) mWindow.mContentParent.getLayoutParams();
mlp.bottomMargin = insets.getSystemWindowInsetBottom();
- mContentParent.setLayoutParams(mlp);
+ mWindow.mContentParent.setLayoutParams(mlp);
}
}
// position the navigation guard view, creating it if necessary
@@ -3344,7 +3385,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mDefaultOpacity = opacity;
if (mFeatureId < 0) {
- setDefaultWindowFormat(opacity);
+ mWindow.setDefaultWindowFormat(opacity);
}
}
@@ -3354,12 +3395,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// If the user is chording a menu shortcut, release the chord since
// this window lost focus
- if (hasFeature(FEATURE_OPTIONS_PANEL) && !hasWindowFocus && mPanelChordingKey != 0) {
- closePanel(FEATURE_OPTIONS_PANEL);
+ if (mWindow.hasFeature(FEATURE_OPTIONS_PANEL) && !hasWindowFocus
+ && mWindow.mPanelChordingKey != 0) {
+ mWindow.closePanel(FEATURE_OPTIONS_PANEL);
}
- final Callback cb = getCallback();
- if (cb != null && !isDestroyed() && mFeatureId < 0) {
+ final Callback cb = mWindow.getCallback();
+ if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
cb.onWindowFocusChanged(hasWindowFocus);
}
@@ -3375,8 +3417,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- final Callback cb = getCallback();
- if (cb != null && !isDestroyed() && mFeatureId < 0) {
+ final Callback cb = mWindow.getCallback();
+ if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
cb.onAttachedToWindow();
}
@@ -3388,7 +3430,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
* menu was open. When the activity is recreated, the menu
* should be shown again.
*/
- openPanelsAfterRestore();
+ mWindow.openPanelsAfterRestore();
}
}
@@ -3396,13 +3438,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- final Callback cb = getCallback();
+ final Callback cb = mWindow.getCallback();
if (cb != null && mFeatureId < 0) {
cb.onDetachedFromWindow();
}
- if (mDecorContentParent != null) {
- mDecorContentParent.dismissPopups();
+ if (mWindow.mDecorContentParent != null) {
+ mWindow.mDecorContentParent.dismissPopups();
}
if (mPrimaryActionModePopup != null) {
@@ -3417,7 +3459,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mFloatingToolbar = null;
}
- PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+ PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
if (st != null && st.menu != null && mFeatureId < 0) {
st.menu.close();
}
@@ -3426,29 +3468,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public void onCloseSystemDialogs(String reason) {
if (mFeatureId >= 0) {
- closeAllPanels();
+ mWindow.closeAllPanels();
}
}
public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() {
- return mFeatureId < 0 ? mTakeSurfaceCallback : null;
+ return mFeatureId < 0 ? mWindow.mTakeSurfaceCallback : null;
}
public InputQueue.Callback willYouTakeTheInputQueue() {
- return mFeatureId < 0 ? mTakeInputQueueCallback : null;
+ return mFeatureId < 0 ? mWindow.mTakeInputQueueCallback : null;
}
public void setSurfaceType(int type) {
- PhoneWindow.this.setType(type);
+ mWindow.setType(type);
}
public void setSurfaceFormat(int format) {
- PhoneWindow.this.setFormat(format);
+ mWindow.setFormat(format);
}
public void setSurfaceKeepScreenOn(boolean keepOn) {
- if (keepOn) PhoneWindow.this.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- else PhoneWindow.this.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ if (keepOn) mWindow.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ else mWindow.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
@Override
@@ -3480,7 +3522,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
endOnGoingFadeAnimation();
cleanupPrimaryActionMode();
if (mPrimaryActionModeView == null) {
- if (isFloating()) {
+ if (mWindow.isFloating()) {
// Use the action bar theme.
final TypedValue outValue = new TypedValue();
final Theme baseTheme = mContext.getTheme();
@@ -3627,7 +3669,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private void setHandledFloatingActionMode(ActionMode mode) {
mFloatingActionMode = mode;
- mFloatingToolbar = new FloatingToolbar(mContext, PhoneWindow.this);
+ mFloatingToolbar = new FloatingToolbar(mContext, mWindow);
((FloatingActionMode) mFloatingActionMode).setFloatingToolbar(mFloatingToolbar);
mFloatingActionMode.invalidate(); // Will show the floating toolbar if necessary.
mFloatingActionModeOriginatingView.getViewTreeObserver()
@@ -3666,6 +3708,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
return windowHasNonClientDecor() && getElevation() > 0;
}
+ void setWindow(PhoneWindow phoneWindow) {
+ mWindow = phoneWindow;
+ Context context = getContext();
+ if (context instanceof DecorContext) {
+ DecorContext decorContex = (DecorContext) context;
+ decorContex.setPhoneWindow(mWindow);
+ }
+ }
+
/**
* Clears out internal references when the action mode is destroyed.
*/
@@ -3754,9 +3805,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
cleanupFloatingActionModeViews();
mFloatingActionMode = null;
}
- if (getCallback() != null && !isDestroyed()) {
+ if (mWindow.getCallback() != null && !mWindow.isDestroyed()) {
try {
- getCallback().onActionModeFinished(mode);
+ mWindow.getCallback().onActionModeFinished(mode);
} catch (AbstractMethodError ame) {
// Older apps might not implement this callback method.
}
@@ -3776,7 +3827,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
protected DecorView generateDecor(int featureId) {
- return new DecorView(getContext(), featureId);
+ // System process doesn't have application context and in that case we need to directly use
+ // the context we have. Otherwise we want the application context, so we don't cling to the
+ // activity.
+ Context applicationContext = getContext().getApplicationContext();
+ Context context;
+ if (applicationContext == null) {
+ context = getContext();
+ } else {
+ context = new DecorContext(applicationContext);
+ if (mTheme != -1) {
+ context.setTheme(mTheme);
+ }
+ }
+ return new DecorView(context, featureId);
}
protected void setFeatureFromAttrs(int featureId, TypedArray attrs,
@@ -4145,13 +4209,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// Dependent on the brightness of the used title we either use the
// dark or the light button frame.
if (nonClientDecorView == null) {
+ Context context = mDecor.getContext();
TypedValue value = new TypedValue();
- getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
+ context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
+ LayoutInflater inflater = mLayoutInflater.from(context);
if (Color.luminance(value.data) < 0.5) {
- nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
+ nonClientDecorView = (NonClientDecorView) inflater.inflate(
R.layout.non_client_decor_dark, null);
} else {
- nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
+ nonClientDecorView = (NonClientDecorView) inflater.inflate(
R.layout.non_client_decor_light, null);
}
}
@@ -4173,11 +4239,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
+ mDecor.setWindow(this);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
+ } else {
+ mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
@@ -5352,4 +5421,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
public boolean hasNonClientDecorView() {
return mNonClientDecorView != null;
}
+
+ @Override
+ public void setTheme(int resid) {
+ mTheme = resid;
+ if (mDecor != null) {
+ Context context = mDecor.getContext();
+ if (context instanceof DecorContext) {
+ context.setTheme(resid);
+ }
+ }
+ }
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index ab3ec985d688..11ef18b4d5c0 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -74,7 +74,9 @@ oneway interface IStatusBar
/**
* Notifies the status bar that a camera launch gesture has been detected.
+ *
+ * @param source the identifier for the gesture, see {@link StatusBarManager}
*/
- void onCameraLaunchGestureDetected();
+ void onCameraLaunchGestureDetected(int source);
}
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index aa7b34bb9999..293e2ade7229 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -20,14 +20,16 @@ import android.view.ViewTreeObserver;
import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnKeyListener;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.widget.AdapterView;
import android.widget.DropDownListView;
+import android.widget.FrameLayout;
import android.widget.MenuItemHoverListener;
+import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.MenuPopupWindow;
import android.widget.MenuPopupWindow.MenuDropDownListView;
import android.widget.PopupWindow;
import android.widget.PopupWindow.OnDismissListener;
+import android.widget.TextView;
import com.android.internal.util.Preconditions;
@@ -36,8 +38,8 @@ import com.android.internal.util.Preconditions;
* side.
* @hide
*/
-final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemClickListener,
- MenuPresenter, OnKeyListener, PopupWindow.OnDismissListener {
+final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKeyListener,
+ PopupWindow.OnDismissListener {
@Retention(RetentionPolicy.SOURCE)
@IntDef({HORIZ_POSITION_LEFT, HORIZ_POSITION_RIGHT})
public @interface HorizPosition {}
@@ -96,7 +98,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
int menuIndex = -1;
for (int i = 0; i < mListViews.size(); i++) {
final MenuDropDownListView view = (MenuDropDownListView) mListViews.get(i);
- final MenuAdapter adapter = (MenuAdapter) view.getAdapter();
+ final MenuAdapter adapter = toMenuAdapter(view.getAdapter());
if (adapter.getAdapterMenu() == menu) {
menuIndex = i;
@@ -129,7 +131,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
int nextIndex = mListViews.indexOf(view) + 1;
if (nextIndex < mListViews.size()) {
MenuAdapter nextSubMenuAdapter =
- (MenuAdapter) mListViews.get(nextIndex).getAdapter();
+ toMenuAdapter(mListViews.get(nextIndex).getAdapter());
// Disable exit animation, to prevent overlapping fading out
// submenus.
mPopupWindows.get(nextIndex).setExitTransition(null);
@@ -151,7 +153,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
final MenuDropDownListView nextView =
(MenuDropDownListView) mListViews.get(menuIndex + 1);
- final MenuAdapter nextAdapter = (MenuAdapter) nextView.getAdapter();
+ final MenuAdapter nextAdapter = toMenuAdapter(nextView.getAdapter());
mSubMenuHoverHandler.removeCallbacksAndMessages(null);
mSubMenuHoverHandler.postDelayed(new Runnable() {
@@ -184,7 +186,10 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
private int mLastPosition;
private List<Integer> mPositions;
private List<int[]> mOffsets;
+ private int mInitXOffset;
+ private int mInitYOffset;
private boolean mForceShowIcon;
+ private boolean mShowTitle;
private Callback mPresenterCallback;
private ViewTreeObserver mTreeObserver;
private PopupWindow.OnDismissListener mOnDismissListener;
@@ -248,7 +253,25 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
for (int i = 0; i < mPopupWindows.size(); i++) {
MenuPopupWindow popupWindow = mPopupWindows.get(i);
popupWindow.show();
- mListViews.add((DropDownListView) popupWindow.getListView());
+ DropDownListView listView = (DropDownListView) popupWindow.getListView();
+ mListViews.add(listView);
+
+ MenuBuilder menu = toMenuAdapter(listView.getAdapter()).getAdapterMenu();
+ if (i == 0 && mShowTitle && menu.getHeaderTitle() != null) {
+ FrameLayout titleItemView =
+ (FrameLayout) LayoutInflater.from(mContext).inflate(
+ com.android.internal.R.layout.popup_menu_header_item_layout,
+ listView,
+ false);
+ TextView titleView = (TextView) titleItemView.findViewById(
+ com.android.internal.R.id.title);
+ titleView.setText(menu.getHeaderTitle());
+ titleItemView.setEnabled(false);
+ listView.addHeaderView(titleItemView, null, false);
+
+ // Update to show the title.
+ popupWindow.show();
+ }
}
mShownAnchorView = mAnchorView;
@@ -275,12 +298,6 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
}
@Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- MenuAdapter adapter = (MenuAdapter) parent.getAdapter();
- adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
- }
-
- @Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
dismiss();
@@ -381,6 +398,9 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
y = lastOffset[1] + lastListView.getSelectedView().getTop() -
lastListView.getChildAt(0).getTop();
+ } else {
+ x = mInitXOffset;
+ y = mInitYOffset;
}
popupWindow.setWidth(menuWidth);
@@ -393,7 +413,8 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
// we deliberately do not yet show the popupWindow, as #show() will do that later.
if (isShowing()) {
popupWindow.show();
- mListViews.add((DropDownListView) popupWindow.getListView());
+ DropDownListView listView = (DropDownListView) popupWindow.getListView();
+ mListViews.add(listView);
}
int[] offsets = {x, y};
@@ -425,8 +446,9 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
if (dismissedIndex != -1) {
for (int i = dismissedIndex; i < mListViews.size(); i++) {
ListView view = mListViews.get(i);
- MenuAdapter adapter = (MenuAdapter) view.getAdapter();
- adapter.mAdapterMenu.close();
+ ListAdapter adapter = view.getAdapter();
+ MenuAdapter menuAdapter = toMenuAdapter(adapter);
+ menuAdapter.mAdapterMenu.close();
}
}
}
@@ -434,7 +456,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
@Override
public void updateMenuView(boolean cleared) {
for (ListView view : mListViews) {
- ((MenuAdapter) view.getAdapter()).notifyDataSetChanged();
+ toMenuAdapter(view.getAdapter()).notifyDataSetChanged();
}
}
@@ -447,7 +469,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
// Don't allow double-opening of the same submenu.
for (ListView view : mListViews) {
- if (((MenuAdapter) view.getAdapter()).mAdapterMenu.equals(subMenu)) {
+ if (toMenuAdapter(view.getAdapter()).mAdapterMenu.equals(subMenu)) {
// Just re-focus that one.
view.requestFocus();
return true;
@@ -471,7 +493,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
for (int i = 0; i < mListViews.size(); i++) {
ListView view = mListViews.get(i);
- MenuAdapter adapter = (MenuAdapter) view.getAdapter();
+ MenuAdapter adapter = toMenuAdapter(view.getAdapter());
if (menuIndex == -1 && menu == adapter.mAdapterMenu) {
menuIndex = i;
@@ -557,4 +579,18 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
return mListViews.size() > 0 ? mListViews.get(mListViews.size() - 1) : null;
}
+ @Override
+ public void setHorizontalOffset(int x) {
+ mInitXOffset = x;
+ }
+
+ @Override
+ public void setVerticalOffset(int y) {
+ mInitYOffset = y;
+ }
+
+ @Override
+ public void setShowTitle(boolean showTitle) {
+ mShowTitle = showTitle;
+ }
} \ No newline at end of file
diff --git a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
index bf44d51b6dd9..aaa1bf16bf80 100644
--- a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
@@ -17,6 +17,7 @@
package com.android.internal.view.menu;
import android.content.Context;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.IBinder;
import android.util.EventLog;
@@ -93,4 +94,29 @@ public class ContextMenuBuilder extends MenuBuilder implements ContextMenu {
return null;
}
+ public MenuPopupHelper showPopup(Context context, View originalView, float x, float y) {
+ if (originalView != null) {
+ // Let relevant views and their populate context listeners populate
+ // the context menu
+ originalView.createContextMenu(this);
+ }
+
+ if (getVisibleItems().size() > 0) {
+ EventLog.writeEvent(50001, 1);
+
+ int location[] = new int[2];
+ originalView.getLocationOnScreen(location);
+
+ final MenuPopupHelper helper = new MenuPopupHelper(
+ context,
+ this,
+ originalView,
+ false /* overflowOnly */,
+ com.android.internal.R.attr.contextPopupMenuStyle);
+ helper.show(Math.round(x), Math.round(y));
+ return helper;
+ }
+
+ return null;
+ }
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java
index b43e8adbc8ac..98f5d9061e14 100644
--- a/core/java/com/android/internal/view/menu/MenuPopup.java
+++ b/core/java/com/android/internal/view/menu/MenuPopup.java
@@ -17,10 +17,13 @@
package com.android.internal.view.menu;
import android.content.Context;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
+import android.widget.AdapterView;
import android.widget.FrameLayout;
+import android.widget.HeaderViewListAdapter;
import android.widget.ListAdapter;
import android.widget.PopupWindow;
@@ -30,7 +33,8 @@ import android.widget.PopupWindow;
*
* @hide
*/
-public abstract class MenuPopup implements ShowableListMenu, MenuPresenter {
+public abstract class MenuPopup implements ShowableListMenu, MenuPresenter,
+ AdapterView.OnItemClickListener {
public abstract void setForceShowIcon(boolean forceShow);
@@ -49,6 +53,18 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter {
public abstract void setAnchorView(View anchor);
+ public abstract void setHorizontalOffset(int x);
+
+ public abstract void setVerticalOffset(int y);
+
+ /**
+ * Set whether a title entry should be shown in the popup menu (if a title exists for the
+ * menu).
+ *
+ * @param showTitle
+ */
+ public abstract void setShowTitle(boolean showTitle);
+
/**
* Set a listener to receive a callback when the popup is dismissed.
*
@@ -81,6 +97,16 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter {
return 0;
}
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ ListAdapter outerAdapter = (ListAdapter) parent.getAdapter();
+ MenuAdapter wrappedAdapter = toMenuAdapter(outerAdapter);
+
+ // Use the position from the outer adapter so that if a header view was added, we don't get
+ // an off-by-1 error in position.
+ wrappedAdapter.mAdapterMenu.performItemAction((MenuItem) outerAdapter.getItem(position), 0);
+ }
+
/**
* Measures the width of the given menu view.
*
@@ -121,4 +147,19 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter {
return maxWidth;
}
-} \ No newline at end of file
+
+ /**
+ * Converts the given ListAdapter originating from a menu, to a MenuAdapter, accounting for
+ * the possibility of the parameter adapter actually wrapping the MenuAdapter. (That could
+ * happen if a header view was added on the menu.)
+ *
+ * @param adapter
+ * @return
+ */
+ protected static MenuAdapter toMenuAdapter(ListAdapter adapter) {
+ if (adapter instanceof HeaderViewListAdapter) {
+ return (MenuAdapter) ((HeaderViewListAdapter) adapter).getWrappedAdapter();
+ }
+ return (MenuAdapter) adapter;
+ }
+}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index ea7998339f3b..e674eccd889d 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -39,7 +39,11 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener {
private MenuPopup mPopup;
private int mDropDownGravity = Gravity.NO_GRAVITY;
+ private boolean mForceShowIcon;
+ private boolean mShowTitle;
private Callback mPresenterCallback;
+ private int mInitXOffset;
+ private int mInitYOffset;
public MenuPopupHelper(Context context, MenuBuilder menu) {
this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0);
@@ -81,6 +85,7 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener {
}
public void setForceShowIcon(boolean forceShow) {
+ mForceShowIcon = forceShow;
mPopup.setForceShowIcon(forceShow);
}
@@ -99,6 +104,12 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener {
}
}
+ public void show(int x, int y) {
+ if (!tryShow(x, y)) {
+ throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
+ }
+ }
+
public ShowableListMenu getPopup() {
return mPopup;
}
@@ -118,10 +129,40 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener {
return false;
}
+ mInitXOffset = 0;
+ mInitYOffset = 0;
+ mShowTitle = false;
+
+ showPopup();
+ return true;
+ }
+
+ public boolean tryShow(int x, int y) {
+ if (isShowing()) {
+ return true;
+ }
+
+ if (mAnchorView == null) {
+ return false;
+ }
+
+ mInitXOffset = x;
+ mInitYOffset = y;
+ mShowTitle = true;
+
+ showPopup();
+ return true;
+ }
+
+ private void showPopup() {
mPopup = createMenuPopup();
mPopup.setAnchorView(mAnchorView);
- mPopup.setGravity(mDropDownGravity);
mPopup.setCallback(mPresenterCallback);
+ mPopup.setForceShowIcon(mForceShowIcon);
+ mPopup.setGravity(mDropDownGravity);
+ mPopup.setHorizontalOffset(mInitXOffset);
+ mPopup.setShowTitle(mShowTitle);
+ mPopup.setVerticalOffset(mInitYOffset);
// In order for subclasses of MenuPopupHelper to satisfy the OnDismissedListener interface,
// we must set the listener to this outer Helper rather than to the inner MenuPopup.
@@ -131,7 +172,6 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener {
mPopup.addMenu(mMenu);
mPopup.show();
- return true;
}
public void dismiss() {
@@ -149,7 +189,6 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener {
return mPopup != null && mPopup.isShowing();
}
-
public void setCallback(MenuPresenter.Callback cb) {
mPresenterCallback = cb;
mPopup.setCallback(cb);
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index 8877f3d96a39..caee0d2d9a74 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -6,17 +6,17 @@ import android.os.Parcelable;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnKeyListener;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.ViewTreeObserver;
-import android.widget.AdapterView;
+import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.MenuPopupWindow;
import android.widget.PopupWindow;
+import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.PopupWindow.OnDismissListener;
@@ -92,6 +92,10 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On
private int mDropDownGravity = Gravity.NO_GRAVITY;
+ private int mXOffset;
+ private int mYOffset;
+ private boolean mShowTitle;
+
public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr,
int popupStyleRes, boolean overflowOnly) {
mContext = Preconditions.checkNotNull(context);
@@ -158,8 +162,28 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On
mPopup.setContentWidth(mContentWidth);
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+ mPopup.setHorizontalOffset(mXOffset);
+ mPopup.setVerticalOffset(mYOffset);
mPopup.show();
- mPopup.getListView().setOnKeyListener(this);
+
+ ListView listView = mPopup.getListView();
+ listView.setOnKeyListener(this);
+
+ if (mShowTitle && mMenu.getHeaderTitle() != null) {
+ FrameLayout titleItemView =
+ (FrameLayout) LayoutInflater.from(mContext).inflate(
+ com.android.internal.R.layout.popup_menu_header_item_layout,
+ listView,
+ false);
+ TextView titleView = (TextView) titleItemView.findViewById(
+ com.android.internal.R.id.title);
+ titleView.setText(mMenu.getHeaderTitle());
+ titleItemView.setEnabled(false);
+ listView.addHeaderView(titleItemView, null, false);
+
+ // Update to show the title.
+ mPopup.show();
+ }
return true;
}
@@ -178,12 +202,6 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On
}
@Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- MenuAdapter adapter = mAdapter;
- adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
- }
-
- @Override
public void addMenu(MenuBuilder menu) {
// No-op: standard implementation has only one menu which is set in the constructor.
}
@@ -288,4 +306,20 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On
public ListView getListView() {
return mPopup.getListView();
}
-} \ No newline at end of file
+
+
+ @Override
+ public void setHorizontalOffset(int x) {
+ mXOffset = x;
+ }
+
+ @Override
+ public void setVerticalOffset(int y) {
+ mYOffset = y;
+ }
+
+ @Override
+ public void setShowTitle(boolean showTitle) {
+ mShowTitle = showTitle;
+ }
+}
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 2a25db6b64c4..7bab446d4705 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -73,6 +73,8 @@ public final class FloatingToolbar {
// This class is responsible for the public API of the floating toolbar.
// It delegates rendering operations to the FloatingToolbarPopup.
+ public static final String FLOATING_TOOLBAR_TAG = "floating_toolbar";
+
private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER =
new MenuItem.OnMenuItemClickListener() {
@Override
@@ -1460,8 +1462,10 @@ public final class FloatingToolbar {
}
private static ViewGroup createContentContainer(Context context) {
- return (ViewGroup) LayoutInflater.from(context)
+ ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context)
.inflate(R.layout.floating_popup_container, null);
+ contentContainer.setTag(FLOATING_TOOLBAR_TAG);
+ return contentContainer;
}
private static PopupWindow createPopupWindow(View content) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f7e9add58f21..60ef4a47b230 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1078,7 +1078,7 @@ public class LockPatternUtils {
long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
final long now = SystemClock.elapsedRealtime();
- if (deadline < now) {
+ if (deadline < now && deadline != 0) {
// timeout expired
setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId);
setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index 6ab306cec730..6960a3b29fad 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -17,15 +17,23 @@
package com.android.internal.widget;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.Rect;
+import android.os.Looper;
import android.os.RemoteException;
import android.util.AttributeSet;
+import android.view.Choreographer;
+import android.view.DisplayListCanvas;
import android.view.MotionEvent;
+import android.view.RenderNode;
+import android.view.ThreadedRenderer;
import android.view.View;
+import android.view.ViewRootImpl;
import android.widget.LinearLayout;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.Window;
+import android.view.WindowCallbacks;
import android.util.Log;
import android.util.TypedValue;
@@ -57,7 +65,8 @@ import com.android.internal.policy.PhoneWindow;
* </ul>
* This will be mitigated once b/22527834 will be addressed.
*/
-public class NonClientDecorView extends LinearLayout implements View.OnClickListener {
+public class NonClientDecorView extends LinearLayout
+ implements View.OnClickListener, View.OnTouchListener, WindowCallbacks {
private final static String TAG = "NonClientDecorView";
// The height of a window which has focus in DIP.
private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20;
@@ -66,6 +75,8 @@ public class NonClientDecorView extends LinearLayout implements View.OnClickList
private PhoneWindow mOwner = null;
private boolean mWindowHasShadow = false;
private boolean mShowDecor = false;
+ // True when this object is listening for window size changes.
+ private boolean mAttachedCallbacksToRootViewImpl = false;
// True if the window is being dragged.
private boolean mDragging = false;
@@ -84,6 +95,9 @@ public class NonClientDecorView extends LinearLayout implements View.OnClickList
// to max until the first layout command has been executed.
private boolean mAllowUpdateElevation = false;
+ // The resize frame renderer.
+ private ResizeFrameThread mFrameRendererThread = null;
+
public NonClientDecorView(Context context) {
super(context);
}
@@ -107,12 +121,24 @@ public class NonClientDecorView extends LinearLayout implements View.OnClickList
// By changing the outline provider to BOUNDS, the window can remove its
// background without removing the shadow.
mOwner.getDecorView().setOutlineProvider(ViewOutlineProvider.BOUNDS);
+
+ if (!mAttachedCallbacksToRootViewImpl) {
+ // If there is no window callback installed there was no window set before. Set it now.
+ // Note that our ViewRootImpl object will not change.
+ getViewRootImpl().addWindowCallbacks(this);
+ mAttachedCallbacksToRootViewImpl = true;
+ } else if (mFrameRendererThread != null) {
+ // We are resizing and this call happened due to a configuration change. Tell the
+ // renderer about it.
+ mFrameRendererThread.onConfigurationChange();
+ }
+
findViewById(R.id.maximize_window).setOnClickListener(this);
findViewById(R.id.close_window).setOnClickListener(this);
}
@Override
- public boolean onTouchEvent(MotionEvent e) {
+ public boolean onTouch(View v, MotionEvent e) {
// Note: There are no mixed events. When a new device gets used (e.g. 1. Mouse, 2. touch)
// the old input device events get cancelled first. So no need to remember the kind of
// input device we are listening to.
@@ -224,6 +250,7 @@ public class NonClientDecorView extends LinearLayout implements View.OnClickList
boolean invisible = isFillingScreen() || !mShowDecor;
View caption = getChildAt(0);
caption.setVisibility(invisible ? GONE : VISIBLE);
+ caption.setOnTouchListener(this);
mVisible = !invisible;
}
@@ -249,7 +276,9 @@ public class NonClientDecorView extends LinearLayout implements View.OnClickList
**/
private void updateElevation() {
float elevation = 0;
- if (mWindowHasShadow) {
+ // Do not use a shadow when we are in resizing mode (mRenderer not null) since the shadow
+ // is bound to the content size and not the target size.
+ if (mWindowHasShadow && mFrameRendererThread == null) {
boolean fill = isFillingScreen();
elevation = fill ? 0 :
(mWindowHasFocus ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP :
@@ -291,4 +320,270 @@ public class NonClientDecorView extends LinearLayout implements View.OnClickList
}
}
}
+
+ @Override
+ public void onWindowDragResizeStart(Rect initialBounds) {
+ if (mOwner.isDestroyed()) {
+ // If the owner's window is gone, we should not be able to come here anymore.
+ releaseResources();
+ return;
+ }
+ if (mFrameRendererThread != null) {
+ return;
+ }
+ final ThreadedRenderer renderer =
+ (ThreadedRenderer) mOwner.getDecorView().getHardwareRenderer();
+ if (renderer != null) {
+ mFrameRendererThread = new ResizeFrameThread(renderer, initialBounds);
+ // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
+ // If we want to get the shadow shown while resizing, we would need to elevate a new
+ // element which owns the caption and has the elevation.
+ updateElevation();
+ }
+ }
+
+ @Override
+ public void onWindowDragResizeEnd() {
+ releaseThreadedRenderer();
+ }
+
+ @Override
+ public void onWindowSizeIsChanging(Rect newBounds) {
+ if (mFrameRendererThread != null) {
+ mFrameRendererThread.setTargetRect(newBounds);
+ }
+ }
+
+ /**
+ * Release the renderer thread which is usually done when the user stops resizing.
+ */
+ private void releaseThreadedRenderer() {
+ if (mFrameRendererThread != null) {
+ mFrameRendererThread.releaseRenderer();
+ mFrameRendererThread = null;
+ // Bring the shadow back.
+ updateElevation();
+ }
+ }
+
+ /**
+ * Called when the parent window is destroyed to release all resources. Note that this will also
+ * destroy the renderer thread.
+ */
+ private void releaseResources() {
+ releaseThreadedRenderer();
+ if (mAttachedCallbacksToRootViewImpl) {
+ ViewRootImpl.removeWindowCallbacks(this);
+ mAttachedCallbacksToRootViewImpl = false;
+ }
+ }
+
+ /**
+ * The thread which draws the chrome while we are resizing.
+ * It starts with the creation and it ends once someone calls destroy().
+ * Any size changes can be passed by a call to setTargetRect will passed to the thread and
+ * executed via the Choreographer.
+ */
+ private class ResizeFrameThread extends Thread implements Choreographer.FrameCallback {
+ // This is containing the last requested size by a resize command. Note that this size might
+ // or might not have been applied to the output already.
+ private final Rect mTargetRect = new Rect();
+
+ // The render nodes for the multi threaded renderer.
+ private ThreadedRenderer mRenderer;
+ private RenderNode mFrameNode;
+ private RenderNode mBackdropNode;
+
+ private final Rect mOldTargetRect = new Rect();
+ private final Rect mNewTargetRect = new Rect();
+ private Choreographer mChoreographer;
+
+ // Cached size values from the last render for the case that the view hierarchy is gone
+ // during a configuration change.
+ private int mLastContentWidth;
+ private int mLastContentHeight;
+ private int mLastCaptionHeight;
+ private int mLastXOffset;
+ private int mLastYOffset;
+
+ ResizeFrameThread(ThreadedRenderer renderer, Rect initialBounds) {
+ mRenderer = renderer;
+
+ // Create the render nodes for our frame and backdrop which can be resized independently
+ // from the content.
+ mFrameNode = RenderNode.create("FrameNode", null);
+ mBackdropNode = RenderNode.create("BackdropNode", null);
+
+ mRenderer.addRenderNode(mFrameNode, false);
+ mRenderer.addRenderNode(mBackdropNode, true);
+
+ // Set the initial bounds and draw once so that we do not get a broken frame.
+ mTargetRect.set(initialBounds);
+ changeWindowSize(initialBounds);
+
+ // Kick off our draw thread.
+ start();
+ }
+
+ /**
+ * Call this function asynchronously when the window size has been changed. The change will
+ * be picked up once per frame and the frame will be re-rendered accordingly.
+ * @param newTargetBounds The new target bounds.
+ */
+ public void setTargetRect(Rect newTargetBounds) {
+ synchronized (this) {
+ mTargetRect.set(newTargetBounds);
+ // Notify of a bounds change.
+ pingRenderLocked();
+ }
+ }
+
+ /**
+ * The window got replaced due to a configuration change.
+ */
+ public void onConfigurationChange() {
+ if (mRenderer != null) {
+ // Enforce a window redraw.
+ mOldTargetRect.set(0, 0, 0, 0);
+ pingRenderLocked();
+ }
+ }
+
+ /**
+ * All resources of the renderer will be released. This function can be called from the
+ * the UI thread as well as the renderer thread.
+ */
+ public void releaseRenderer() {
+ synchronized (this) {
+ if (mRenderer != null) {
+ // Invalidate the current content bounds.
+ mRenderer.setContentDrawBounds(0, 0, 0, 0);
+
+ // Remove the render nodes again (see comment above - better to do that only once).
+ mRenderer.removeRenderNode(mFrameNode);
+ mRenderer.removeRenderNode(mBackdropNode);
+
+ mRenderer = null;
+
+ // Exit the renderer loop.
+ pingRenderLocked();
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ Looper.prepare();
+ mChoreographer = Choreographer.getInstance();
+ Looper.loop();
+ } finally {
+ releaseRenderer();
+ }
+ synchronized (this) {
+ // Make sure no more messages are being sent.
+ mChoreographer = null;
+ }
+ }
+
+ /**
+ * The implementation of the FrameCallback.
+ * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
+ * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000}
+ */
+ @Override
+ public void doFrame(long frameTimeNanos) {
+ if (mRenderer == null) {
+ // Tell the looper to stop. We are done.
+ Looper.myLooper().quit();
+ return;
+ }
+ // Prevent someone from changing this while we are copying.
+ synchronized (this) {
+ mNewTargetRect.set(mTargetRect);
+ }
+ if (!mNewTargetRect.equals(mOldTargetRect)) {
+ mOldTargetRect.set(mNewTargetRect);
+ changeWindowSize(mNewTargetRect);
+ }
+ }
+
+ /**
+ * Resizing the frame to fit the new window size.
+ * @param newBounds The window bounds which needs to be drawn.
+ */
+ private void changeWindowSize(Rect newBounds) {
+ long startTime = System.currentTimeMillis();
+
+ // While a configuration change is taking place the view hierarchy might become
+ // inaccessible. For that case we remember the previous metrics to avoid flashes.
+ View caption = getChildAt(0);
+ View content = getChildAt(1);
+ if (content != null && caption != null) {
+ mLastContentWidth = content.getWidth();
+ mLastContentHeight = content.getHeight();
+ mLastCaptionHeight = caption.getHeight();
+
+ // Get the draw position within our surface.
+ int[] surfaceOrigin = new int[2];
+ surfaceOrigin[0] = 0;
+ surfaceOrigin[1] = 0;
+
+ // Get the shadow offsets.
+ getLocationInSurface(surfaceOrigin);
+ mLastXOffset = surfaceOrigin[0];
+ mLastYOffset = surfaceOrigin[1];
+ }
+
+ // Since the surface is spanning the entire screen, we have to add the start offset of
+ // the bounds to get to the surface location.
+ final int left = mLastXOffset + newBounds.left;
+ final int top = mLastYOffset + newBounds.top;
+ final int width = newBounds.width();
+ final int height = newBounds.height();
+
+ // Produce the draw calls.
+ // TODO(skuhne): Create a separate caption view which draws this. If the shadow should
+ // be resized while the window resizes, this hierarchy needs to have the elevation.
+ // That said - it is probably no good idea to draw the shadow every time since it costs
+ // a considerable time which we should rather spend for resizing the content and it does
+ // barely show while the entire screen is moving.
+ mFrameNode.setLeftTopRightBottom(left, top, left + width, top + mLastCaptionHeight);
+ DisplayListCanvas canvas = mFrameNode.start(width, height);
+ canvas.drawColor(Color.BLACK);
+ mFrameNode.end(canvas);
+
+ mBackdropNode.setLeftTopRightBottom(left, top + mLastCaptionHeight, left + width,
+ top + height);
+
+ // The backdrop: clear everything with the background. Clipping is done elsewhere.
+ canvas = mBackdropNode.start(width, height - mLastCaptionHeight);
+ // TODO(skuhne): mOwner.getDecorView().mBackgroundFallback.draw(..) - or similar.
+ // Note: This might not work (calculator for example uses a transparent background).
+ canvas.drawColor(0xff808080);
+ mBackdropNode.end(canvas);
+
+ // The current content buffer is drawn here.
+ mRenderer.setContentDrawBounds(
+ mLastXOffset,
+ mLastYOffset + mLastCaptionHeight,
+ mLastXOffset + mLastContentWidth,
+ mLastYOffset + mLastCaptionHeight + mLastContentHeight);
+
+ // We need to render both rendered nodes explicitly.
+ mRenderer.drawRenderNode(mFrameNode);
+ mRenderer.drawRenderNode(mBackdropNode);
+ }
+
+ /**
+ * Sends a message to the renderer to wake up and perform the next action which can be
+ * either the next rendering or the self destruction if mRenderer is null.
+ * Note: This call must be synchronized.
+ */
+ private void pingRenderLocked() {
+ if (mChoreographer != null) {
+ mChoreographer.postFrameCallback(this);
+ }
+ }
+ }
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 75da27e25abb..20d00b03092a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -1,6 +1,5 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
@@ -259,6 +258,9 @@ LOCAL_SHARED_LIBRARIES += \
# <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
LOCAL_C_INCLUDES += bionic/libc/private
+# AndroidRuntime.h depends on nativehelper/jni.h
+LOCAL_EXPORT_C_INCLUDE_DIRS := libnativehelper/include
+
LOCAL_MODULE:= libandroid_runtime
# -Wno-unknown-pragmas: necessary for Clang as the GL bindings need to turn
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 520dc4fdb496..314e4b6f984e 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -44,6 +44,7 @@
#include "TypefaceImpl.h"
#include <vector>
+#include <memory>
// temporary for debugging
#include <Caches.h>
@@ -65,10 +66,6 @@ static JMetricsID gFontMetrics_fieldID;
static jclass gFontMetricsInt_class;
static JMetricsID gFontMetricsInt_fieldID;
-static jclass gPaint_class;
-static jfieldID gPaint_nativeInstanceID;
-static jfieldID gPaint_nativeTypefaceID;
-
static void defaultSettingsForAndroid(Paint* paint) {
// GlyphID encoding is required because we are using Harfbuzz shaping
paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
@@ -81,37 +78,17 @@ struct LocaleCacheEntry {
static thread_local LocaleCacheEntry sSingleEntryLocaleCache;
-class PaintGlue {
-public:
+namespace PaintGlue {
enum MoveOpt {
AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
};
- static Paint* getNativePaint(JNIEnv* env, jobject paint) {
- SkASSERT(env);
- SkASSERT(paint);
- SkASSERT(env->IsInstanceOf(paint, gPaint_class));
- jlong paintHandle = env->GetLongField(paint, gPaint_nativeInstanceID);
- android::Paint* p = reinterpret_cast<android::Paint*>(paintHandle);
- SkASSERT(p);
- return p;
- }
-
- static TypefaceImpl* getNativeTypeface(JNIEnv* env, jobject paint) {
- SkASSERT(env);
- SkASSERT(paint);
- SkASSERT(env->IsInstanceOf(paint, gPaint_class));
- jlong typefaceHandle = env->GetLongField(paint, gPaint_nativeTypefaceID);
- android::TypefaceImpl* p = reinterpret_cast<android::TypefaceImpl*>(typefaceHandle);
- return p;
- }
-
static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
Paint* obj = reinterpret_cast<Paint*>(objHandle);
delete obj;
}
- static jlong init(JNIEnv* env, jobject clazz) {
+ static jlong init(JNIEnv* env, jobject) {
static_assert(1 << 0 == SkPaint::kAntiAlias_Flag, "paint_flags_mismatch");
static_assert(1 << 2 == SkPaint::kDither_Flag, "paint_flags_mismatch");
static_assert(1 << 3 == SkPaint::kUnderlineText_Flag, "paint_flags_mismatch");
@@ -148,9 +125,8 @@ public:
// Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
static const uint32_t sFilterBitmapFlag = 0x02;
- static jint getFlags(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
- Paint* nativePaint = getNativePaint(env, paint);
+ static jint getFlags(JNIEnv* env, jobject, jlong paintHandle) {
+ Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
uint32_t result = nativePaint->getFlags();
result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
@@ -159,9 +135,8 @@ public:
return static_cast<jint>(result);
}
- static void setFlags(JNIEnv* env, jobject paint, jint flags) {
- NPE_CHECK_RETURN_VOID(env, paint);
- Paint* nativePaint = getNativePaint(env, paint);
+ static void setFlags(JNIEnv* env, jobject, jlong paintHandle, jint flags) {
+ Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
// Instead of modifying 0x02, change the filter level.
nativePaint->setFilterQuality(flags & sFilterBitmapFlag
? kLow_SkFilterQuality
@@ -174,57 +149,47 @@ public:
nativePaint->setFlags(flags);
}
- static jint getHinting(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
- return getNativePaint(env, paint)->getHinting()
+ static jint getHinting(JNIEnv* env, jobject, jlong paintHandle) {
+ return reinterpret_cast<Paint*>(paintHandle)->getHinting()
== Paint::kNo_Hinting ? 0 : 1;
}
- static void setHinting(JNIEnv* env, jobject paint, jint mode) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setHinting(
+ static void setHinting(JNIEnv* env, jobject, jlong paintHandle, jint mode) {
+ reinterpret_cast<Paint*>(paintHandle)->setHinting(
mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
}
- static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setAntiAlias(aa);
+ static void setAntiAlias(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
+ reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
}
- static void setLinearText(JNIEnv* env, jobject paint, jboolean linearText) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setLinearText(linearText);
+ static void setLinearText(JNIEnv* env, jobject, jlong paintHandle, jboolean linearText) {
+ reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
}
- static void setSubpixelText(JNIEnv* env, jobject paint, jboolean subpixelText) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setSubpixelText(subpixelText);
+ static void setSubpixelText(JNIEnv* env, jobject, jlong paintHandle, jboolean subpixelText) {
+ reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
}
- static void setUnderlineText(JNIEnv* env, jobject paint, jboolean underlineText) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setUnderlineText(underlineText);
+ static void setUnderlineText(JNIEnv* env, jobject, jlong paintHandle, jboolean underlineText) {
+ reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText);
}
- static void setStrikeThruText(JNIEnv* env, jobject paint, jboolean strikeThruText) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setStrikeThruText(strikeThruText);
+ static void setStrikeThruText(JNIEnv* env, jobject, jlong paintHandle, jboolean strikeThruText) {
+ reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText);
}
- static void setFakeBoldText(JNIEnv* env, jobject paint, jboolean fakeBoldText) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setFakeBoldText(fakeBoldText);
+ static void setFakeBoldText(JNIEnv* env, jobject, jlong paintHandle, jboolean fakeBoldText) {
+ reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
}
- static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setFilterQuality(
+ static void setFilterBitmap(JNIEnv* env, jobject, jlong paintHandle, jboolean filterBitmap) {
+ reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
}
- static void setDither(JNIEnv* env, jobject paint, jboolean dither) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setDither(dither);
+ static void setDither(JNIEnv* env, jobject, jlong paintHandle, jboolean dither) {
+ reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
}
static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) {
@@ -238,48 +203,40 @@ public:
obj->setStyle(style);
}
- static jint getColor(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
+ static jint getColor(JNIEnv* env, jobject, jlong paintHandle) {
int color;
- color = getNativePaint(env, paint)->getColor();
+ color = reinterpret_cast<Paint*>(paintHandle)->getColor();
return static_cast<jint>(color);
}
- static jint getAlpha(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
+ static jint getAlpha(JNIEnv* env, jobject, jlong paintHandle) {
int alpha;
- alpha = getNativePaint(env, paint)->getAlpha();
+ alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
return static_cast<jint>(alpha);
}
- static void setColor(JNIEnv* env, jobject paint, jint color) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setColor(color);
+ static void setColor(JNIEnv* env, jobject, jlong paintHandle, jint color) {
+ reinterpret_cast<Paint*>(paintHandle)->setColor(color);
}
- static void setAlpha(JNIEnv* env, jobject paint, jint a) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setAlpha(a);
+ static void setAlpha(JNIEnv* env, jobject, jlong paintHandle, jint a) {
+ reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
}
- static jfloat getStrokeWidth(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
- return SkScalarToFloat(getNativePaint(env, paint)->getStrokeWidth());
+ static jfloat getStrokeWidth(JNIEnv* env, jobject, jlong paintHandle) {
+ return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
}
- static void setStrokeWidth(JNIEnv* env, jobject paint, jfloat width) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setStrokeWidth(width);
+ static void setStrokeWidth(JNIEnv* env, jobject, jlong paintHandle, jfloat width) {
+ reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
}
- static jfloat getStrokeMiter(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
- return SkScalarToFloat(getNativePaint(env, paint)->getStrokeMiter());
+ static jfloat getStrokeMiter(JNIEnv* env, jobject, jlong paintHandle) {
+ return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
}
- static void setStrokeMiter(JNIEnv* env, jobject paint, jfloat miter) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setStrokeMiter(miter);
+ static void setStrokeMiter(JNIEnv* env, jobject, jlong paintHandle, jfloat miter) {
+ reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
}
static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) {
@@ -416,46 +373,38 @@ public:
obj->setTextLocale(sSingleEntryLocaleCache.languageTag);
}
- static jboolean isElegantTextHeight(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
- Paint* obj = getNativePaint(env, paint);
+ static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(paintHandle);
return obj->getFontVariant() == VARIANT_ELEGANT;
}
- static void setElegantTextHeight(JNIEnv* env, jobject paint, jboolean aa) {
- NPE_CHECK_RETURN_VOID(env, paint);
- Paint* obj = getNativePaint(env, paint);
+ static void setElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
+ Paint* obj = reinterpret_cast<Paint*>(paintHandle);
obj->setFontVariant(aa ? VARIANT_ELEGANT : VARIANT_DEFAULT);
}
- static jfloat getTextSize(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
- return SkScalarToFloat(getNativePaint(env, paint)->getTextSize());
+ static jfloat getTextSize(JNIEnv* env, jobject, jlong paintHandle) {
+ return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
}
- static void setTextSize(JNIEnv* env, jobject paint, jfloat textSize) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setTextSize(textSize);
+ static void setTextSize(JNIEnv* env, jobject, jlong paintHandle, jfloat textSize) {
+ reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
}
- static jfloat getTextScaleX(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
- return SkScalarToFloat(getNativePaint(env, paint)->getTextScaleX());
+ static jfloat getTextScaleX(JNIEnv* env, jobject, jlong paintHandle) {
+ return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
}
- static void setTextScaleX(JNIEnv* env, jobject paint, jfloat scaleX) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setTextScaleX(scaleX);
+ static void setTextScaleX(JNIEnv* env, jobject, jlong paintHandle, jfloat scaleX) {
+ reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
}
- static jfloat getTextSkewX(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
- return SkScalarToFloat(getNativePaint(env, paint)->getTextSkewX());
+ static jfloat getTextSkewX(JNIEnv* env, jobject, jlong paintHandle) {
+ return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
}
- static void setTextSkewX(JNIEnv* env, jobject paint, jfloat skewX) {
- NPE_CHECK_RETURN_VOID(env, paint);
- getNativePaint(env, paint)->setTextSkewX(skewX);
+ static void setTextSkewX(JNIEnv* env, jobject, jlong paintHandle, jfloat skewX) {
+ reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
}
static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) {
@@ -488,14 +437,15 @@ public:
paint->setHyphenEdit((uint32_t)hyphen);
}
- static SkScalar getMetricsInternal(JNIEnv* env, jobject jpaint, Paint::FontMetrics *metrics) {
+ static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle,
+ Paint::FontMetrics *metrics) {
const int kElegantTop = 2500;
const int kElegantBottom = -1000;
const int kElegantAscent = 1900;
const int kElegantDescent = -500;
const int kElegantLeading = 0;
- Paint* paint = getNativePaint(env, jpaint);
- TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
typeface = TypefaceImpl_resolveDefault(typeface);
FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
float saveSkewX = paint->getTextSkewX();
@@ -519,24 +469,22 @@ public:
return spacing;
}
- static jfloat ascent(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
+ static jfloat ascent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
Paint::FontMetrics metrics;
- getMetricsInternal(env, paint, &metrics);
+ getMetricsInternal(paintHandle, typefaceHandle, &metrics);
return SkScalarToFloat(metrics.fAscent);
}
- static jfloat descent(JNIEnv* env, jobject paint) {
- NPE_CHECK_RETURN_ZERO(env, paint);
+ static jfloat descent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
Paint::FontMetrics metrics;
- getMetricsInternal(env, paint, &metrics);
+ getMetricsInternal(paintHandle, typefaceHandle, &metrics);
return SkScalarToFloat(metrics.fDescent);
}
- static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) {
- NPE_CHECK_RETURN_ZERO(env, paint);
+ static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle,
+ jlong typefaceHandle, jobject metricsObj) {
Paint::FontMetrics metrics;
- SkScalar spacing = getMetricsInternal(env, paint, &metrics);
+ SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics);
if (metricsObj) {
SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
@@ -549,11 +497,11 @@ public:
return SkScalarToFloat(spacing);
}
- static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) {
- NPE_CHECK_RETURN_ZERO(env, paint);
+ static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle,
+ jlong typefaceHandle, jobject metricsObj) {
Paint::FontMetrics metrics;
- getMetricsInternal(env, paint, &metrics);
+ getMetricsInternal(paintHandle, typefaceHandle, &metrics);
int ascent = SkScalarRoundToInt(metrics.fAscent);
int descent = SkScalarRoundToInt(metrics.fDescent);
int leading = SkScalarRoundToInt(metrics.fLeading);
@@ -569,138 +517,9 @@ public:
return descent - ascent + leading;
}
- static jfloat measureText_CIII(JNIEnv* env, jobject jpaint, jcharArray text, jint index, jint count,
- jint bidiFlags) {
- NPE_CHECK_RETURN_ZERO(env, jpaint);
- NPE_CHECK_RETURN_ZERO(env, text);
-
- size_t textLength = env->GetArrayLength(text);
- if ((index | count) < 0 || (size_t)(index + count) > textLength) {
- doThrowAIOOBE(env);
- return 0;
- }
- if (count == 0) {
- return 0;
- }
-
- Paint* paint = getNativePaint(env, jpaint);
- const jchar* textArray = env->GetCharArrayElements(text, NULL);
- jfloat result = 0;
-
- Layout layout;
- TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray + index, 0, count,
- count);
- result = layout.getAdvance();
- env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
- return result;
- }
-
- static jfloat measureText_StringIII(JNIEnv* env, jobject jpaint, jstring text, jint start, jint end,
- jint bidiFlags) {
- NPE_CHECK_RETURN_ZERO(env, jpaint);
- NPE_CHECK_RETURN_ZERO(env, text);
-
- size_t textLength = env->GetStringLength(text);
- int count = end - start;
- if ((start | count) < 0 || (size_t)end > textLength) {
- doThrowAIOOBE(env);
- return 0;
- }
- if (count == 0) {
- return 0;
- }
-
- const jchar* textArray = env->GetStringChars(text, NULL);
- Paint* paint = getNativePaint(env, jpaint);
- jfloat width = 0;
-
- Layout layout;
- TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
- // Only the substring is used for measurement, so no additional context is passed in. This
- // behavior is consistent between char[] and String specializations.
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray + start, 0, count, count);
- width = layout.getAdvance();
-
- env->ReleaseStringChars(text, textArray);
- return width;
- }
-
- static jfloat measureText_StringI(JNIEnv* env, jobject jpaint, jstring text, jint bidiFlags) {
- NPE_CHECK_RETURN_ZERO(env, jpaint);
- NPE_CHECK_RETURN_ZERO(env, text);
-
- size_t textLength = env->GetStringLength(text);
- if (textLength == 0) {
- return 0;
- }
-
- const jchar* textArray = env->GetStringChars(text, NULL);
- Paint* paint = getNativePaint(env, jpaint);
- jfloat width = 0;
-
- Layout layout;
- TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, 0, textLength, textLength);
- width = layout.getAdvance();
-
- env->ReleaseStringChars(text, textArray);
- return width;
- }
-
- static int dotextwidths(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar text[], int count,
- jfloatArray widths, jint bidiFlags) {
- NPE_CHECK_RETURN_ZERO(env, paint);
- NPE_CHECK_RETURN_ZERO(env, text);
-
- if (count < 0 || !widths) {
- doThrowAIOOBE(env);
- return 0;
- }
- if (count == 0) {
- return 0;
- }
- size_t widthsLength = env->GetArrayLength(widths);
- if ((size_t)count > widthsLength) {
- doThrowAIOOBE(env);
- return 0;
- }
-
- AutoJavaFloatArray autoWidths(env, widths, count);
- jfloat* widthsArray = autoWidths.ptr();
-
- Layout layout;
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
- layout.getAdvances(widthsArray);
-
- return count;
- }
-
- static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text,
- jint index, jint count, jint bidiFlags, jfloatArray widths) {
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
- const jchar* textArray = env->GetCharArrayElements(text, NULL);
- count = dotextwidths(env, paint, typeface, textArray + index, count, widths, bidiFlags);
- env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
- JNI_ABORT);
- return count;
- }
-
- static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring text,
- jint start, jint end, jint bidiFlags, jfloatArray widths) {
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
- const jchar* textArray = env->GetStringChars(text, NULL);
- int count = dotextwidths(env, paint, typeface, textArray + start, end - start, widths, bidiFlags);
- env->ReleaseStringChars(text, textArray);
- return count;
- }
-
- static jfloat doTextRunAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface, const jchar *text,
- jint start, jint count, jint contextCount, jboolean isRtl,
- jfloatArray advances, jint advancesIndex) {
- NPE_CHECK_RETURN_ZERO(env, paint);
+ static jfloat doTextAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface,
+ const jchar *text, jint start, jint count, jint contextCount, jint bidiFlags,
+ jfloatArray advances, jint advancesIndex) {
NPE_CHECK_RETURN_ZERO(env, text);
if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
@@ -712,50 +531,45 @@ public:
}
if (advances) {
size_t advancesLength = env->GetArrayLength(advances);
- if ((size_t)count > advancesLength) {
+ if ((size_t)(count + advancesIndex) > advancesLength) {
doThrowAIOOBE(env);
return 0;
}
}
- jfloat* advancesArray = new jfloat[count];
- jfloat totalAdvance = 0;
-
- int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
Layout layout;
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount);
- layout.getAdvances(advancesArray);
- totalAdvance = layout.getAdvance();
-
+ MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count,
+ contextCount);
if (advances != NULL) {
- env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
+ std::unique_ptr<jfloat> advancesArray(new jfloat[count]);
+ layout.getAdvances(advancesArray.get());
+ env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get());
}
- delete [] advancesArray;
- return totalAdvance;
+ return layout.getAdvance();
}
- static jfloat getTextRunAdvances___CIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
+ static jfloat getTextAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
jlong typefaceHandle,
jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
- jboolean isRtl, jfloatArray advances, jint advancesIndex) {
+ jint bidiFlags, jfloatArray advances, jint advancesIndex) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
jchar* textArray = env->GetCharArrayElements(text, NULL);
- jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex,
- index - contextIndex, count, contextCount, isRtl, advances, advancesIndex);
+ jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex,
+ index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
return result;
}
- static jfloat getTextRunAdvances__StringIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
+ static jfloat getTextAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
jlong typefaceHandle,
- jstring text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl,
+ jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint bidiFlags,
jfloatArray advances, jint advancesIndex) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
const jchar* textArray = env->GetStringChars(text, NULL);
- jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart,
- start - contextStart, end - start, contextEnd - contextStart, isRtl,
+ jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart,
+ start - contextStart, end - start, contextEnd - contextStart, bidiFlags,
advances, advancesIndex);
env->ReleaseStringChars(text, textArray);
return result;
@@ -973,7 +787,7 @@ public:
static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
- const Paint* paint = reinterpret_cast<Paint*>(paintHandle);;
+ const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
const jchar* textArray = env->GetStringChars(text, NULL);
doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
@@ -1093,102 +907,97 @@ public:
return result;
}
-};
+}; // namespace PaintGlue
static const JNINativeMethod methods[] = {
- {"finalizer", "(J)V", (void*) PaintGlue::finalizer},
- {"native_init","()J", (void*) PaintGlue::init},
- {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
-
- {"native_reset","!(J)V", (void*) PaintGlue::reset},
- {"native_set","!(JJ)V", (void*) PaintGlue::assign},
- {"getFlags","!()I", (void*) PaintGlue::getFlags},
- {"setFlags","!(I)V", (void*) PaintGlue::setFlags},
- {"getHinting","!()I", (void*) PaintGlue::getHinting},
- {"setHinting","!(I)V", (void*) PaintGlue::setHinting},
- {"setAntiAlias","!(Z)V", (void*) PaintGlue::setAntiAlias},
- {"setSubpixelText","!(Z)V", (void*) PaintGlue::setSubpixelText},
- {"setLinearText","!(Z)V", (void*) PaintGlue::setLinearText},
- {"setUnderlineText","!(Z)V", (void*) PaintGlue::setUnderlineText},
- {"setStrikeThruText","!(Z)V", (void*) PaintGlue::setStrikeThruText},
- {"setFakeBoldText","!(Z)V", (void*) PaintGlue::setFakeBoldText},
- {"setFilterBitmap","!(Z)V", (void*) PaintGlue::setFilterBitmap},
- {"setDither","!(Z)V", (void*) PaintGlue::setDither},
- {"native_getStyle","!(J)I", (void*) PaintGlue::getStyle},
- {"native_setStyle","!(JI)V", (void*) PaintGlue::setStyle},
- {"getColor","!()I", (void*) PaintGlue::getColor},
- {"setColor","!(I)V", (void*) PaintGlue::setColor},
- {"getAlpha","!()I", (void*) PaintGlue::getAlpha},
- {"setAlpha","!(I)V", (void*) PaintGlue::setAlpha},
- {"getStrokeWidth","!()F", (void*) PaintGlue::getStrokeWidth},
- {"setStrokeWidth","!(F)V", (void*) PaintGlue::setStrokeWidth},
- {"getStrokeMiter","!()F", (void*) PaintGlue::getStrokeMiter},
- {"setStrokeMiter","!(F)V", (void*) PaintGlue::setStrokeMiter},
- {"native_getStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
- {"native_setStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
- {"native_getStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
- {"native_setStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
- {"native_getFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
- {"native_setShader","!(JJ)J", (void*) PaintGlue::setShader},
- {"native_setColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
- {"native_setXfermode","!(JJ)J", (void*) PaintGlue::setXfermode},
- {"native_setPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
- {"native_setMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
- {"native_setTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
- {"native_setRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
- {"native_getTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
- {"native_setTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
- {"native_setTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale},
- {"isElegantTextHeight","!()Z", (void*) PaintGlue::isElegantTextHeight},
- {"setElegantTextHeight","!(Z)V", (void*) PaintGlue::setElegantTextHeight},
- {"getTextSize","!()F", (void*) PaintGlue::getTextSize},
- {"setTextSize","!(F)V", (void*) PaintGlue::setTextSize},
- {"getTextScaleX","!()F", (void*) PaintGlue::getTextScaleX},
- {"setTextScaleX","!(F)V", (void*) PaintGlue::setTextScaleX},
- {"getTextSkewX","!()F", (void*) PaintGlue::getTextSkewX},
- {"setTextSkewX","!(F)V", (void*) PaintGlue::setTextSkewX},
- {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
- {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
- {"native_setFontFeatureSettings","(JLjava/lang/String;)V",
+ {"nFinalizer", "(J)V", (void*) PaintGlue::finalizer},
+ {"nInit","()J", (void*) PaintGlue::init},
+ {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
+
+ {"nReset","!(J)V", (void*) PaintGlue::reset},
+ {"nSet","!(JJ)V", (void*) PaintGlue::assign},
+ {"nGetFlags","!(J)I", (void*) PaintGlue::getFlags},
+ {"nSetFlags","!(JI)V", (void*) PaintGlue::setFlags},
+ {"nGetHinting","!(J)I", (void*) PaintGlue::getHinting},
+ {"nSetHinting","!(JI)V", (void*) PaintGlue::setHinting},
+ {"nSetAntiAlias","!(JZ)V", (void*) PaintGlue::setAntiAlias},
+ {"nSetSubpixelText","!(JZ)V", (void*) PaintGlue::setSubpixelText},
+ {"nSetLinearText","!(JZ)V", (void*) PaintGlue::setLinearText},
+ {"nSetUnderlineText","!(JZ)V", (void*) PaintGlue::setUnderlineText},
+ {"nSetStrikeThruText","!(JZ)V", (void*) PaintGlue::setStrikeThruText},
+ {"nSetFakeBoldText","!(JZ)V", (void*) PaintGlue::setFakeBoldText},
+ {"nSetFilterBitmap","!(JZ)V", (void*) PaintGlue::setFilterBitmap},
+ {"nSetDither","!(JZ)V", (void*) PaintGlue::setDither},
+ {"nGetStyle","!(J)I", (void*) PaintGlue::getStyle},
+ {"nSetStyle","!(JI)V", (void*) PaintGlue::setStyle},
+ {"nGetColor","!(J)I", (void*) PaintGlue::getColor},
+ {"nSetColor","!(JI)V", (void*) PaintGlue::setColor},
+ {"nGetAlpha","!(J)I", (void*) PaintGlue::getAlpha},
+ {"nSetAlpha","!(JI)V", (void*) PaintGlue::setAlpha},
+ {"nGetStrokeWidth","!(J)F", (void*) PaintGlue::getStrokeWidth},
+ {"nSetStrokeWidth","!(JF)V", (void*) PaintGlue::setStrokeWidth},
+ {"nGetStrokeMiter","!(J)F", (void*) PaintGlue::getStrokeMiter},
+ {"nSetStrokeMiter","!(JF)V", (void*) PaintGlue::setStrokeMiter},
+ {"nGetStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
+ {"nSetStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
+ {"nGetStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
+ {"nSetStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
+ {"nGetFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
+ {"nSetShader","!(JJ)J", (void*) PaintGlue::setShader},
+ {"nSetColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
+ {"nSetXfermode","!(JJ)J", (void*) PaintGlue::setXfermode},
+ {"nSetPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
+ {"nSetMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
+ {"nSetTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
+ {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
+ {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
+ {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
+ {"nSetTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale},
+ {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight},
+ {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight},
+ {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize},
+ {"nSetTextSize","!(JF)V", (void*) PaintGlue::setTextSize},
+ {"nGetTextScaleX","!(J)F", (void*) PaintGlue::getTextScaleX},
+ {"nSetTextScaleX","!(JF)V", (void*) PaintGlue::setTextScaleX},
+ {"nGetTextSkewX","!(J)F", (void*) PaintGlue::getTextSkewX},
+ {"nSetTextSkewX","!(JF)V", (void*) PaintGlue::setTextSkewX},
+ {"nGetLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
+ {"nSetLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
+ {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
(void*) PaintGlue::setFontFeatureSettings},
- {"native_getHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit},
- {"native_setHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit},
- {"ascent","!()F", (void*) PaintGlue::ascent},
- {"descent","!()F", (void*) PaintGlue::descent},
+ {"nGetHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit},
+ {"nSetHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit},
+ {"nAscent","!(JJ)F", (void*) PaintGlue::ascent},
+ {"nDescent","!(JJ)F", (void*) PaintGlue::descent},
- {"getFontMetrics", "!(Landroid/graphics/Paint$FontMetrics;)F",
+ {"nGetFontMetrics", "!(JJLandroid/graphics/Paint$FontMetrics;)F",
(void*)PaintGlue::getFontMetrics},
- {"getFontMetricsInt", "!(Landroid/graphics/Paint$FontMetricsInt;)I",
+ {"nGetFontMetricsInt", "!(JJLandroid/graphics/Paint$FontMetricsInt;)I",
(void*)PaintGlue::getFontMetricsInt},
- {"native_measureText","([CIII)F", (void*) PaintGlue::measureText_CIII},
- {"native_measureText","(Ljava/lang/String;I)F", (void*) PaintGlue::measureText_StringI},
- {"native_measureText","(Ljava/lang/String;III)F", (void*) PaintGlue::measureText_StringIII},
- {"native_breakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
- {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
- {"native_getTextWidths","(JJ[CIII[F)I", (void*) PaintGlue::getTextWidths___CIII_F},
- {"native_getTextWidths","(JJLjava/lang/String;III[F)I",
- (void*) PaintGlue::getTextWidths__StringIII_F},
- {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F",
- (void*) PaintGlue::getTextRunAdvances___CIIIIZ_FI},
- {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F",
- (void*) PaintGlue::getTextRunAdvances__StringIIIIZ_FI},
-
- {"native_getTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
- {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I",
+
+ {"nBreakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
+ {"nBreakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
+ {"nGetTextAdvances","(JJ[CIIIII[FI)F",
+ (void*) PaintGlue::getTextAdvances___CIIIII_FI},
+ {"nGetTextAdvances","(JJLjava/lang/String;IIIII[FI)F",
+ (void*) PaintGlue::getTextAdvances__StringIIIII_FI},
+
+ {"nGetTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
+ {"nGetTextRunCursor", "(JLjava/lang/String;IIIII)I",
(void*) PaintGlue::getTextRunCursor__String},
- {"native_getTextPath", "(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
- {"native_getTextPath", "(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
- {"nativeGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V",
+ {"nGetTextPath", "(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
+ {"nGetTextPath", "(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
+ {"nGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V",
(void*) PaintGlue::getStringBounds },
- {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
+ {"nGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
(void*) PaintGlue::getCharArrayBounds },
- {"native_hasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph },
- {"native_getRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F},
- {"native_getOffsetForAdvance", "(JJ[CIIIIZF)I",
+ {"nHasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph },
+ {"nGetRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F},
+ {"nGetOffsetForAdvance", "(JJ[CIIIIZF)I",
(void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
- {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
- {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
+ {"nSetShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
+ {"nHasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
};
int register_android_graphics_Paint(JNIEnv* env) {
@@ -1210,10 +1019,6 @@ int register_android_graphics_Paint(JNIEnv* env) {
gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");
- gPaint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Paint"));
- gPaint_nativeInstanceID = GetFieldIDOrDie(env, gPaint_class, "mNativePaint", "J");
- gPaint_nativeTypefaceID = GetFieldIDOrDie(env, gPaint_class, "mNativeTypeface", "J");
-
return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods));
}
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index a151e004922d..83f76eab053d 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -117,9 +117,17 @@ static void nFinishBuilder(JNIEnv*, jclass, jlong nativePtr) {
b->finish();
}
-static jlong nLoadHyphenator(JNIEnv* env, jclass, jstring patternData) {
- ScopedStringChars str(env, patternData);
- Hyphenator* hyphenator = Hyphenator::load(str.get(), str.size());
+static jlong nLoadHyphenator(JNIEnv* env, jclass, jobject buffer, jint offset) {
+ const uint8_t* bytebuf = nullptr;
+ if (buffer != nullptr) {
+ void* rawbuf = env->GetDirectBufferAddress(buffer);
+ if (rawbuf != nullptr) {
+ bytebuf = reinterpret_cast<const uint8_t*>(rawbuf) + offset;
+ } else {
+ ALOGE("failed to get direct buffer address");
+ }
+ }
+ Hyphenator* hyphenator = Hyphenator::loadBinary(bytebuf);
return reinterpret_cast<jlong>(hyphenator);
}
@@ -177,7 +185,7 @@ static const JNINativeMethod gMethods[] = {
{"nNewBuilder", "()J", (void*) nNewBuilder},
{"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
{"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
- {"nLoadHyphenator", "(Ljava/lang/String;)J", (void*) nLoadHyphenator},
+ {"nLoadHyphenator", "(Ljava/nio/ByteBuffer;I)J", (void*) nLoadHyphenator},
{"nSetLocale", "(JLjava/lang/String;J)V", (void*) nSetLocale},
{"nSetupParagraph", "(J[CIFIF[IIII)V", (void*) nSetupParagraph},
{"nSetIndents", "(J[I)V", (void*) nSetIndents},
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index c79f833b54a9..17eb876aebf3 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -461,10 +461,10 @@ static void android_view_ThreadedRendererd_drawRenderNode(JNIEnv* env, jobject c
proxy->drawRenderNode(renderNode);
}
-static void android_view_ThreadedRenderer_setContentOverdrawProtectionBounds(JNIEnv* env,
+static void android_view_ThreadedRenderer_setContentDrawBounds(JNIEnv* env,
jobject clazz, jlong proxyPtr, jint left, jint top, jint right, jint bottom) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->setContentOverdrawProtectionBounds(left, top, right, bottom);
+ proxy->setContentDrawBounds(left, top, right, bottom);
}
// ----------------------------------------------------------------------------
@@ -522,8 +522,7 @@ static const JNINativeMethod gMethods[] = {
{ "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode},
{ "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
{ "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
- { "nSetContentOverdrawProtectionBounds", "(JIIII)V",
- (void*)android_view_ThreadedRenderer_setContentOverdrawProtectionBounds},
+ { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
};
int register_android_view_ThreadedRenderer(JNIEnv* env) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 28dac39d7022..148e7c109601 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -65,6 +65,7 @@
<protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" />
<protected-broadcast android:name="android.intent.action.REBOOT" />
<protected-broadcast android:name="android.intent.action.DOCK_EVENT" />
+ <protected-broadcast android:name="android.intent.action.THERMAL_EVENT" />
<protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" />
<protected-broadcast android:name="android.intent.action.USER_ADDED" />
<protected-broadcast android:name="android.intent.action.USER_REMOVED" />
@@ -1714,7 +1715,7 @@
android:protectionLevel="signature|privileged" />
<!-- Allows applications to change network connectivity state.
- <p>Protection level: normal
+ <p>Protection level: signature
-->
<permission android:name="android.permission.CHANGE_NETWORK_STATE"
android:description="@string/permdesc_changeNetworkState"
@@ -2529,6 +2530,12 @@
android:label="@string/permlab_access_notification_policy"
android:protectionLevel="normal" />
+ <!-- Allows modification of do not disturb rules and policies. Only allowed for system
+ processes.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_NOTIFICATIONS"
+ android:protectionLevel="signature" />
+
<!-- Allows access to keyguard secure storage. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
diff --git a/core/res/res/color/btn_colored_text_material.xml b/core/res/res/color/btn_colored_text_material.xml
index 23d05a9bafd6..c80fea62ef30 100644
--- a/core/res/res/color/btn_colored_text_material.xml
+++ b/core/res/res/color/btn_colored_text_material.xml
@@ -18,6 +18,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
android:alpha="?attr/disabledAlpha"
- android:color="?attr/textColorSecondary" />
- <item android:color="?attr/textColorSecondaryInverse" />
+ android:color="?attr/textColorPrimary" />
+ <item android:color="?attr/textColorPrimaryInverse" />
</selector>
diff --git a/core/res/res/layout/popup_menu_header_item_layout.xml b/core/res/res/layout/popup_menu_header_item_layout.xml
new file mode 100644
index 000000000000..5879f85fbd6c
--- /dev/null
+++ b/core/res/res/layout/popup_menu_header_item_layout.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/dropdownListPreferredItemHeight"
+ android:minWidth="196dip"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="?attr/textAppearancePopupMenuHeader"
+ android:layout_gravity="center_vertical"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:textAlignment="viewStart" />
+
+</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a08f040ff716..2f1627b29c0f 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -227,23 +227,23 @@
<string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string>
<string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
- <string name="permgroupdesc_contacts" msgid="6951499528303668046">"gaan by jou kontakte in"</string>
+ <string name="permgroupdesc_contacts" msgid="6951499528303668046">"in te gaan by jou kontakte"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Ligging"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"verkry toegang tot hierdie toestel se ligging"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"toegang te verkry tot hierdie toestel se ligging"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
- <string name="permgroupdesc_calendar" msgid="3889615280211184106">"gaan by jou kalender in"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"by jou kalender in te gaan"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
- <string name="permgroupdesc_sms" msgid="4656988620100940350">"stuur en bekyk SMS-boodskappe"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS-boodskappe te stuur en te bekyk"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Stoor"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"verkry toegang tot foto\'s, media en lêers op jou toestel"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"toegang te verkry tot foto\'s, media en lêers op jou toestel"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofoon"</string>
- <string name="permgroupdesc_microphone" msgid="4988812113943554584">"neem oudio op"</string>
+ <string name="permgroupdesc_microphone" msgid="4988812113943554584">"oudio op te neem"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
- <string name="permgroupdesc_camera" msgid="3250611594678347720">"neem foto\'s en neem video op"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"foto\'s en video te neem"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Foon"</string>
- <string name="permgroupdesc_phone" msgid="6234224354060641055">"maak en bestuur foonoproepe"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"foonoproepe te maak en te bestuur"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Liggaamsensors"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"kry toegang tot sensordata oor jou lewenstekens"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"toegang te verkry tot sensordata oor jou lewenstekens"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Haal venster-inhoud op"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Ondersoek die inhoud van \'n venster waarmee jy interaksie het."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Skakel Verken deur raak aan"</string>
@@ -272,7 +272,7 @@
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Laat die program toe om seluitsending-boodskappe te lees wat deur jou toestel ontvang word. Seluitsending-waarskuwings word in sommige plekke afgelewer om jou van noodsituasies te waarsku. Kwaadwillige programme mag inmeng met die prestasie of die werking van jou toestel wanneer \'n noodgeval se seluitsending ontvang word."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lees ingetekende nuus"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Laat die program toe om details oor die tans gesinkroniseerde strome te kry."</string>
- <string name="permlab_sendSms" msgid="7544599214260982981">"stuur en bekyk SMS-boodskappe"</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"SMS-boodskappe te stuur en te bekyk"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Laat die program toe om SMS-boodskappe te stuur. Dit kan tot onverwagse heffings lei. Kwaadwillige programme kan jou geld kos deur boodskappe sonder jou bevestiging te stuur."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"lees jou teksboodskappe (SMS of MMS)"</string>
<string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Laat die program toe om SMS-boodskappe wat op jou tablet of SIM-kaart gestoor is, te lees. Dit laat die program toe om alle SMS-boodskappe te lees, ongeag van die inhoud of vertroulikheid daarvan."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index cd6bb4b5a6e3..7b05612ab3e2 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -231,7 +231,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"přístup ke kontaktům"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"přístup k poloze tohoto zařízení"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"přístup k poloze tohoto zařízení"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendář"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"přístup ke kalendáři"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index e718935269bc..60f05020a3f0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -493,8 +493,8 @@
<string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Dette giver indehaveren mulighed for at knytte sig til det øverste grænsefladeniveau for et mobilselskabs beskedtjeneste. Dette bør ikke være nødvendigt i normale apps."</string>
<string name="permlab_bindCarrierServices" msgid="3233108656245526783">"knytte til tjenester fra mobilselskabet"</string>
<string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Tillader, at brugeren knytter sig til tjenester fra mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string>
- <string name="permlab_access_notification_policy" msgid="4247510821662059671">"Adgang til Vil ikke forstyrres"</string>
- <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Giver appen tilladelse til at læse og skrive konfigurationen af Vil ikke forstyrres."</string>
+ <string name="permlab_access_notification_policy" msgid="4247510821662059671">"have adgang til Forstyr ikke"</string>
+ <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Giver appen tilladelse til at læse og skrive konfigurationen af Forstyr ikke."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Angiv regler for adgangskoder"</string>
<string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrollér længden samt tilladte tegn i adgangskoder og pinkoder til skærmlåsen."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
@@ -1471,10 +1471,10 @@
</plurals>
<string name="zen_mode_until" msgid="7336308492289875088">"Indtil <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Indtil du slår denne indstilling fra"</string>
- <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Indtil du slår \"Vil ikke forstyrres\" fra"</string>
+ <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Indtil du slår \"Forstyr ikke\" fra"</string>
<string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
<string name="toolbar_collapse_description" msgid="2821479483960330739">"Skjul"</string>
- <string name="zen_mode_feature_name" msgid="5254089399895895004">"Vil ikke forstyrres"</string>
+ <string name="zen_mode_feature_name" msgid="5254089399895895004">"Forstyr ikke"</string>
<string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Nedetid"</string>
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Hverdagsaften"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Weekend"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 2c7a64dab5c8..8e7193a2037f 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -227,23 +227,23 @@
<string name="user_owner_label" msgid="2804351898001038951">"Pertsonalak"</string>
<string name="managed_profile_label" msgid="6260850669674791528">"Lana"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktuak"</string>
- <string name="permgroupdesc_contacts" msgid="6951499528303668046">"Atzitu kontaktuak"</string>
+ <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktuak atzitzeko"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Kokapena"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"Atzitu gailuaren kokapena"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"gailuaren kokapena atzitzeko"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Egutegia"</string>
- <string name="permgroupdesc_calendar" msgid="3889615280211184106">"Atzitu egutegia"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"egutegia atzitzeko"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS mezuak"</string>
- <string name="permgroupdesc_sms" msgid="4656988620100940350">"Bidali eta ikusi SMS mezuak"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS mezuak bidaltzeko eta ikusteko"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Memoria"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"Atzitu gailuko argazkiak, multimedia-elementuak eta fitxategiak"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"gailuko argazkiak, multimedia-elementuak eta fitxategiak atzitzeko"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofonoa"</string>
- <string name="permgroupdesc_microphone" msgid="4988812113943554584">"Grabatu audioa"</string>
+ <string name="permgroupdesc_microphone" msgid="4988812113943554584">"audioa grabatzeko"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
- <string name="permgroupdesc_camera" msgid="3250611594678347720">"Atera argazkiak eta grabatu bideoak"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"argazkiak ateratzeko eta bideoak grabatzeko"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Telefonoa"</string>
- <string name="permgroupdesc_phone" msgid="6234224354060641055">"Egin eta kudeatu telefono-deiak"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"telefono-deiak egiteko eta kudeatzeko"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Gorputz-sentsoreak"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"Atzitu bizi-konstanteei buruzko sentsore-datuak"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"bizi-konstanteei buruzko sentsore-datuak atzitzeko"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Eskuratu leihoko edukia"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Arakatu irekita daukazun leihoko edukia."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktibatu ukipen bidez arakatzeko eginbidea"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6c031593e156..45d9dc36adae 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -144,14 +144,14 @@
<string name="httpErrorOk" msgid="1191919378083472204">"تأیید"</string>
<string name="httpError" msgid="7956392511146698522">"خطایی در شبکه وجود داشت."</string>
<string name="httpErrorLookup" msgid="4711687456111963163">"‏URL پیدا نشد."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"‏طرح کلی تأیید اعتبار سایت پشتیبانی نمی‎شود."</string>
+ <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"‏طرح کلی تأیید اعتبار سایت پشتیبانی نمی‌‎شود."</string>
<string name="httpErrorAuth" msgid="1435065629438044534">"تأیید اعتبار انجام نشد."</string>
<string name="httpErrorProxyAuth" msgid="1788207010559081331">"تأیید اعتبار از طریق سرور پروکسی انجام نشد."</string>
<string name="httpErrorConnect" msgid="8714273236364640549">"اتصال به سرور انجام نشد."</string>
<string name="httpErrorIO" msgid="2340558197489302188">"برقراری ارتباط با سرور ممکن نبود. بعداً دوباره امتحان کنید."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"زمان اتصال به سرور تمام شده است."</string>
<string name="httpErrorRedirectLoop" msgid="8679596090392779516">"این صفحه دارای تعداد بسیار زیادی تغییر مسیر سرور است."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"‏پروتکل پشتیبانی نمی‎شود."</string>
+ <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"‏پروتکل پشتیبانی نمی‌‎شود."</string>
<string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"اتصال امن ایجاد نشد."</string>
<string name="httpErrorBadUrl" msgid="3636929722728881972">"‏بدلیل نامعتبر بودن URL، باز کردن صفحه ممکن نیست."</string>
<string name="httpErrorFile" msgid="2170788515052558676">"دسترسی به فایل انجام نشد."</string>
@@ -781,13 +781,13 @@
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"به برنامه اجازه می‌دهد تا سابقه یا نشانک‌های ذخیره شده مرورگر در تلویزیون شما را تغییر دهد. شاید به برنامه اجازه دهد تا داده‌های «مرورگر» را پاک کند یا تغییر دهد. توجه: این مجوز شاید توسط مرورگرهای شخص ثالث یا سایر برنامه‌ها با قابلیت‌های مرور وب اجرا شود."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"به برنامه اجازه می‌دهد سابقه مرورگر یا نشانک‌های ذخیره شده در تلفن شما را اصلاح کند. این ویژگی ممکن است به برنامه اجازه دهد داده‌های مرورگر را حذف یا اصلاح کند. توجه: این مجوز ممکن است توسط مرورگرهای شخص ثالث یا سایر برنامه‌های دارای قابلیت مرور وب قابل اجرا نباشد."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"تنظیم یک هشدار"</string>
- <string name="permdesc_setAlarm" msgid="316392039157473848">"‏به برنامه اجازه می‎دهد تا هشداری را در برنامه ساعت زنگدار نصب شده تنظیم کند. برخی از برنامه‎های ساعت زنگدار نمی‎توانند این ویژگی را اعمال کنند."</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"‏به برنامه اجازه می‎دهد تا هشداری را در برنامه ساعت زنگدار نصب شده تنظیم کند. برخی از برنامه‎های ساعت زنگدار نمی‌‎توانند این ویژگی را اعمال کنند."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"افزودن پست صوتی"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"به برنامه اجازه می‌دهد تا پیام‌ها را به صندوق دریافت پست صوتی شما اضافه کند."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"تغییر مجوزهای مکان جغرافیایی مرورگر"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"‏به برنامه اجازه می‎دهد تا مجوزهای جغرافیایی مرورگر را تغییر دهد. برنامه‎های مخرب می‎توانند از آن استفاده کنند تا اطلاعات موقعیت مکانی را به سایت‌های وب کتابخانه بفرستند."</string>
<string name="save_password_message" msgid="767344687139195790">"می‌خواهید مرورگر این رمز ورود را به خاطر داشته باشد؟"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"الآن نه"</string>
+ <string name="save_password_notnow" msgid="6389675316706699758">"اکنون نه"</string>
<string name="save_password_remember" msgid="6491879678996749466">"به خاطر سپردن"</string>
<string name="save_password_never" msgid="8274330296785855105">"هیچ‌وقت"</string>
<string name="open_permission_deny" msgid="7374036708316629800">"شما اجازه بازکردن این صفحه را ندارید."</string>
@@ -894,16 +894,16 @@
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"‏پیش‌فرض را در تنظیمات سیستم&gt; برنامه‎ها&gt; مورد دانلود شده پاک کنید."</string>
<string name="chooseActivity" msgid="7486876147751803333">"انتخاب عملکرد"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"‏انتخاب برنامه برای دستگاه USB"</string>
- <string name="noApplications" msgid="2991814273936504689">"‏هیچ برنامه‌ای نمی‎تواند این کار را انجام دهد."</string>
+ <string name="noApplications" msgid="2991814273936504689">"‏هیچ برنامه‌ای نمی‌‎تواند این کار را انجام دهد."</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
<string name="aerr_application" msgid="932628488013092776">"متأسفانه، <xliff:g id="APPLICATION">%1$s</xliff:g> متوقف شده است."</string>
<string name="aerr_process" msgid="4507058997035697579">"متأسفانه، پردازش <xliff:g id="PROCESS">%1$s</xliff:g> متوقف شده است."</string>
<string name="aerr_process_silence" msgid="4226685530196000222">"تا را‌ه‌اندازی مجدد، خرابی‌ها از <xliff:g id="PROCESS">%1$s</xliff:g> نادیده گرفته شوند."</string>
<string name="anr_title" msgid="4351948481459135709"></string>
- <string name="anr_activity_application" msgid="1904477189057199066">"‏<xliff:g id="APPLICATION">%2$s</xliff:g> پاسخ نمی‎دهد.\n\nآیا می‎خواهید آنرا ببندید؟"</string>
- <string name="anr_activity_process" msgid="5776209883299089767">"‏فعالیت <xliff:g id="ACTIVITY">%1$s</xliff:g> پاسخ نمی‎دهد.\n\nآیا می‎خواهید آن را ببندید؟"</string>
- <string name="anr_application_process" msgid="8941757607340481057">"‏<xliff:g id="APPLICATION">%1$s</xliff:g> پاسخ نمی‎دهد. آیا می‎خواهید آن را ببندید؟"</string>
- <string name="anr_process" msgid="6513209874880517125">"‏روند <xliff:g id="PROCESS">%1$s</xliff:g> پاسخ نمی‎دهد. \n\nآیا می‎خواهید آن را ببندید؟"</string>
+ <string name="anr_activity_application" msgid="1904477189057199066">"‏<xliff:g id="APPLICATION">%2$s</xliff:g> پاسخ نمی‌‎دهد.\n\nآیا می‎خواهید آنرا ببندید؟"</string>
+ <string name="anr_activity_process" msgid="5776209883299089767">"‏فعالیت <xliff:g id="ACTIVITY">%1$s</xliff:g> پاسخ نمی‌‎دهد.\n\nآیا می‎خواهید آن را ببندید؟"</string>
+ <string name="anr_application_process" msgid="8941757607340481057">"‏<xliff:g id="APPLICATION">%1$s</xliff:g> پاسخ نمی‌‎دهد. آیا می‎خواهید آن را ببندید؟"</string>
+ <string name="anr_process" msgid="6513209874880517125">"‏روند <xliff:g id="PROCESS">%1$s</xliff:g> پاسخ نمی‌‎دهد. \n\nآیا می‎خواهید آن را ببندید؟"</string>
<string name="force_close" msgid="8346072094521265605">"تأیید"</string>
<string name="report" msgid="4060218260984795706">"گزارش"</string>
<string name="wait" msgid="7147118217226317732">"منتظر بمانید"</string>
@@ -1006,14 +1006,14 @@
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"همیشه غیرمجاز"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"سیم کارت برداشته شد"</string>
<string name="sim_removed_message" msgid="5450336489923274918">"تا زمانی که با یک سیم‌کارت معتبر دوباره راه‌اندازی نکنید شبکه تلفن همراه غیر قابل‌ دسترس خواهد بود."</string>
- <string name="sim_done_button" msgid="827949989369963775">"انجام شد"</string>
+ <string name="sim_done_button" msgid="827949989369963775">"تمام"</string>
<string name="sim_added_title" msgid="3719670512889674693">"سیم کارت اضافه شد"</string>
<string name="sim_added_message" msgid="7797975656153714319">"برای دسترسی به شبکه تلفن همراه، دستگاهتان را مجدداً راه‌اندازی کنید."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"راه‌اندازی مجدد"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"تنظیم زمان"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"تاریخ تنظیم"</string>
<string name="date_time_set" msgid="5777075614321087758">"تنظیم"</string>
- <string name="date_time_done" msgid="2507683751759308828">"انجام شد"</string>
+ <string name="date_time_done" msgid="2507683751759308828">"تمام"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"جدید: "</font></string>
<string name="perms_description_app" msgid="5139836143293299417">"ارائه شده توسط <xliff:g id="APP_NAME">%1$s</xliff:g> ."</string>
<string name="no_permissions" msgid="7283357728219338112">"مجوزی لازم نیست"</string>
@@ -1085,7 +1085,7 @@
<string name="ime_action_search" msgid="658110271822807811">"جستجو"</string>
<string name="ime_action_send" msgid="2316166556349314424">"ارسال"</string>
<string name="ime_action_next" msgid="3138843904009813834">"بعدی"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"انجام شد"</string>
+ <string name="ime_action_done" msgid="8971516117910934605">"تمام"</string>
<string name="ime_action_previous" msgid="1443550039250105948">"قبلی"</string>
<string name="ime_action_default" msgid="2840921885558045721">"اجرا کردن"</string>
<string name="dial_number_using" msgid="5789176425167573586">"شماره گیری \nبا استفاده از <xliff:g id="NUMBER">%s</xliff:g>"</string>
@@ -1131,7 +1131,7 @@
<item quantity="one"><xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g></item>
<item quantity="other"><xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g></item>
</plurals>
- <string name="action_mode_done" msgid="7217581640461922289">"انجام شد"</string>
+ <string name="action_mode_done" msgid="7217581640461922289">"تمام"</string>
<string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"‏در حال پاک کردن حافظهٔ USB..."</string>
<string name="progress_erasing" product="default" msgid="6596988875507043042">"‏در حال پاک کردن کارت SD..."</string>
<string name="share" msgid="1778686618230011964">"اشتراک‌گذاری"</string>
@@ -1173,7 +1173,7 @@
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"لغو"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
- <string name="keyboardview_keycode_done" msgid="1992571118466679775">"انجام شد"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"تمام"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"تغییر حالت"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
@@ -1416,7 +1416,7 @@
<string name="immersive_cling_title" msgid="8394201622932303336">"مشاهده در حالت تمام صفحه"</string>
<string name="immersive_cling_description" msgid="3482371193207536040">"برای خروج، انگشتتان را از بالای صفحه به پایین بکشید."</string>
<string name="immersive_cling_positive" msgid="5016839404568297683">"متوجه شدم"</string>
- <string name="done_label" msgid="2093726099505892398">"انجام شد"</string>
+ <string name="done_label" msgid="2093726099505892398">"تمام"</string>
<string name="hour_picker_description" msgid="6698199186859736512">"لغزنده دایره‌ای ساعت"</string>
<string name="minute_picker_description" msgid="8606010966873791190">"لغزنده دایره‌ای دقیقه"</string>
<string name="select_hours" msgid="6043079511766008245">"انتخاب ساعت"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 7b5ca2949fb9..c32add03c72f 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -229,7 +229,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder aos teus contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Localización"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"acceso á localización deste dispositivo"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"acceder á localización deste dispositivo"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendario"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceder ao teu calendario"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 939299779f29..6281abf705b4 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -229,8 +229,8 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"સંપર્કો"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"તમારા સંપર્કોને ઍક્સેસ કરો"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"સ્થાન"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"આ ઉપકરણના સ્થાનને ઍક્સેસ કરો"</string>
- <string name="permgrouplab_calendar" msgid="5863508437783683902">"કૅલેન્ડર"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"આ ઉપકરણના સ્થાનને ઍક્સેસ કરવાની"</string>
+ <string name="permgrouplab_calendar" msgid="5863508437783683902">"કેલેન્ડર"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"તમારા કેલેન્ડરને ઍક્સેસ કરવાની"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS સંદેશા મોકલો અને જોવાની"</string>
@@ -326,14 +326,14 @@
<string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"એપ્લિકેશનને ઇનકમિંગ અને આઉટગોઇંગ કૉલ્સ વિશેનાં ડેટા સહિત, તમારા ફોનના કૉલ લૉગને સંશોધિત કરવાની મંજૂરી આપે છે. દુર્ભાવનાપૂર્ણ એપ્લિકેશનો આનો ઉપયોગ તમારા કૉલ લૉગને કાઢી નાખવા અથવા સંશોધિત માટે કરી શકે છે."</string>
<string name="permlab_bodySensors" msgid="4871091374767171066">"બૉડી સેન્સર્સ (જેમ કે હાર્ટ રેટ મૉનિટર્સ)"</string>
<string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"એપ્લિકેશનને તમારી હૃદય ગતિ જેવી તમારી શારીરિક સ્થિતિને મૉનિટર કરતાં સેન્સર્સથી ડેટા ઍક્સેસ કરવાની મંજૂરી આપે છે."</string>
- <string name="permlab_readCalendar" msgid="5972727560257612398">"કૅલેન્ડર ઇવેન્ટ્સ વત્તા ગોપનીયતા માહિતી વાંચો"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર સંગ્રહિત તમામ કૅલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કૅલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
- <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર સંગ્રહિત તમામ કૅલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કૅલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
- <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર સંગ્રહિત તમામ કૅલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કૅલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
- <string name="permlab_writeCalendar" msgid="8438874755193825647">"કૅલેન્ડર ઇવેન્ટ્સ ઉમેરો અથવા સંશોધિત કરો અને માલિકની જાણ બહાર અતિથિઓને ઇમેઇલ મોકલો"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કૅલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
- <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કૅલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કૅલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
+ <string name="permlab_readCalendar" msgid="5972727560257612398">"કેલેન્ડર ઇવેન્ટ્સ વત્તા ગોપનીયતા માહિતી વાંચો"</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર સંગ્રહિત તમામ કેલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કેલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર સંગ્રહિત તમામ કેલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કેલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર સંગ્રહિત તમામ કેલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કેલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
+ <string name="permlab_writeCalendar" msgid="8438874755193825647">"કેલેન્ડર ઇવેન્ટ્સ ઉમેરો અથવા સંશોધિત કરો અને માલિકની જાણ બહાર અતિથિઓને ઇમેઇલ મોકલો"</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કેલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
+ <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કેલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કેલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"વધારાના સ્થાન પ્રદાતા આદેશોને ઍક્સેસ કરો"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"એપ્લિકેશનને વધારાના સ્થાન પ્રદાતા આદેશોને ઍક્સેસ કરવાની મંજૂરી આપે છે. આ એપ્લિકેશનને GPS અથવા અન્ય સ્થાન સ્રોતોના ઓપરેશનમાં દખલ કરવાની મંજૂરી આપી શકે છે."</string>
<string name="permlab_accessFineLocation" msgid="1191898061965273372">"નિશ્ચિત સ્થાન (GPS અને નેટવર્ક-આધારિત)"</string>
diff --git a/core/res/res/values-it-watch/strings.xml b/core/res/res/values-it-watch/strings.xml
index c348e481cd7e..aa6a4be8f64c 100644
--- a/core/res/res/values-it-watch/strings.xml
+++ b/core/res/res/values-it-watch/strings.xml
@@ -29,7 +29,7 @@
<string name="permgrouplab_storagewear" msgid="1003807594193602313">"accedere a foto, contenuti multimediali e file sull\'orologio"</string>
<string name="permgrouplab_microphonewear" msgid="1047561180980891136">"registrare audio"</string>
<string name="permgrouplab_camerawear" msgid="4543951283103407017">"scattare foto e registrare video"</string>
- <string name="permgrouplab_phonewear" msgid="134365036753766126">"fare e gestire telefonate"</string>
+ <string name="permgrouplab_phonewear" msgid="134365036753766126">"eseguire e gestire le telefonate"</string>
<string name="permgrouplab_sensorswear" msgid="1429324744329327663">"accedere ai dati dei sensori relativi ai tuoi parametri vitali"</string>
<string name="permlab_statusBarServicewear" msgid="2469402818964691034">"avere la funzione di barra di stato"</string>
<string name="permlab_bodySensorswear" msgid="7857941041202791873">"accedere ai sensori (come il cardiofrequenzimetro)"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 42712876b15d..72b1c54293d6 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -239,11 +239,11 @@
<string name="permgrouplab_microphone" msgid="171539900250043464">"Microfono"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"registrare audio"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Fotocamera"</string>
- <string name="permgroupdesc_camera" msgid="3250611594678347720">"acquisire foto e registrare video"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"scattare foto e registrare video"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Telefono"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"eseguire e gestire le telefonate"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Sensori per il corpo"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accedere ai dati dei sensori sui tuoi parametri vitali"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accedere ai dati dei sensori relativi ai tuoi parametri vitali"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperare contenuti della finestra"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Esaminare i contenuti di una finestra con cui interagisci."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Attivare Esplora al tocco"</string>
@@ -272,7 +272,7 @@
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Consente all\'applicazione di leggere i messaggi cell broadcast ricevuti dal dispositivo. Gli avvisi cell broadcast vengono trasmessi in alcune località per avvertire di eventuali situazioni di emergenza. Le applicazioni dannose potrebbero interferire con il rendimento o con il funzionamento del dispositivo quando si riceve un messaggio cell broadcast di emergenza."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lettura feed sottoscritti"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Consente all\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string>
- <string name="permlab_sendSms" msgid="7544599214260982981">"invio e lettura di SMS"</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"inviare e visualizzare SMS"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Consente all\'applicazione di inviare messaggi SMS. Ciò potrebbe comportare costi imprevisti. Applicazioni dannose potrebbero generare dei costi inviando messaggi senza la tua conferma."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"lettura messaggi di testo personali (SMS o MMS)"</string>
<string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Consente all\'applicazione di leggere i messaggi SMS memorizzati sul tablet o sulla scheda SIM. Ciò consente all\'applicazione di leggere tutti i messaggi SMS, indipendentemente dai contenuti o dal livello di riservatezza."</string>
@@ -342,7 +342,7 @@
<string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Consente all\'applicazione di ottenere la tua posizione approssimativa. Questa posizione viene ottenuta da servizi di localizzazione utilizzando fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione approssimativa."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifica impostazioni audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Consente all\'applicazione di modificare le impostazioni audio globali, come il volume e quale altoparlante viene utilizzato per l\'uscita."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"registrazione audio"</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"registrare audio"</string>
<string name="permdesc_recordAudio" msgid="4906839301087980680">"Consente all\'applicazione di registrare audio con il microfono. Questa autorizzazione consente all\'applicazione di registrare audio in qualsiasi momento senza la tua conferma."</string>
<string name="permlab_sim_communication" msgid="1180265879464893029">"comunicazione SIM"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"Consente all\'app di inviare comandi alla SIM. Questo è molto pericoloso."</string>
diff --git a/core/res/res/values-ja-watch/strings.xml b/core/res/res/values-ja-watch/strings.xml
index 3248041becd3..82c3ffdb8a1a 100644
--- a/core/res/res/values-ja-watch/strings.xml
+++ b/core/res/res/values-ja-watch/strings.xml
@@ -37,7 +37,7 @@
<string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"おおよその位置情報(ネットワーク基地局)へのアクセス"</string>
<string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIMへのコマンド送信"</string>
<string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ネットワークへのフルアクセス"</string>
- <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"プロフィールの所有者と端末の所有者の管理"</string>
+ <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"プロファイルの所有者と端末の所有者の管理"</string>
<string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX状態の変更"</string>
<string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Androidビーム転送のステータスの受信"</string>
<string name="permlab_route_media_outputwear" msgid="8737024341474587192">"メディア出力のルーティング"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 545b963cef61..135c7ea9157c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -282,8 +282,8 @@
<string name="permdesc_receiveWapPush" msgid="748232190220583385">"WAPメッセージの受信と処理をアプリに許可します。これにより、アプリが端末に届いたメッセージを表示することなく監視または削除できるようになります。"</string>
<string name="permlab_getTasks" msgid="6466095396623933906">"実行中のアプリの取得"</string>
<string name="permdesc_getTasks" msgid="7454215995847658102">"現在実行中または最近実行したタスクに関する情報の取得をアプリに許可します。これにより、その端末でどのアプリを使用しているかをアプリから識別できるようになる可能性があります。"</string>
- <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"プロフィールの所有者と端末の所有者の管理"</string>
- <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"プロフィールの所有者と端末の所有者の設定をアプリに許可します。"</string>
+ <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"プロファイルの所有者と端末の所有者の管理"</string>
+ <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"プロファイルの所有者と端末の所有者の設定をアプリに許可します。"</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"実行中のアプリの順序変更"</string>
<string name="permdesc_reorderTasks" msgid="7734217754877439351">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリに許可します。これにより、アプリがユーザーからの入力なしでこの処理を実行する可能性があります。"</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"運転モードの有効化"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index d39ee056c709..7af4df041821 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -229,7 +229,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контактілер"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"контактілерге кіру"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Орын"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"бұл құрылғының орнына кіру"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"бұл құрылғының орналасқан жерін көру"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Күнтізбе"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"күнтізбеге кіру"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index e7e43f0ebcd9..f20551dcf067 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -229,7 +229,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Байланыштар"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"байланыштарыңызга уруксат"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Жайгашкан жер"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"бул түзмөктүн жайгашкан жерине кирүү"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"бул түзмөктүн жайгашкан жери тууралуу дайындарды көрүү"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Күнбарак"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"жылнаамаңызды пайдалануу"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index f10fb1907cd2..a41be56b7637 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -227,23 +227,23 @@
<string name="user_owner_label" msgid="2804351898001038951">"Лични"</string>
<string name="managed_profile_label" msgid="6260850669674791528">"Работа"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
- <string name="permgroupdesc_contacts" msgid="6951499528303668046">"пристапи до контактите"</string>
+ <string name="permgroupdesc_contacts" msgid="6951499528303668046">"пристапува до контактите"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"да пристапува до локацијата на овој уред"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"пристапува до локацијата на овој уред"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string>
- <string name="permgroupdesc_calendar" msgid="3889615280211184106">"пристапи до календарот"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"пристапува до календарот"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"СМС"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"испраќа и прикажува СМС-пораки"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Меморија"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"пристапува до фотографии, медиуми и датотеки на уредот"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"пристапува до фотографии, аудио-видео и датотеки на уредот"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
- <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снимај аудио"</string>
+ <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Фотоапарат"</string>
- <string name="permgroupdesc_camera" msgid="3250611594678347720">"фотографирај и снимај видео"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"фотографира и снима видео"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string>
- <string name="permgroupdesc_phone" msgid="6234224354060641055">"повикувај и управувај со телефонски повици"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"упатува и управува со телефонски повици"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Телесни сензори"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"пристапи до податоците од сензорите за виталните знаци"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"пристапува до податоците од сензорите за виталните знаци"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Врати содржина на прозорец"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Провери ја содржината на прозорецот со кој се комуницира."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Вклучи „Истражувај со допир“"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index a547ca733ca6..41528d87cbca 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -229,7 +229,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"အဆက်အသွယ်များ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"သင့် အဆက်အသွယ်များအား ဝင်ရောက်သုံးရန်"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"တည်နေရာ"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"စက်ပစ္စည်း၏ တည်နေရာကို အသုံးပြုမည်"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"ဤစက်ပစ္စည်း၏ တည်နေရာကို ရယူ"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"ပြက္ခဒိန်"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"သင့်ပြက္ခဒိန်အား ဝင်ရောက်သုံးရန်"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"စာတိုစနစ်"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index d203a6a6c86f..2f6c8bf173ae 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -227,23 +227,23 @@
<string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
<string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
- <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acessar seus contatos"</string>
+ <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"acesse o local do dispositivo"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
- <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acessar sua agenda"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do seu dispositivo"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do dispositivo"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"grave áudio"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Câmera"</string>
<string name="permgroupdesc_camera" msgid="3250611594678347720">"tire fotos e grave vídeos"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Telefone"</string>
- <string name="permgroupdesc_phone" msgid="6234224354060641055">"fazer e gerenciar chamadas telefônicas"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"faça e gerencie chamadas telefônicas"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporais"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acessar dados do sensor sobre seus sinais vitais"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acesse dados do sensor sobre seus sinais vitais"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar cont. da janela"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecionar o conteúdo da janela com que você está interagindo."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Ativar Explorar por toque"</string>
@@ -272,7 +272,7 @@
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite que o app leia mensagens de difusão celular recebidas por seu dispositivo. Alertas de difusão celular são recebidos em alguns locais para avisar você de situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento de seu dispositivo quando uma difusão celular de emergência é recebida."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds inscritos"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite que o app obtenha detalhes sobre os feeds sincronizados no momento."</string>
- <string name="permlab_sendSms" msgid="7544599214260982981">"enviar e ver mensagens SMS"</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"envie e veja mensagens SMS"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Permite que o app envie mensagens SMS. Isso pode resultar em cobranças inesperadas. Apps maliciosos podem gerar custos através do envio de mensagens sem sua confirmação."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"ler suas mensagens de texto (SMS ou MMS)"</string>
<string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite que o app leia mensagens SMS armazenadas no tablet ou cartão SIM. Isso permite que o app leia todas as mensagens SMS, independentemente de seu conteúdo ou confidencialidade."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d203a6a6c86f..2f6c8bf173ae 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -227,23 +227,23 @@
<string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
<string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
- <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acessar seus contatos"</string>
+ <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"acesse o local do dispositivo"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
- <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acessar sua agenda"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do seu dispositivo"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do dispositivo"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"grave áudio"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Câmera"</string>
<string name="permgroupdesc_camera" msgid="3250611594678347720">"tire fotos e grave vídeos"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Telefone"</string>
- <string name="permgroupdesc_phone" msgid="6234224354060641055">"fazer e gerenciar chamadas telefônicas"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"faça e gerencie chamadas telefônicas"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporais"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acessar dados do sensor sobre seus sinais vitais"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acesse dados do sensor sobre seus sinais vitais"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar cont. da janela"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecionar o conteúdo da janela com que você está interagindo."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Ativar Explorar por toque"</string>
@@ -272,7 +272,7 @@
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite que o app leia mensagens de difusão celular recebidas por seu dispositivo. Alertas de difusão celular são recebidos em alguns locais para avisar você de situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento de seu dispositivo quando uma difusão celular de emergência é recebida."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds inscritos"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite que o app obtenha detalhes sobre os feeds sincronizados no momento."</string>
- <string name="permlab_sendSms" msgid="7544599214260982981">"enviar e ver mensagens SMS"</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"envie e veja mensagens SMS"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Permite que o app envie mensagens SMS. Isso pode resultar em cobranças inesperadas. Apps maliciosos podem gerar custos através do envio de mensagens sem sua confirmação."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"ler suas mensagens de texto (SMS ou MMS)"</string>
<string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite que o app leia mensagens SMS armazenadas no tablet ou cartão SIM. Isso permite que o app leia todas as mensagens SMS, independentemente de seu conteúdo ou confidencialidade."</string>
diff --git a/core/res/res/values-ro-watch/strings.xml b/core/res/res/values-ro-watch/strings.xml
index e412cad4f674..9a8e4e0f4857 100644
--- a/core/res/res/values-ro-watch/strings.xml
+++ b/core/res/res/values-ro-watch/strings.xml
@@ -22,15 +22,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="android_upgrading_apk" msgid="1090732262010398759">"Aplic. <xliff:g id="NUMBER_0">%1$d</xliff:g> din <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
<string name="permgrouplab_sensors" msgid="202675452368612754">"Senzori"</string>
- <string name="permgrouplab_contactswear" msgid="2340286500790908344">"să acceseze persoanele de contact"</string>
+ <string name="permgrouplab_contactswear" msgid="2340286500790908344">"acceseze persoanele de contact"</string>
<string name="permgrouplab_locationwear" msgid="6275317222482780209">"să acceseze locația acestui ceas"</string>
- <string name="permgrouplab_calendarwear" msgid="441900844045065081">"să acceseze calendarul"</string>
- <string name="permgrouplab_smswear" msgid="6849506550342974220">"să trimită și să vadă mesajele SMS"</string>
+ <string name="permgrouplab_calendarwear" msgid="441900844045065081">"acceseze calendarul"</string>
+ <string name="permgrouplab_smswear" msgid="6849506550342974220">"trimită și să vadă mesajele SMS"</string>
<string name="permgrouplab_storagewear" msgid="1003807594193602313">"să acceseze fotografiile, conținutul media și fișierele de pe ceas"</string>
- <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"să înregistreze conținut audio"</string>
- <string name="permgrouplab_camerawear" msgid="4543951283103407017">"să fotografieze și să înregistreze videoclipuri"</string>
- <string name="permgrouplab_phonewear" msgid="134365036753766126">"să inițieze să și gestioneze apeluri telefonice"</string>
- <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"să acceseze datele de la senzori despre semnele vitale"</string>
+ <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"înregistreze sunet"</string>
+ <string name="permgrouplab_camerawear" msgid="4543951283103407017">"fotografieze și să înregistreze imagini"</string>
+ <string name="permgrouplab_phonewear" msgid="134365036753766126">"inițieze să și gestioneze apeluri telefonice"</string>
+ <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"acceseze datele de la senzori despre semnele vitale"</string>
<string name="permlab_statusBarServicewear" msgid="2469402818964691034">"să fie bara de stare"</string>
<string name="permlab_bodySensorswear" msgid="7857941041202791873">"să acceseze senzorii corporali (cum ar fi monitoarele cardiace)"</string>
<string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"să acceseze locația exactă (bazată pe GPS și pe rețea)"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index d215d4c3d7a7..5062e7628b6d 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -135,7 +135,7 @@
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Se preferă conexiunea Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Se preferă conexiunea mobilă"</string>
<string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Numai Wi-Fi"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionată"</string>
+ <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecționată"</string>
<string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> după <xliff:g id="TIME_DELAY">{2}</xliff:g> (de) secunde"</string>
<string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionat"</string>
@@ -232,19 +232,19 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Locație"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"acceseze locația acestui dispozitiv"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendar"</string>
- <string name="permgroupdesc_calendar" msgid="3889615280211184106">"accesează calendarul"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceseze calendarul"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
- <string name="permgroupdesc_sms" msgid="4656988620100940350">"trimite și vede mesajele SMS"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"trimită și să vadă mesajele SMS"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Stocare"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"acceseze fotografiile, conținutul media și fișierele de pe dispozitiv"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Microfonul"</string>
- <string name="permgroupdesc_microphone" msgid="4988812113943554584">"înregistreze conținut audio"</string>
+ <string name="permgroupdesc_microphone" msgid="4988812113943554584">"înregistreze sunet"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Camera foto"</string>
- <string name="permgroupdesc_camera" msgid="3250611594678347720">"fotografieze și să înregistreze videoclipuri"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"fotografieze și să înregistreze imagini"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"inițieze și să gestioneze apeluri telefonice"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Senzori corporali"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accesează datele înregistrate de senzori despre semnele vitale"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceseze datele de la senzori despre semnele vitale"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperează conținutul ferestrei"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspectează conținutul unei ferestre cu care interacționați."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Activează funcția Explorați prin atingere"</string>
@@ -270,11 +270,11 @@
<string name="permlab_receiveMms" msgid="1821317344668257098">"primeşte mesaje text (MMS)"</string>
<string name="permdesc_receiveMms" msgid="533019437263212260">"Permite aplicației să primească și să proceseze mesaje MMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"citeşte mesajele cu transmisie celulară"</string>
- <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situaţiile de urgenţă. Aplicaţiile rău intenţionate pot afecta performanţa sau funcţionarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situațiile de urgenţă. Aplicaţiile rău intenţionate pot afecta performanţa sau funcționarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"citire feeduri abonat"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite aplicației să obţină detalii despre feedurile sincronizate în prezent."</string>
- <string name="permlab_sendSms" msgid="7544599214260982981">"trimite și vede mesajele SMS"</string>
- <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariţia unor taxe neaşteptate. Aplicaţiile rău intenţionate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"trimită și să vadă mesajele SMS"</string>
+ <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariția unor taxe neaşteptate. Aplicaţiile rău intenţionate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"citeşte mesajele text (SMS sau MMS)"</string>
<string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite aplicației să citească mesajele SMS stocate pe tabletă sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conţinutul sau de gradul de confidenţialitate al acestora."</string>
<string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Permite aplicației să citească mesajele SMS stocate pe televizor sau pe cardul SIM. Cu această permisiune, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string>
@@ -292,11 +292,11 @@
<string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"închide alte aplicații"</string>
<string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Permite aplicației să oprească procesele derulate în fundal de alte aplicații. Acest lucru poate face ca respectivele aplicații să nu mai ruleze."</string>
<string name="permlab_systemAlertWindow" msgid="3543347980839518613">"suprapune elemente vizuale peste alte aplicații"</string>
- <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite aplicației să suprapună elemente vizuale peste alte aplicații sau părţi ale interfeţei cu utilizatorul. Acestea pot interfera cu utilizarea de către dvs. a interfeţei în orice aplicație sau pot schimba ceea ce credeţi că vedeţi în alte aplicații."</string>
+ <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite aplicației să suprapună elemente vizuale peste alte aplicații sau părți ale interfeței cu utilizatorul. Acestea pot interfera cu utilizarea de către dvs. a interfeței în orice aplicație sau pot schimba ceea ce credeți că vedeţi în alte aplicații."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"rulare continuă a aplicației"</string>
- <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permite aplicației să declare persistente în memorie anumite părţi ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcţionarea tabletei."</string>
+ <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea tabletei."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea televizorului."</string>
- <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Permite aplicației să declare persistente în memorie anumite părţi ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcţionarea telefonului."</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea telefonului."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"măsurare spaţiu de stocare al aplicației"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Permite aplicației să preia dimensiunile codului, ale datelor și ale memoriei cache"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"modifică setări de sistem"</string>
@@ -310,17 +310,17 @@
<string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze televizorul, determinându-l să utilizeze prea multă memorie."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze telefonul, determinându-l să utilizeze prea multă memorie."</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"citeşte agenda"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără ştirea dvs."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string>
<string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Permite aplicației să citească datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string>
- <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără ştirea dvs."</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string>
<string name="permlab_writeContacts" msgid="5107492086416793544">"modifică agenda"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
<string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Permite aplicației să modifice datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane de contact. Cu această permisiune, aplicația poate șterge datele de contact."</string>
- <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"citeşte jurnalul de apeluri"</string>
- <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără ştirea dvs."</string>
+ <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string>
<string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Permite aplicației să citească jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune, aplicațiile pot să salveze datele din jurnalul de apeluri, iar aplicațiile rău-intenționate pot permite accesul la datele din jurnalul de apeluri fără cunoștința dvs."</string>
- <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără ştirea dvs."</string>
+ <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"scrie jurnalul de apeluri"</string>
<string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
<string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Permite aplicației să modifice jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău-intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul de apeluri."</string>
@@ -331,10 +331,10 @@
<string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Permite aplicației să citească toate evenimentele din calendar stocate pe tabletă, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string>
<string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Permite aplicației să citească toate evenimentele din calendar stocate pe televizor, inclusiv cele ale prietenilor sau colegilor. Cu această permisiune, aplicația poate să permită accesul la datele din calendar sau să le salveze, indiferent dacă acestea sunt confidențiale sau sensibile."</string>
<string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Permite aplicației să citească toate evenimentele din calendar stocate pe telefon, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string>
- <string name="permlab_writeCalendar" msgid="8438874755193825647">"adăugarea sau modificarea evenimentelor din calendar și trimiterea de e-mailuri invitaţilor fără ştirea proprietarului"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string>
+ <string name="permlab_writeCalendar" msgid="8438874755193825647">"adăugarea sau modificarea evenimentelor din calendar și trimiterea de e-mailuri invitaților fără știrea proprietarului"</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără știrea proprietarilor."</string>
<string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe televizor, inclusiv pe cele ale prietenilor sau ale colegilor. Cu această permisiune, aplicația poate să trimită mesaje care par că vin din partea proprietarilor calendarului sau să modifice evenimentele fără cunoștința acestora."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe telefon, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe telefon, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără știrea proprietarilor."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesare comenzi suplimentare ale furnizorului locației"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite aplicației să acceseze comenzi suplimentare pentru furnizorul locației. Aplicația ar putea să utilizeze această permisiune pentru a influența operațiile GPS sau ale altor surse de locații."</string>
<string name="permlab_accessFineLocation" msgid="1191898061965273372">"locaţia exactă (bazată pe rețea și GPS)"</string>
@@ -343,7 +343,7 @@
<string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permite aplicației să obţină locaţia dvs. aproximativă. Această locație este dedusă de serviciile de localizare utilizând surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicaţiile pot utiliza această permisiune pentru a determina locaţia dvs. aproximativă."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modificare setări audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite aplicației să modifice setările audio globale, cum ar fi volumul și difuzorul care este utilizat pentru ieșire."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"înregistrare audio"</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"înregistreze sunet"</string>
<string name="permdesc_recordAudio" msgid="4906839301087980680">"Permite aplicației să efectueze înregistrări audio cu ajutorul microfonului. Cu această permisiune aplicația efectuează oricând înregistrări audio fără confirmare."</string>
<string name="permlab_sim_communication" msgid="1180265879464893029">"comunicare cu cardul SIM"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"Permite aplicației să trimită comenzi pe cardul SIM. Această permisiune este foarte periculoasă."</string>
@@ -354,11 +354,11 @@
<string name="permlab_flashlight" msgid="2155920810121984215">"control lanternă"</string>
<string name="permdesc_flashlight" msgid="6522284794568368310">"Permite aplicației să controleze lanterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"apelare directă numere de telefon"</string>
- <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariţia unor taxe sau a unor apeluri neaşteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
+ <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neaşteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string>
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite aplicației să folosească serviciul IMS pentru apeluri, fără intervenția dvs."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"citeşte starea și identitatea telefonului"</string>
- <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicației să acceseze funcţiile de telefon ale dispozitivului. Cu această permisiune aplicația stabileşte numărul de telefon și ID-urile de dispozitiv, dacă un apel este activ, precum și numărul de la distanţă conectat printr-un apel."</string>
+ <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicației să acceseze funcţiile de telefon ale dispozitivului. Cu această permisiune aplicația stabilește numărul de telefon și ID-urile de dispozitiv, dacă un apel este activ, precum și numărul de la distanţă conectat printr-un apel."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"împiedicarea computerului tablet PC să intre în repaus"</string>
<string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"împiedică intrarea televizorului în stare de inactivitate"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string>
@@ -756,7 +756,7 @@
<string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Rămâneți în această pagină"</string>
<string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nSigur doriți să părăsiți această pagină?"</string>
<string name="save_password_label" msgid="6860261758665825069">"Confirmați"</string>
- <string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriţi și micşoraţi prin dublă atingere."</string>
+ <string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriți și micșorați prin dublă atingere."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Automat"</string>
<string name="setup_autofill" msgid="7103495070180590814">"Conf.Compl.auto."</string>
<string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
@@ -767,7 +767,7 @@
<string name="autofill_postal_code" msgid="4696430407689377108">"Cod poştal"</string>
<string name="autofill_state" msgid="6988894195520044613">"Stat"</string>
<string name="autofill_zip_code" msgid="8697544592627322946">"Cod ZIP"</string>
- <string name="autofill_county" msgid="237073771020362891">"Judeţ"</string>
+ <string name="autofill_county" msgid="237073771020362891">"Județ"</string>
<string name="autofill_island" msgid="4020100875984667025">"Insulă"</string>
<string name="autofill_district" msgid="8400735073392267672">"District"</string>
<string name="autofill_department" msgid="5343279462564453309">"Departament"</string>
@@ -776,11 +776,11 @@
<string name="autofill_area" msgid="3547409050889952423">"Zonă"</string>
<string name="autofill_emirate" msgid="2893880978835698818">"Emirat"</string>
<string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"citeşte marcajele și istoricul web"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Permite aplicației să citească istoricul tuturor adreselor URL accesate de Browser și toate marcajele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Permite aplicației să citească istoricul tuturor adreselor URL accesate de Browser și toate marcajele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string>
<string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"scrie în marcajele și în istoricul web"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string>
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Permite aplicației să modifice istoricul sau marcajele browserului stocate pe televizor. Cu această permisiune, aplicația poate șterge sau modifica datele din browser. Notă: această permisiune nu poate fi aplicată de browsere terță parte sau de alte aplicații cu capacități de navigare pe web."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"setează o alarmă"</string>
<string name="permdesc_setAlarm" msgid="316392039157473848">"Permite aplicației să seteze o alarmă într-o aplicație de ceas cu alarmă instalată. Este posibil ca unele aplicații de ceas cu alarmă să nu implementeze această funcție."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"adăugare mesagerie vocală"</string>
@@ -803,11 +803,11 @@
<string name="searchview_description_search" msgid="6749826639098512120">"Căutați"</string>
<string name="searchview_description_query" msgid="5911778593125355124">"Interogare de căutare"</string>
<string name="searchview_description_clear" msgid="1330281990951833033">"Ștergeți interogarea"</string>
- <string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteţi interogarea"</string>
+ <string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteți interogarea"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Căutare vocală"</string>
- <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activați Exploraţi prin atingere?"</string>
- <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu tableta."</string>
- <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu telefonul."</string>
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activați Explorați prin atingere?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu tableta."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu telefonul."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Cu mai mult de 1 lună în urmă"</string>
<plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
@@ -918,7 +918,7 @@
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scară"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Afişaţi întotdeauna"</string>
- <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivaţi acest mod din Setări de sistem &gt; Aplicații &gt; Descărcate."</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivați acest mod din Setări de sistem &gt; Aplicații &gt; Descărcate."</string>
<string name="smv_application" msgid="3307209192155442829">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> a încălcat propria politică StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android trece la o versiune superioară..."</string>
@@ -1002,10 +1002,10 @@
<string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; trimite un număr mare de mesaje SMS. Permiteți acestei aplicații să trimită în continuare mesaje?"</string>
<string name="sms_control_yes" msgid="3663725993855816807">"Permiteți"</string>
<string name="sms_control_no" msgid="625438561395534982">"Refuzaţi"</string>
- <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; intenţionează să trimită un mesaj la &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
+ <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; intenționează să trimită un mesaj la &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
<string name="sms_short_code_details" msgid="5873295990846059400">"Acest lucru "<b>"poate genera costuri"</b>" în contul dvs. mobil."</string>
<string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Acest lucru va genera costuri în contul dvs. mobil."</b></string>
- <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Trimiteţi"</string>
+ <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Trimiteți"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Anulați"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Doresc să se reţină opţiunea"</string>
<string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Puteți modifica ulterior în Setări &gt; Aplicații"</string>
@@ -1080,8 +1080,8 @@
<string name="ext_media_status_formatting" msgid="1085079556538644861">"Se formatează…"</string>
<string name="ext_media_status_missing" msgid="5638633895221670766">"Nu este introdus"</string>
<string name="activity_list_empty" msgid="1675388330786841066">"Nu s-a găsit nicio activitate potrivită."</string>
- <string name="permlab_route_media_output" msgid="1642024455750414694">"Direcţionează rezultatele media"</string>
- <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite unei aplicații să direcţioneze rezultate media către alte dispozitive externe."</string>
+ <string name="permlab_route_media_output" msgid="1642024455750414694">"Direcționează rezultatele media"</string>
+ <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite unei aplicații să direcționeze rezultate media către alte dispozitive externe."</string>
<string name="permlab_readInstallSessions" msgid="6165432407628065939">"Citirea sesiunilor de instalare"</string>
<string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite unei aplicații accesul la citirea sesiunilor de instalare. Aceasta poate vedea detalii despre instalările de pachete active."</string>
<string name="permlab_requestInstallPackages" msgid="1772330282283082214">"Solicită instalarea pachetelor"</string>
@@ -1124,7 +1124,7 @@
<string name="upload_file" msgid="2897957172366730416">"Alegeţi un fişier"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fișiere"</string>
<string name="reset" msgid="2448168080964209908">"Resetaţi"</string>
- <string name="submit" msgid="1602335572089911941">"Trimiteţi"</string>
+ <string name="submit" msgid="1602335572089911941">"Trimiteți"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mod Maşină activat"</string>
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Atingeți pentru a ieşi din modul Maşină."</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"Tethering sau hotspot activ"</string>
@@ -1160,21 +1160,21 @@
<string name="choose_account_label" msgid="5655203089746423927">"Alegeţi un cont"</string>
<string name="add_account_label" msgid="2935267344849993553">"Adăugaţi un cont"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Adăugaţi un cont"</string>
- <string name="number_picker_increment_button" msgid="2412072272832284313">"Creşteţi"</string>
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Creșteți"</string>
<string name="number_picker_decrement_button" msgid="476050778386779067">"Reduceţi"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Atingeți și țineți apăsat <xliff:g id="VALUE">%s</xliff:g>."</string>
<string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Glisaţi în sus pentru a creşte și în jos pentru a reduce."</string>
- <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Creşteţi valoarea pentru minute"</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Creșteți valoarea pentru minute"</string>
<string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Reduceţi valoarea pentru minute"</string>
- <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Creşteţi valoarea pentru oră"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Creșteți valoarea pentru oră"</string>
<string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Reduceţi valoarea pentru oră"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Setaţi valoarea PM"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Setaţi valoarea AM"</string>
- <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Creşteţi valoarea pentru lună"</string>
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Creșteți valoarea pentru lună"</string>
<string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Reduceţi valoarea pentru lună"</string>
- <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Creşteţi valoarea pentru zi"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Creșteți valoarea pentru zi"</string>
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reduceţi valoarea pentru zi"</string>
- <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Creşteţi valoarea pentru an"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Creșteți valoarea pentru an"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reduceţi valoarea pentru an"</string>
<string name="date_picker_prev_month_button" msgid="2858244643992056505">"Luna trecută"</string>
<string name="date_picker_next_month_button" msgid="5559507736887605055">"Luna viitoare"</string>
@@ -1245,7 +1245,7 @@
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletă"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
- <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Căşti"</string>
+ <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Căști"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Difuz. dispozit. andocare"</string>
<string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index f1deb22d3c8d..0621bbe1bd0a 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -915,7 +915,7 @@
<string name="anr_application_process" msgid="8941757607340481057">"Приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" не отвечает. Закрыть его?"</string>
<string name="anr_process" msgid="6513209874880517125">"Приложение \"<xliff:g id="PROCESS">%1$s</xliff:g>\" не отвечает.\n\nЗакрыть его?"</string>
<string name="force_close" msgid="8346072094521265605">"ОК"</string>
- <string name="report" msgid="4060218260984795706">"Отзыв"</string>
+ <string name="report" msgid="4060218260984795706">"Отправить отчет"</string>
<string name="wait" msgid="7147118217226317732">"Подождать"</string>
<string name="webpage_unresponsive" msgid="3272758351138122503">"Страница не отвечает.\n\nЗакрыть ее?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Приложение перенаправлено"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index d5bafd259217..582f912b0e80 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -229,7 +229,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"සම්බන්ධතා"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ඔබේ සම්බන්ධතාවලට පිවිසෙන්න"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"ස්ථානය"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"මෙම උපාංගයේ ස්ථානය ප්‍රවේශ කිරීම"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"මෙම උපාංගයේ ස්ථානයට ප්‍රවේශ කරන්න"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"දින දර්ශනය"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"ඔබේ දින දර්ශනයට පිවිසෙන්න"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"කෙටි පණිවිඩ"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index cf87e2a67b4c..c5ca3c254b76 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -993,7 +993,7 @@
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ni bilo mogoče zagnati."</string>
<string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je vklopljen"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotaknite se za nastavitve"</string>
- <string name="accept" msgid="1645267259272829559">"Sprejmi"</string>
+ <string name="accept" msgid="1645267259272829559">"Sprejmem"</string>
<string name="decline" msgid="2112225451706137894">"Zavrni"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Povabilo je poslano"</string>
<string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Povabilo za povezavo"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 86f9d11fac6c..7df0f86ba96f 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -229,7 +229,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktet"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"qasu te kontaktet e tua"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Vendndodhja"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"qasu te vendndodhja e kësaj pajisjeje"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"qasjen te vendndodhja e kësaj pajisjeje"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendari"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"qasu te kalendari yt"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a3a4b32f0a71..5bb2d781ea72 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -230,21 +230,21 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"приступи контактима"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"приступ локацији овог уређаја"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"приступи локацији овог уређаја"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"приступи календару"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"шаље и прегледа SMS поруке"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Складиште"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"приступи сликама, медијима и датотекама на уређају"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"приступа сликама, медијима и датотекама на уређају"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
- <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снимање аудио снимака"</string>
+ <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио снимке"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
- <string name="permgroupdesc_camera" msgid="3250611594678347720">"снимање слика и видео снимака"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"снима слике и видео снимке"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string>
- <string name="permgroupdesc_phone" msgid="6234224354060641055">"упућивање телефонских позива и управљање њима"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"упућује телефонске позиве и управља њима"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Сензори за тело"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"приступ подацима сензора о виталним функцијама"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"приступа подацима сензора о виталним функцијама"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Преузима садржај прозора"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Проверава садржај прозора са којим остварујете интеракцију."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Укључи Истраживања додиром"</string>
@@ -273,7 +273,7 @@
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Омогућава апликацији да чита поруке инфо сервиса које уређај прима. Упозорења инфо сервиса се на неким локацијама примају као упозорења на хитне случајеве. Злонамерне апликације могу да утичу на учинак или ометају функционисање уређаја када се прими порука инфо сервиса о хитном случају."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"читање пријављених фидова"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Дозвољава апликацији да преузима детаље о тренутно синхронизованим фидовима."</string>
- <string name="permlab_sendSms" msgid="7544599214260982981">"шаљи и прегледај SMS поруке"</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"шаље и прегледа SMS поруке"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Дозвољава апликацији да шаље SMS поруке. Ово може да доведе до неочекиваних трошкова. Злонамерне апликације могу да шаљу поруке без ваше потврде, што може да изазове трошкове."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"читање текстуалних порука (SMS или MMS)"</string>
<string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Дозвољава апликацији да чита SMS поруке ускладиштене на таблету или SIM картици. Ово омогућава апликацији да чита све SMS поруке, без обзира на садржај или поверљивост."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 237afe742d2e..29fd6a1be775 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -853,7 +853,7 @@
<string name="Midnight" msgid="5630806906897892201">"Midnatt"</string>
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Välj alla"</string>
+ <string name="selectAll" msgid="6876518925844129331">"Markera allt"</string>
<string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
<string name="copy" msgid="2681946229533511987">"Kopiera"</string>
<string name="paste" msgid="5629880836805036433">"Klistra in"</string>
@@ -1190,7 +1190,7 @@
<string name="action_menu_overflow_description" msgid="2295659037509008453">"Fler alternativ"</string>
<string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
- <string name="storage_internal" msgid="4891916833657929263">"Internminne"</string>
+ <string name="storage_internal" msgid="4891916833657929263">"lagring"</string>
<string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
<string name="storage_sd_card_label" msgid="6347111320774379257">"SD-kort (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
<string name="storage_usb_drive" msgid="6261899683292244209">"USB-enhet"</string>
@@ -1235,7 +1235,7 @@
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara en gång"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s har inte stöd för arbetsprofil"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Surfplatta"</string>
- <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string>
+ <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Mobil"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Hörlurar"</string>
<string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockningsstationens högtalare"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 6445f6a4a62e..d367887275ac 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -231,7 +231,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Anwani"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"ifikie anwani zako"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Mahali"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"fikia mahali kilipo kifaa hiki"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"ifikie mahali kilipo kifaa hiki"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalenda"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"fikia kalenda yako"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-uz-rUZ-watch/strings.xml b/core/res/res/values-uz-rUZ-watch/strings.xml
index 0fe54a194474..44af51d997d5 100644
--- a/core/res/res/values-uz-rUZ-watch/strings.xml
+++ b/core/res/res/values-uz-rUZ-watch/strings.xml
@@ -22,15 +22,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g>dan <xliff:g id="NUMBER_0">%1$d</xliff:g> ilova."</string>
<string name="permgrouplab_sensors" msgid="202675452368612754">"Sensorlar"</string>
- <string name="permgrouplab_contactswear" msgid="2340286500790908344">"kontaktlarga kirishga ruxsat berish"</string>
+ <string name="permgrouplab_contactswear" msgid="2340286500790908344">"kontaktlarga kirish"</string>
<string name="permgrouplab_locationwear" msgid="6275317222482780209">"mazkur soatning joylashgan joyini ko‘rishga ruxsat berish"</string>
<string name="permgrouplab_calendarwear" msgid="441900844045065081">"taqvim ma’lumotlariga kirish"</string>
<string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS xabarlarni yuborish va ko‘rish"</string>
<string name="permgrouplab_storagewear" msgid="1003807594193602313">"Soatingizdagi rasmlar, media va fayllarga kirish"</string>
<string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ovoz yozib olish"</string>
- <string name="permgrouplab_camerawear" msgid="4543951283103407017">"rasmga tushirish va videoga olish"</string>
+ <string name="permgrouplab_camerawear" msgid="4543951283103407017">"suratga olish va video yozib olish"</string>
<string name="permgrouplab_phonewear" msgid="134365036753766126">"telefon qo‘ng‘iroqlarini amalga oshirish va boshqarish"</string>
- <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"asosiy belgilaringiz haqidagi sezgich ma’lumotlaridan foydalanishga ruxsat"</string>
+ <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"organizm holati haqidagi sezgich ma’lumotlariga kirish"</string>
<string name="permlab_statusBarServicewear" msgid="2469402818964691034">"holat qatorida ko‘rinishi"</string>
<string name="permlab_bodySensorswear" msgid="7857941041202791873">"tana sezgichlari (m-n, yurak urishi sensori) ma’lumotlaridan foydalanishga ruxsat"</string>
<string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"aniq joylashuv (GPS va tarmoqqa asoslanib) ma’lumotlaridan foydalanishga ruxsat"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 325ad919694f..b7ae9921460c 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -231,19 +231,19 @@
<string name="permgrouplab_location" msgid="7275582855722310164">"Joylashuv"</string>
<string name="permgroupdesc_location" msgid="1346617465127855033">"qurilmaning joylashuvi haqidagi ma’lumotlarga kirish"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Taqvim"</string>
- <string name="permgroupdesc_calendar" msgid="3889615280211184106">"taqvimga kirish"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"taqvim ma’lumotlariga kirish"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS xabarlarni yuborish va ko‘rish"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Xotira"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"qurilmangizdagi rasm, media va fayllarga kirish"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"qurilmangizdagi rasm, multimedia va fayllarga kirish"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"ovoz yozib olish"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
- <string name="permgroupdesc_camera" msgid="3250611594678347720">"rasm va videoga olish"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"suratga olish va video yozib olish"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"telefon qo‘ng‘iroqlarini amalga oshirish va boshqarish"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Tana sezgichlari"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"asosiy belgilaringiz haqidagi sezgich ma’lumotlariga kirish"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"organizm holati haqidagi sezgich ma’lumotlariga kirish"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Oynadagi kontentni o‘qiydi"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Joriy oynadagi kontent mazmunini aniqlaydi."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Teginib o‘rganish xizmatini yoqadi"</string>
@@ -342,7 +342,7 @@
<string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Ilovaga sizning taxminiy joylashuvingizni topishga ruxsat beradi. Ushbu joylashuv Wi-Fi va uyali tarmoq antennalari kabi tarmoq joylashuv manbalaridan foydlanuvchi joylashuv xizmatlari orqali aniqlanadi. Ushbu joylashuv xizmatlari yoqib qo‘yilgan bo‘lishi va qurilmangizdagi ilovaga ulardan foydalanish uchun mavjud bo‘lishi kerak. Ilovalar bundan foydalanib, sizning taxminiy joylashuvingizni aniqlaydi."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"audio sozlamalaringizni o‘zgartirish"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Ilovalarga tovush va ovoz chiqarish uchun foydalaniladigan karnay kabi global audio sozlamalarini o‘zgartirish uchun ruxsat beradi."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"audioni yozib olish"</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"ovoz yozib olish"</string>
<string name="permdesc_recordAudio" msgid="4906839301087980680">"Ilovaga mikrofon yordamida audio yozish uchun ruxsat beradi. Bu huquq ilovaga ruxsatingizsiz audio fayllarni yozib olishga ruxsat beradi."</string>
<string name="permlab_sim_communication" msgid="1180265879464893029">"sim orqali ulanish"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"Dasturga SIM kartaga buyruqlar jo‘natishga ruxsat beradi. Bu juda ham xavfli."</string>
@@ -797,9 +797,9 @@
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"space"</string>
<string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
<string name="menu_delete_shortcut_label" msgid="3658178007202748164">"delete"</string>
- <string name="search_go" msgid="8298016669822141719">"Izlash"</string>
+ <string name="search_go" msgid="8298016669822141719">"Qidirish"</string>
<string name="search_hint" msgid="1733947260773056054">"Qidirish…"</string>
- <string name="searchview_description_search" msgid="6749826639098512120">"Izlash"</string>
+ <string name="searchview_description_search" msgid="6749826639098512120">"Qidirish"</string>
<string name="searchview_description_query" msgid="5911778593125355124">"Qidiruv so‘rovi"</string>
<string name="searchview_description_clear" msgid="1330281990951833033">"So‘rovni tozalash"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"So‘rov yaratish"</string>
@@ -1082,7 +1082,7 @@
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Masshtabni o‘zgartirish uchun ikki marta bosing"</string>
<string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidjet qo‘shilmadi."</string>
<string name="ime_action_go" msgid="8320845651737369027">"O‘tish"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Izlash"</string>
+ <string name="ime_action_search" msgid="658110271822807811">"Qidirish"</string>
<string name="ime_action_send" msgid="2316166556349314424">"Jo‘natish"</string>
<string name="ime_action_next" msgid="3138843904009813834">"Keyingi"</string>
<string name="ime_action_done" msgid="8971516117910934605">"Tayyor"</string>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 41b05ea8757a..919519e5832a 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -54,4 +54,7 @@
<!-- Do not show the message saying USB is connected in charging mode. -->
<bool name="config_usbChargingMessage">false</bool>
+
+ <!-- Use a custom transition for RemoteViews. -->
+ <bool name="config_overrideRemoteViewsActivityTransition">true</bool>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index dc96df4e9d7c..a6eb68b73baa 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -162,6 +162,9 @@
<!-- Text color, typeface, size, and style for small text inside of a popup menu. -->
<attr name="textAppearanceSmallPopupMenu" format="reference" />
+ <!-- Text color, typeface, size, and style for header text inside of a popup menu. -->
+ <attr name="textAppearancePopupMenuHeader" format="reference" />
+
<!-- The underline color and thickness for easy correct suggestion -->
<attr name="textAppearanceEasyCorrectSuggestion" format="reference" />
@@ -729,6 +732,8 @@ i
<attr name="listPopupWindowStyle" format="reference" />
<!-- Default PopupMenu style. -->
<attr name="popupMenuStyle" format="reference" />
+ <!-- Default context menu PopupMenu style. -->
+ <attr name="contextPopupMenuStyle" format="reference" />
<!-- Default StackView style. -->
<attr name="stackViewStyle" format="reference" />
@@ -2150,6 +2155,13 @@ i
(which is exiting the screen). The wallpaper remains
static behind the animation. -->
<attr name="wallpaperIntraCloseExitAnimation" format="reference" />
+
+ <!-- When opening a new activity from a RemoteViews, this is the
+ animation that is run on the next activity (which is entering the
+ screen). Requires config_overrideRemoteViewsActivityTransition to
+ be true. -->
+ <attr name="activityOpenRemoteViewsEnterAnimation" format="reference" />
+
</declare-styleable>
<!-- ============================= -->
diff --git a/core/res/res/values/colors_holo.xml b/core/res/res/values/colors_holo.xml
index c29fec652652..9d1dda547586 100644
--- a/core/res/res/values/colors_holo.xml
+++ b/core/res/res/values/colors_holo.xml
@@ -79,8 +79,7 @@
<eat-comment />
<color name="holo_primary_dark">#ff000000</color>
- <color name="holo_primary">#ffe6e6e6</color>
- <color name="holo_primary_light">#ffffffff</color>
+ <color name="holo_primary">#ff222222</color>
<color name="holo_control_activated">@color/holo_blue_light</color>
<color name="holo_control_normal">#39cccccc</color>
<color name="holo_button_pressed">#59f0f0f0</color>
@@ -88,8 +87,7 @@
<color name="holo_light_primary_dark">#ff000000</color>
<color name="holo_light_primary">#ffe6e6e6</color>
- <color name="holo_light_primary_light">#ffffffff</color>
- <color name="holo_light_control_activated">@color/holo_control_activated</color>
+ <color name="holo_light_control_activated">@color/holo_blue_light</color>
<color name="holo_light_control_normal">#dacccccc</color>
<color name="holo_light_button_pressed">#66666666</color>
<color name="holo_light_button_normal">#b3cccccc</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9b1a613894d9..24d760fddbf8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2214,6 +2214,10 @@
<bool name="config_defaultWindowFeatureOptionsPanel">true</bool>
<bool name="config_defaultWindowFeatureContextMenu">true</bool>
+ <!-- If true, the transition for a RemoteViews is read from a resource instead of using the
+ default scale-up transition. -->
+ <bool name="config_overrideRemoteViewsActivityTransition">false</bool>
+
<!-- This config is used to check if the carrier requires converting destination
number before sending out a SMS.
Formats for this configuration as below:
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 55bea9e38291..96a81d138457 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -72,6 +72,7 @@
<dimen name="text_size_title_material_toolbar">20dp</dimen>
<dimen name="text_size_subtitle_material_toolbar">16dp</dimen>
<dimen name="text_size_menu_material">16sp</dimen>
+ <dimen name="text_size_menu_header_material">14sp</dimen>
<dimen name="text_size_body_2_material">14sp</dimen>
<dimen name="text_size_body_1_material">14sp</dimen>
<dimen name="text_size_caption_material">12sp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 89d9babbbc1e..f4d0b398561f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2674,6 +2674,8 @@
<public type="attr" name="buttonGravity" />
<public type="attr" name="collapseIcon" />
<public type="attr" name="level" />
+ <public type="attr" name="contextPopupMenuStyle" />
+ <public type="attr" name="textAppearancePopupMenuHeader" />
<public type="style" name="Theme.Material.DayNight" />
<public type="style" name="Theme.Material.DayNight.DarkActionBar" />
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 611b17148158..58640eb2ef55 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -307,6 +307,11 @@ please see styles_device_defaults.xml.
<style name="TextAppearance.Material.Widget.PopupMenu"/>
<style name="TextAppearance.Material.Widget.PopupMenu.Large" parent="TextAppearance.Material.Menu" />
<style name="TextAppearance.Material.Widget.PopupMenu.Small" parent="TextAppearance.Material.Menu" />
+ <style name="TextAppearance.Material.Widget.PopupMenu.Header">
+ <item name="fontFamily">@string/font_family_title_material</item>
+ <item name="textSize">@dimen/text_size_menu_header_material</item>
+ <item name="textColor">?attr/textColorSecondary</item>
+ </style>
<style name="TextAppearance.Material.Widget.DropDownHint" parent="TextAppearance.Material.Menu" />
@@ -863,6 +868,11 @@ please see styles_device_defaults.xml.
<item name="dropDownHorizontalOffset">-4dip</item>
</style>
+ <style name="Widget.Material.ContextPopupMenu" parent="Widget.Material.ListPopupWindow">
+ <item name="overlapAnchor">true</item>
+ <item name="popupEnterTransition">@null</item>
+ </style>
+
<style name="Widget.Material.ActionButton">
<item name="background">?attr/actionBarItemBackground</item>
<item name="paddingStart">12dp</item>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index c6052fffd2e2..05835e7b41ab 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -18,6 +18,7 @@
<style name="Animation.Micro.Activity" parent="Animation.Material.Activity">
<item name="activityOpenEnterAnimation">@anim/slide_in_micro</item>
+ <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_micro</item>
<item name="activityOpenExitAnimation">@null</item>
<item name="activityCloseEnterAnimation">@null</item>
<item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b5efbfd2462a..06de81d1081e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1290,6 +1290,7 @@
<java-symbol type="layout" name="number_picker" />
<java-symbol type="layout" name="permissions_package_list_item" />
<java-symbol type="layout" name="popup_menu_item_layout" />
+ <java-symbol type="layout" name="popup_menu_header_item_layout" />
<java-symbol type="layout" name="remote_views_adapter_default_loading_view" />
<java-symbol type="layout" name="search_bar" />
<java-symbol type="layout" name="search_dropdown_item_icons_2line" />
@@ -2191,6 +2192,7 @@
<java-symbol type="bool" name="config_sms_force_7bit_encoding" />
<java-symbol type="bool" name="config_defaultWindowFeatureOptionsPanel" />
<java-symbol type="bool" name="config_defaultWindowFeatureContextMenu" />
+ <java-symbol type="bool" name="config_overrideRemoteViewsActivityTransition" />
<java-symbol type="layout" name="simple_account_item" />
<java-symbol type="array" name="config_sms_convert_destination_number_support" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 30101909f0b4..59dfc921c392 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -93,6 +93,7 @@ please see themes_device_defaults.xml.
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Small</item>
+ <item name="textAppearancePopupMenuHeader">@style/TextAppearance.Material.Widget.PopupMenu.Header</item>
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.Material.Button</item>
@@ -283,6 +284,7 @@ please see themes_device_defaults.xml.
<item name="stackViewStyle">@style/Widget.Material.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Material.ActivityChooserView</item>
<item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item>
+ <item name="contextPopupMenuStyle">@style/Widget.Material.ContextPopupMenu</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
@@ -449,6 +451,7 @@ please see themes_device_defaults.xml.
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Small</item>
+ <item name="textAppearancePopupMenuHeader">@style/TextAppearance.Material.Widget.PopupMenu.Header</item>
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.Material.Light.Button</item>
@@ -640,6 +643,7 @@ please see themes_device_defaults.xml.
<item name="stackViewStyle">@style/Widget.Material.Light.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Material.Light.ActivityChooserView</item>
<item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item>
+ <item name="contextPopupMenuStyle">@style/Widget.Material.ContextPopupMenu</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index ce9ae02c9cec..4db1d9a56c47 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -18,8 +18,12 @@ package android.widget;
import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
+import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex;
import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
+import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
+import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
import static android.widget.espresso.TextViewAssertions.hasSelection;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.pressKey;
@@ -59,6 +63,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
getActivity();
final String helloWorld = "Hello world!";
+ onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world")));
@@ -68,10 +73,39 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
}
@SmallTest
+ public void testLongPressToSelect() throws Exception {
+ getActivity();
+
+ final String helloWorld = "Hello Kirk!";
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(
+ longPressOnTextAtIndex(helloWorld.indexOf("Kirk")));
+
+ onView(withId(R.id.textview)).check(hasSelection("Kirk"));
+ }
+
+ @SmallTest
+ public void testLongPressEmptySpace() throws Exception {
+ getActivity();
+
+ final String helloWorld = "Hello big round sun!";
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ // Move cursor somewhere else
+ onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big")));
+ // Long-press at end of line.
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(helloWorld.length()));
+
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(helloWorld.length()));
+ }
+
+ @SmallTest
public void testLongPressAndDragToSelect() throws Exception {
getActivity();
final String helloWorld = "Hello little handsome boy!";
+ onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
onView(withId(R.id.textview)).perform(
longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
@@ -80,14 +114,60 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
}
@SmallTest
+ public void testDoubleTapToSelect() throws Exception {
+ getActivity();
+
+ final String helloWorld = "Hello SuetYi!";
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(
+ doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi")));
+
+ onView(withId(R.id.textview)).check(hasSelection("SuetYi"));
+ }
+
+ @SmallTest
public void testDoubleTapAndDragToSelect() throws Exception {
getActivity();
final String helloWorld = "Hello young beautiful girl!";
+ onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
onView(withId(R.id.textview)).perform(
doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!")));
onView(withId(R.id.textview)).check(hasSelection("young beautiful"));
}
+
+ @SmallTest
+ public void testSelectBackwordsByTouch() throws Exception {
+ getActivity();
+
+ final String helloWorld = "Hello king of the Jungle!";
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(
+ doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king")));
+
+ onView(withId(R.id.textview)).check(hasSelection("king of the"));
+ }
+
+ @SmallTest
+ public void testToolbarAppearsAfterSelection() throws Exception {
+ getActivity();
+
+ // It'll be nice to check that the toolbar is not visible (or does not exist) here
+ // I can't currently find a way to do this. I'll get to it later.
+
+ final String text = "Toolbar appears after selection.";
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+ onView(withId(R.id.textview)).perform(
+ longPressOnTextAtIndex(text.indexOf("appears")));
+
+ // It takes the toolbar less than 100ms to start to animate into screen.
+ // Ideally, we'll wait using the UiController, but I guess this works for now.
+ Thread.sleep(100);
+ assertFloatingToolbarIsDisplayed(getActivity());
+ }
}
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
new file mode 100644
index 000000000000..fc01d8416df3
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -0,0 +1,49 @@
+/*
+ * 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.widget.espresso;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withTagValue;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+
+import android.app.Activity;
+import com.android.internal.widget.FloatingToolbar;
+
+/**
+ * Espresso utility methods for the floating toolbar.
+ */
+public class FloatingToolbarEspressoUtils {
+
+
+ private FloatingToolbarEspressoUtils() {}
+
+ /**
+ * Asserts that the floating toolbar is displayed on screen.
+ *
+ * @throws AssertionError if the assertion fails
+ */
+ public static void assertFloatingToolbarIsDisplayed(Activity activity) {
+ onView(withTagValue(is((Object) FloatingToolbar.FLOATING_TOOLBAR_TAG)))
+ .inRoot(withDecorView(not(is(activity.getWindow().getDecorView()))))
+ .check(matches(isDisplayed()));
+ }
+
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 7e4735b298fe..835b1b958860 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -52,6 +52,36 @@ public final class TextViewActions {
}
/**
+ * Returns an action that double-clicks on text at an index on the TextView.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ *
+ * @param index The index of the TextView's text to double-click on.
+ */
+ public static ViewAction doubleClickOnTextAtIndex(int index) {
+ return actionWithAssertions(
+ new GeneralClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER));
+ }
+
+ /**
+ * Returns an action that long presses on text at an index on the TextView.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ *
+ * @param index The index of the TextView's text to long press on.
+ */
+ public static ViewAction longPressOnTextAtIndex(int index) {
+ return actionWithAssertions(
+ new GeneralClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
+ }
+
+ /**
* Returns an action that long presses then drags on text from startIndex to endIndex on the
* TextView.<br>
* <br>
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
index dce3182693a6..37c7425ce478 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
@@ -47,7 +47,7 @@ public final class TextViewAssertions {
* @param selection The expected selection.
*/
public static ViewAssertion hasSelection(String selection) {
- return new TextSelectionAssertion(is(selection));
+ return hasSelection(is(selection));
}
/**
@@ -66,6 +66,53 @@ public final class TextViewAssertions {
}
/**
+ * Returns a {@link ViewAssertion} that asserts that the text view insertion pointer is at
+ * a specified index.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a text view displayed on screen
+ * <ul>
+ *
+ * @param index The expected index.
+ */
+ public static ViewAssertion hasInsertionPointerAtIndex(int index) {
+ return hasInsertionPointerAtIndex(is(index));
+ }
+
+ /**
+ * Returns a {@link ViewAssertion} that asserts that the text view insertion pointer is at
+ * a specified index.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a text view displayed on screen
+ * <ul>
+ *
+ * @param index A matcher representing the expected index.
+ */
+ public static ViewAssertion hasInsertionPointerAtIndex(final Matcher<Integer> index) {
+ return new ViewAssertion() {
+ @Override
+ public void check(View view, NoMatchingViewException exception) {
+ if (view instanceof TextView) {
+ TextView textView = (TextView) view;
+ int selectionStart = textView.getSelectionStart();
+ int selectionEnd = textView.getSelectionEnd();
+ try {
+ assertThat(selectionStart, index);
+ assertThat(selectionEnd, index);
+ } catch (IndexOutOfBoundsException e) {
+ throw new AssertionFailedError(e.getMessage());
+ }
+ } else {
+ throw new AssertionFailedError("TextView not found");
+ }
+ }
+ };
+ }
+
+ /**
* A {@link ViewAssertion} to check the selected text in a {@link TextView}.
*/
private static final class TextSelectionAssertion implements ViewAssertion {
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index 9dc0ed154208..22ad0c9c4539 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -665,7 +665,7 @@ page.title=Support Library
<li>Added support for a Collapse icon description in the {@link android.support.v7.widget.Toolbar}
class.</li>
<li>Updated the {@link android.support.v7.widget.SearchView} widget to support displaying
- the {@link android.support.v7.mediarouter.R.attr#commitIcon}. </li>
+ the {@link android.support.v7.appcompat.R.attr#commitIcon}. </li>
<li>Removed the <code>buttonGravity</code> attribute from the
{@link android.support.v7.widget.Toolbar} class. </li>
</ul>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 6582b7e9ef6b..11b4a9e5adf5 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -430,7 +430,7 @@ public class Paint {
* @param flags initial flag bits, as if they were passed via setFlags().
*/
public Paint(int flags) {
- mNativePaint = native_init();
+ mNativePaint = nInit();
setFlags(flags | HIDDEN_DEFAULT_PAINT_FLAGS);
// TODO: Turning off hinting has undesirable side effects, we need to
// revisit hinting once we add support for subpixel positioning
@@ -448,13 +448,14 @@ public class Paint {
* new paint.
*/
public Paint(Paint paint) {
- mNativePaint = native_initWithPaint(paint.getNativeInstance());
+ mNativePaint = nInitWithPaint(paint.getNativeInstance());
setClassVariablesFrom(paint);
}
/** Restores the paint to its default settings. */
public void reset() {
- native_reset(mNativePaint);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nReset(mNativePaint);
setFlags(HIDDEN_DEFAULT_PAINT_FLAGS);
// TODO: Turning off hinting has undesirable side effects, we need to
@@ -488,9 +489,11 @@ public class Paint {
* methods on this.
*/
public void set(Paint src) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ if (src.mNativePaint == 0) throw new NullPointerException("Source is already finalized!");
if (this != src) {
// copy over the native settings
- native_set(mNativePaint, src.mNativePaint);
+ nSet(mNativePaint, src.mNativePaint);
setClassVariablesFrom(src);
}
}
@@ -538,10 +541,11 @@ public class Paint {
* @hide
*/
public long getNativeInstance() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
long newNativeShader = mShader == null ? 0 : mShader.getNativeInstance();
if (newNativeShader != mNativeShader) {
mNativeShader = newNativeShader;
- native_setShader(mNativePaint, mNativeShader);
+ nSetShader(mNativePaint, mNativeShader);
}
return mNativePaint;
}
@@ -574,26 +578,46 @@ public class Paint {
*
* @return the paint's flags (see enums ending in _Flag for bit masks)
*/
- public native int getFlags();
+ public int getFlags() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetFlags(mNativePaint);
+ }
+
+ private native int nGetFlags(long paintPtr);
/**
* Set the paint's flags. Use the Flag enum to specific flag values.
*
* @param flags The new flag bits for the paint
*/
- public native void setFlags(int flags);
+ public void setFlags(int flags) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetFlags(mNativePaint, flags);
+ }
+
+ private native void nSetFlags(long paintPtr, int flags);
/**
* Return the paint's hinting mode. Returns either
* {@link #HINTING_OFF} or {@link #HINTING_ON}.
*/
- public native int getHinting();
+ public int getHinting() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetHinting(mNativePaint);
+ }
+
+ private native int nGetHinting(long paintPtr);
/**
* Set the paint's hinting mode. May be either
* {@link #HINTING_OFF} or {@link #HINTING_ON}.
*/
- public native void setHinting(int mode);
+ public void setHinting(int mode) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetHinting(mNativePaint, mode);
+ }
+
+ private native void nSetHinting(long paintPtr, int mode);
/**
* Helper for getFlags(), returning true if ANTI_ALIAS_FLAG bit is set
@@ -615,7 +639,12 @@ public class Paint {
*
* @param aa true to set the antialias bit in the flags, false to clear it
*/
- public native void setAntiAlias(boolean aa);
+ public void setAntiAlias(boolean aa) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetAntiAlias(mNativePaint, aa);
+ }
+
+ private native void nSetAntiAlias(long paintPtr, boolean aa);
/**
* Helper for getFlags(), returning true if DITHER_FLAG bit is set
@@ -641,7 +670,12 @@ public class Paint {
*
* @param dither true to set the dithering bit in flags, false to clear it
*/
- public native void setDither(boolean dither);
+ public void setDither(boolean dither) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetDither(mNativePaint, dither);
+ }
+
+ private native void nSetDither(long paintPtr, boolean dither);
/**
* Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
@@ -658,7 +692,12 @@ public class Paint {
* @param linearText true to set the linearText bit in the paint's flags,
* false to clear it.
*/
- public native void setLinearText(boolean linearText);
+ public void setLinearText(boolean linearText) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetLinearText(mNativePaint, linearText);
+ }
+
+ private native void nSetLinearText(long paintPtr, boolean linearText);
/**
* Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set
@@ -675,7 +714,12 @@ public class Paint {
* @param subpixelText true to set the subpixelText bit in the paint's
* flags, false to clear it.
*/
- public native void setSubpixelText(boolean subpixelText);
+ public void setSubpixelText(boolean subpixelText) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetSubpixelText(mNativePaint, subpixelText);
+ }
+
+ private native void nSetSubpixelText(long paintPtr, boolean subpixelText);
/**
* Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
@@ -692,7 +736,12 @@ public class Paint {
* @param underlineText true to set the underlineText bit in the paint's
* flags, false to clear it.
*/
- public native void setUnderlineText(boolean underlineText);
+ public void setUnderlineText(boolean underlineText) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetUnderlineText(mNativePaint, underlineText);
+ }
+
+ private native void nSetUnderlineText(long paintPtr, boolean underlineText);
/**
* Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set
@@ -709,7 +758,12 @@ public class Paint {
* @param strikeThruText true to set the strikeThruText bit in the paint's
* flags, false to clear it.
*/
- public native void setStrikeThruText(boolean strikeThruText);
+ public void setStrikeThruText(boolean strikeThruText) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetStrikeThruText(mNativePaint, strikeThruText);
+ }
+
+ private native void nSetStrikeThruText(long paintPtr, boolean strikeThruText);
/**
* Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set
@@ -726,7 +780,12 @@ public class Paint {
* @param fakeBoldText true to set the fakeBoldText bit in the paint's
* flags, false to clear it.
*/
- public native void setFakeBoldText(boolean fakeBoldText);
+ public void setFakeBoldText(boolean fakeBoldText) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetFakeBoldText(mNativePaint, fakeBoldText);
+ }
+
+ private native void nSetFakeBoldText(long paintPtr, boolean fakeBoldText);
/**
* Whether or not the bitmap filter is activated.
@@ -749,7 +808,12 @@ public class Paint {
* @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
* flags, false to clear it.
*/
- public native void setFilterBitmap(boolean filter);
+ public void setFilterBitmap(boolean filter) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetFilterBitmap(mNativePaint, filter);
+ }
+
+ private native void nSetFilterBitmap(long paintPtr, boolean filter);
/**
* Return the paint's style, used for controlling how primitives'
@@ -759,7 +823,8 @@ public class Paint {
* @return the paint's style setting (Fill, Stroke, StrokeAndFill)
*/
public Style getStyle() {
- return sStyleArray[native_getStyle(mNativePaint)];
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return sStyleArray[nGetStyle(mNativePaint)];
}
/**
@@ -770,7 +835,8 @@ public class Paint {
* @param style The new style to set in the paint
*/
public void setStyle(Style style) {
- native_setStyle(mNativePaint, style.nativeInt);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetStyle(mNativePaint, style.nativeInt);
}
/**
@@ -782,7 +848,12 @@ public class Paint {
* @return the paint's color (and alpha).
*/
@ColorInt
- public native int getColor();
+ public int getColor() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetColor(mNativePaint);
+ }
+
+ private native int nGetColor(long paintPtr);
/**
* Set the paint's color. Note that the color is an int containing alpha
@@ -792,7 +863,12 @@ public class Paint {
*
* @param color The new color (including alpha) to set in the paint.
*/
- public native void setColor(@ColorInt int color);
+ public void setColor(@ColorInt int color) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetColor(mNativePaint, color);
+ }
+
+ private native void nSetColor(long paintPtr, @ColorInt int color);
/**
* Helper to getColor() that just returns the color's alpha value. This is
@@ -801,7 +877,12 @@ public class Paint {
*
* @return the alpha component of the paint's color.
*/
- public native int getAlpha();
+ public int getAlpha() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetAlpha(mNativePaint);
+ }
+
+ private native int nGetAlpha(long paintPtr);
/**
* Helper to setColor(), that only assigns the color's alpha value,
@@ -810,7 +891,12 @@ public class Paint {
*
* @param a set the alpha component [0..255] of the paint's color.
*/
- public native void setAlpha(int a);
+ public void setAlpha(int a) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetAlpha(mNativePaint, a);
+ }
+
+ private native void nSetAlpha(long paintPtr, int a);
/**
* Helper to setColor(), that takes a,r,g,b and constructs the color int
@@ -833,7 +919,12 @@ public class Paint {
* @return the paint's stroke width, used whenever the paint's style is
* Stroke or StrokeAndFill.
*/
- public native float getStrokeWidth();
+ public float getStrokeWidth() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetStrokeWidth(mNativePaint);
+ }
+
+ private native float nGetStrokeWidth(long paintPtr);
/**
* Set the width for stroking.
@@ -843,7 +934,12 @@ public class Paint {
* @param width set the paint's stroke width, used whenever the paint's
* style is Stroke or StrokeAndFill.
*/
- public native void setStrokeWidth(float width);
+ public void setStrokeWidth(float width) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetStrokeWidth(mNativePaint, width);
+ }
+
+ private native void nSetStrokeWidth(long paintPtr, float width);
/**
* Return the paint's stroke miter value. Used to control the behavior
@@ -852,7 +948,12 @@ public class Paint {
* @return the paint's miter limit, used whenever the paint's style is
* Stroke or StrokeAndFill.
*/
- public native float getStrokeMiter();
+ public float getStrokeMiter() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetStrokeMiter(mNativePaint);
+ }
+
+ private native float nGetStrokeMiter(long paintPtr);
/**
* Set the paint's stroke miter value. This is used to control the behavior
@@ -861,7 +962,12 @@ public class Paint {
* @param miter set the miter limit on the paint, used whenever the paint's
* style is Stroke or StrokeAndFill.
*/
- public native void setStrokeMiter(float miter);
+ public void setStrokeMiter(float miter) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetStrokeMiter(mNativePaint, miter);
+ }
+
+ private native void nSetStrokeMiter(long paintPtr, float miter);
/**
* Return the paint's Cap, controlling how the start and end of stroked
@@ -871,7 +977,8 @@ public class Paint {
* style is Stroke or StrokeAndFill.
*/
public Cap getStrokeCap() {
- return sCapArray[native_getStrokeCap(mNativePaint)];
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return sCapArray[nGetStrokeCap(mNativePaint)];
}
/**
@@ -881,7 +988,8 @@ public class Paint {
* style is Stroke or StrokeAndFill.
*/
public void setStrokeCap(Cap cap) {
- native_setStrokeCap(mNativePaint, cap.nativeInt);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetStrokeCap(mNativePaint, cap.nativeInt);
}
/**
@@ -890,7 +998,8 @@ public class Paint {
* @return the paint's Join.
*/
public Join getStrokeJoin() {
- return sJoinArray[native_getStrokeJoin(mNativePaint)];
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return sJoinArray[nGetStrokeJoin(mNativePaint)];
}
/**
@@ -900,7 +1009,8 @@ public class Paint {
* Stroke or StrokeAndFill.
*/
public void setStrokeJoin(Join join) {
- native_setStrokeJoin(mNativePaint, join.nativeInt);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetStrokeJoin(mNativePaint, join.nativeInt);
}
/**
@@ -915,7 +1025,8 @@ public class Paint {
* drawn with a hairline (width == 0)
*/
public boolean getFillPath(Path src, Path dst) {
- return native_getFillPath(mNativePaint, src.ni(), dst.ni());
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetFillPath(mNativePaint, src.ni(), dst.ni());
}
/**
@@ -958,10 +1069,11 @@ public class Paint {
* @return filter
*/
public ColorFilter setColorFilter(ColorFilter filter) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
long filterNative = 0;
if (filter != null)
filterNative = filter.native_instance;
- native_setColorFilter(mNativePaint, filterNative);
+ nSetColorFilter(mNativePaint, filterNative);
mColorFilter = filter;
return filter;
}
@@ -985,10 +1097,11 @@ public class Paint {
* @return xfermode
*/
public Xfermode setXfermode(Xfermode xfermode) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
long xfermodeNative = 0;
if (xfermode != null)
xfermodeNative = xfermode.native_instance;
- native_setXfermode(mNativePaint, xfermodeNative);
+ nSetXfermode(mNativePaint, xfermodeNative);
mXfermode = xfermode;
return xfermode;
}
@@ -1012,11 +1125,12 @@ public class Paint {
* @return effect
*/
public PathEffect setPathEffect(PathEffect effect) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
long effectNative = 0;
if (effect != null) {
effectNative = effect.native_instance;
}
- native_setPathEffect(mNativePaint, effectNative);
+ nSetPathEffect(mNativePaint, effectNative);
mPathEffect = effect;
return effect;
}
@@ -1041,11 +1155,12 @@ public class Paint {
* @return maskfilter
*/
public MaskFilter setMaskFilter(MaskFilter maskfilter) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
long maskfilterNative = 0;
if (maskfilter != null) {
maskfilterNative = maskfilter.native_instance;
}
- native_setMaskFilter(mNativePaint, maskfilterNative);
+ nSetMaskFilter(mNativePaint, maskfilterNative);
mMaskFilter = maskfilter;
return maskfilter;
}
@@ -1072,11 +1187,12 @@ public class Paint {
* @return typeface
*/
public Typeface setTypeface(Typeface typeface) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
long typefaceNative = 0;
if (typeface != null) {
typefaceNative = typeface.native_instance;
}
- native_setTypeface(mNativePaint, typefaceNative);
+ nSetTypeface(mNativePaint, typefaceNative);
mTypeface = typeface;
mNativeTypeface = typefaceNative;
return typeface;
@@ -1110,11 +1226,12 @@ public class Paint {
*/
@Deprecated
public Rasterizer setRasterizer(Rasterizer rasterizer) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
long rasterizerNative = 0;
if (rasterizer != null) {
rasterizerNative = rasterizer.native_instance;
}
- native_setRasterizer(mNativePaint, rasterizerNative);
+ nSetRasterizer(mNativePaint, rasterizerNative);
mRasterizer = rasterizer;
return rasterizer;
}
@@ -1132,7 +1249,8 @@ public class Paint {
* opaque, or the alpha from the shadow color if not.
*/
public void setShadowLayer(float radius, float dx, float dy, int shadowColor) {
- native_setShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
}
/**
@@ -1149,7 +1267,8 @@ public class Paint {
* @hide
*/
public boolean hasShadowLayer() {
- return native_hasShadowLayer(mNativePaint);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nHasShadowLayer(mNativePaint);
}
/**
@@ -1161,7 +1280,8 @@ public class Paint {
* @return the paint's Align value for drawing text.
*/
public Align getTextAlign() {
- return sAlignArray[native_getTextAlign(mNativePaint)];
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return sAlignArray[nGetTextAlign(mNativePaint)];
}
/**
@@ -1173,7 +1293,8 @@ public class Paint {
* @param align set the paint's Align value for drawing text.
*/
public void setTextAlign(Align align) {
- native_setTextAlign(mNativePaint, align.nativeInt);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetTextAlign(mNativePaint, align.nativeInt);
}
/**
@@ -1206,6 +1327,7 @@ public class Paint {
* @param locale the paint's locale value for drawing text, must not be null.
*/
public void setTextLocale(@NonNull Locale locale) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (locale == null) {
throw new IllegalArgumentException("locale cannot be null");
}
@@ -1213,7 +1335,7 @@ public class Paint {
return;
}
mLocales = new LocaleList(locale);
- native_setTextLocale(mNativePaint, locale.toString());
+ nSetTextLocale(mNativePaint, locale.toString());
}
/**
@@ -1244,13 +1366,14 @@ public class Paint {
* @param locales the paint's locale list for drawing text, must not be null or empty.
*/
public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (locales == null || locales.isEmpty()) {
throw new IllegalArgumentException("locales cannot be null or empty");
}
if (locales.equals(mLocales)) return;
mLocales = locales;
// TODO: Pass the whole LocaleList to native code
- native_setTextLocale(mNativePaint, locales.getPrimary().toString());
+ nSetTextLocale(mNativePaint, locales.getPrimary().toString());
}
/**
@@ -1258,7 +1381,12 @@ public class Paint {
*
* @return true if elegant metrics are enabled for text drawing.
*/
- public native boolean isElegantTextHeight();
+ public boolean isElegantTextHeight() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nIsElegantTextHeight(mNativePaint);
+ }
+
+ private native boolean nIsElegantTextHeight(long paintPtr);
/**
* Set the paint's elegant height metrics flag. This setting selects font
@@ -1267,21 +1395,36 @@ public class Paint {
*
* @param elegant set the paint's elegant metrics flag for drawing text.
*/
- public native void setElegantTextHeight(boolean elegant);
+ public void setElegantTextHeight(boolean elegant) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetElegantTextHeight(mNativePaint, elegant);
+ }
+
+ private native void nSetElegantTextHeight(long paintPtr, boolean elegant);
/**
* Return the paint's text size.
*
* @return the paint's text size.
*/
- public native float getTextSize();
+ public float getTextSize() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetTextSize(mNativePaint);
+ }
+
+ private native float nGetTextSize(long paintPtr);
/**
* Set the paint's text size. This value must be > 0
*
* @param textSize set the paint's text size.
*/
- public native void setTextSize(float textSize);
+ public void setTextSize(float textSize) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetTextSize(mNativePaint, textSize);
+ }
+
+ private native void nSetTextSize(long paintPtr, float textSize);
/**
* Return the paint's horizontal scale factor for text. The default value
@@ -1289,7 +1432,12 @@ public class Paint {
*
* @return the paint's scale factor in X for drawing/measuring text
*/
- public native float getTextScaleX();
+ public float getTextScaleX() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetTextScaleX(mNativePaint);
+ }
+
+ private native float nGetTextScaleX(long paintPtr);
/**
* Set the paint's horizontal scale factor for text. The default value
@@ -1298,7 +1446,12 @@ public class Paint {
*
* @param scaleX set the paint's scale in X for drawing/measuring text.
*/
- public native void setTextScaleX(float scaleX);
+ public void setTextScaleX(float scaleX) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetTextScaleX(mNativePaint, scaleX);
+ }
+
+ private native void nSetTextScaleX(long paintPtr, float scaleX);
/**
* Return the paint's horizontal skew factor for text. The default value
@@ -1306,7 +1459,12 @@ public class Paint {
*
* @return the paint's skew factor in X for drawing text.
*/
- public native float getTextSkewX();
+ public float getTextSkewX() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetTextSkewX(mNativePaint);
+ }
+
+ private native float nGetTextSkewX(long paintPtr);
/**
* Set the paint's horizontal skew factor for text. The default value
@@ -1314,7 +1472,12 @@ public class Paint {
*
* @param skewX set the paint's skew factor in X for drawing text.
*/
- public native void setTextSkewX(float skewX);
+ public void setTextSkewX(float skewX) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetTextSkewX(mNativePaint, skewX);
+ }
+
+ private native void nSetTextSkewX(long paintPtr, float skewX);
/**
* Return the paint's letter-spacing for text. The default value
@@ -1323,7 +1486,8 @@ public class Paint {
* @return the paint's letter-spacing for drawing text.
*/
public float getLetterSpacing() {
- return native_getLetterSpacing(mNativePaint);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetLetterSpacing(mNativePaint);
}
/**
@@ -1334,7 +1498,8 @@ public class Paint {
* @param letterSpacing set the paint's letter-spacing for drawing text.
*/
public void setLetterSpacing(float letterSpacing) {
- native_setLetterSpacing(mNativePaint, letterSpacing);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetLetterSpacing(mNativePaint, letterSpacing);
}
/**
@@ -1355,6 +1520,7 @@ public class Paint {
* @param settings the font feature settings string to use, may be null.
*/
public void setFontFeatureSettings(String settings) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (settings != null && settings.equals("")) {
settings = null;
}
@@ -1363,7 +1529,7 @@ public class Paint {
return;
}
mFontFeatureSettings = settings;
- native_setFontFeatureSettings(mNativePaint, settings);
+ nSetFontFeatureSettings(mNativePaint, settings);
}
/**
@@ -1374,7 +1540,8 @@ public class Paint {
* @hide
*/
public int getHyphenEdit() {
- return native_getHyphenEdit(mNativePaint);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetHyphenEdit(mNativePaint);
}
/**
@@ -1386,7 +1553,8 @@ public class Paint {
* @hide
*/
public void setHyphenEdit(int hyphen) {
- native_setHyphenEdit(mNativePaint, hyphen);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ nSetHyphenEdit(mNativePaint, hyphen);
}
/**
@@ -1396,7 +1564,12 @@ public class Paint {
* @return the distance above (negative) the baseline (ascent) based on the
* current typeface and text size.
*/
- public native float ascent();
+ public float ascent() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nAscent(mNativePaint, mNativeTypeface);
+ }
+
+ private native float nAscent(long paintPtr, long typefacePtr);
/**
* Return the distance below (positive) the baseline (descent) based on the
@@ -1405,7 +1578,12 @@ public class Paint {
* @return the distance below (positive) the baseline (descent) based on
* the current typeface and text size.
*/
- public native float descent();
+ public float descent() {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nDescent(mNativePaint, mNativeTypeface);
+ }
+
+ private native float nDescent(long paintPtr, long typefacePtr);
/**
* Class that describes the various metrics for a font at a given text size.
@@ -1447,7 +1625,13 @@ public class Paint {
* the appropriate values given the paint's text attributes.
* @return the font's recommended interline spacing.
*/
- public native float getFontMetrics(FontMetrics metrics);
+ public float getFontMetrics(FontMetrics metrics) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetFontMetrics(mNativePaint, mNativeTypeface, metrics);
+ }
+
+ private native float nGetFontMetrics(long paintPtr,
+ long typefacePtr, FontMetrics metrics);
/**
* Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
@@ -1487,7 +1671,13 @@ public class Paint {
*
* @return the font's interline spacing.
*/
- public native int getFontMetricsInt(FontMetricsInt fmi);
+ public int getFontMetricsInt(FontMetricsInt fmi) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nGetFontMetricsInt(mNativePaint, mNativeTypeface, fmi);
+ }
+
+ private native int nGetFontMetricsInt(long paintPtr,
+ long typefacePtr, FontMetricsInt fmi);
public FontMetricsInt getFontMetricsInt() {
FontMetricsInt fm = new FontMetricsInt();
@@ -1515,6 +1705,7 @@ public class Paint {
* @return The width of the text
*/
public float measureText(char[] text, int index, int count) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -1526,18 +1717,18 @@ public class Paint {
return 0f;
}
if (!mHasCompatScaling) {
- return (float) Math.ceil(native_measureText(text, index, count, mBidiFlags));
+ return (float) Math.ceil(nGetTextAdvances(mNativePaint, mNativeTypeface, text,
+ index, count, index, count, mBidiFlags, null, 0));
}
final float oldSize = getTextSize();
- setTextSize(oldSize*mCompatScaling);
- float w = native_measureText(text, index, count, mBidiFlags);
+ setTextSize(oldSize * mCompatScaling);
+ float w = nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index,
+ count, mBidiFlags, null, 0);
setTextSize(oldSize);
return (float) Math.ceil(w*mInvCompatScaling);
}
- private native float native_measureText(char[] text, int index, int count, int bidiFlags);
-
/**
* Return the width of the text.
*
@@ -1547,6 +1738,7 @@ public class Paint {
* @return The width of the text
*/
public float measureText(String text, int start, int end) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -1558,18 +1750,17 @@ public class Paint {
return 0f;
}
if (!mHasCompatScaling) {
- return (float) Math.ceil(native_measureText(text, start, end, mBidiFlags));
+ return (float) Math.ceil(nGetTextAdvances(mNativePaint, mNativeTypeface, text,
+ start, end, start, end, mBidiFlags, null, 0));
}
-
final float oldSize = getTextSize();
- setTextSize(oldSize*mCompatScaling);
- float w = native_measureText(text, start, end, mBidiFlags);
+ setTextSize(oldSize * mCompatScaling);
+ float w = nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start,
+ end, mBidiFlags, null, 0);
setTextSize(oldSize);
- return (float) Math.ceil(w*mInvCompatScaling);
+ return (float) Math.ceil(w * mInvCompatScaling);
}
- private native float native_measureText(String text, int start, int end, int bidiFlags);
-
/**
* Return the width of the text.
*
@@ -1577,26 +1768,13 @@ public class Paint {
* @return The width of the text
*/
public float measureText(String text) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
-
- if (text.length() == 0) {
- return 0f;
- }
-
- if (!mHasCompatScaling) {
- return (float) Math.ceil(native_measureText(text, mBidiFlags));
- }
- final float oldSize = getTextSize();
- setTextSize(oldSize*mCompatScaling);
- float w = native_measureText(text, mBidiFlags);
- setTextSize(oldSize);
- return (float) Math.ceil(w*mInvCompatScaling);
+ return measureText(text, 0, text.length());
}
- private native float native_measureText(String text, int bidiFlags);
-
/**
* Return the width of the text.
*
@@ -1651,6 +1829,7 @@ public class Paint {
*/
public int breakText(char[] text, int index, int count,
float maxWidth, float[] measuredWidth) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -1662,20 +1841,20 @@ public class Paint {
return 0;
}
if (!mHasCompatScaling) {
- return native_breakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth,
+ return nBreakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth,
mBidiFlags, measuredWidth);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
- int res = native_breakText(mNativePaint, mNativeTypeface, text, index, count,
+ int res = nBreakText(mNativePaint, mNativeTypeface, text, index, count,
maxWidth * mCompatScaling, mBidiFlags, measuredWidth);
setTextSize(oldSize);
if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
return res;
}
- private static native int native_breakText(long native_object, long native_typeface,
+ private static native int nBreakText(long nObject, long nTypeface,
char[] text, int index, int count,
float maxWidth, int bidiFlags, float[] measuredWidth);
@@ -1698,6 +1877,7 @@ public class Paint {
public int breakText(CharSequence text, int start, int end,
boolean measureForwards,
float maxWidth, float[] measuredWidth) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -1746,6 +1926,7 @@ public class Paint {
*/
public int breakText(String text, boolean measureForwards,
float maxWidth, float[] measuredWidth) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -1754,20 +1935,20 @@ public class Paint {
return 0;
}
if (!mHasCompatScaling) {
- return native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+ return nBreakText(mNativePaint, mNativeTypeface, text, measureForwards,
maxWidth, mBidiFlags, measuredWidth);
}
final float oldSize = getTextSize();
setTextSize(oldSize*mCompatScaling);
- int res = native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+ int res = nBreakText(mNativePaint, mNativeTypeface, text, measureForwards,
maxWidth*mCompatScaling, mBidiFlags, measuredWidth);
setTextSize(oldSize);
if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
return res;
}
- private static native int native_breakText(long native_object, long native_typeface,
+ private static native int nBreakText(long nObject, long nTypeface,
String text, boolean measureForwards,
float maxWidth, int bidiFlags, float[] measuredWidth);
@@ -1783,6 +1964,7 @@ public class Paint {
*/
public int getTextWidths(char[] text, int index, int count,
float[] widths) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -1795,17 +1977,20 @@ public class Paint {
return 0;
}
if (!mHasCompatScaling) {
- return native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths);
+ nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count,
+ mBidiFlags, widths, 0);
+ return count;
}
final float oldSize = getTextSize();
- setTextSize(oldSize*mCompatScaling);
- int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths);
+ setTextSize(oldSize * mCompatScaling);
+ nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count,
+ mBidiFlags, widths, 0);
setTextSize(oldSize);
- for (int i=0; i<res; i++) {
+ for (int i = 0; i < count; i++) {
widths[i] *= mInvCompatScaling;
}
- return res;
+ return count;
}
/**
@@ -1860,9 +2045,10 @@ public class Paint {
* @param end The end of the text slice to measure
* @param widths array to receive the advance widths of the characters.
* Must be at least a large as the text.
- * @return the number of unichars in the specified text.
+ * @return the number of code units in the specified text.
*/
public int getTextWidths(String text, int start, int end, float[] widths) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -1877,17 +2063,20 @@ public class Paint {
return 0;
}
if (!mHasCompatScaling) {
- return native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths);
+ nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end,
+ mBidiFlags, widths, 0);
+ return end - start;
}
final float oldSize = getTextSize();
- setTextSize(oldSize*mCompatScaling);
- int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths);
+ setTextSize(oldSize * mCompatScaling);
+ nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end,
+ mBidiFlags, widths, 0);
setTextSize(oldSize);
- for (int i=0; i<res; i++) {
+ for (int i = 0; i < end - start; i++) {
widths[i] *= mInvCompatScaling;
}
- return res;
+ return end - start;
}
/**
@@ -1896,7 +2085,7 @@ public class Paint {
* @param text The text to measure
* @param widths array to receive the advance widths of the characters.
* Must be at least a large as the text.
- * @return the number of unichars in the specified text.
+ * @return the number of code units in the specified text.
*/
public int getTextWidths(String text, float[] widths) {
return getTextWidths(text, 0, text.length(), widths);
@@ -1913,6 +2102,7 @@ public class Paint {
int contextIndex, int contextCount, boolean isRtl, float[] advances,
int advancesIndex) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (chars == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -1929,14 +2119,16 @@ public class Paint {
return 0f;
}
if (!mHasCompatScaling) {
- return native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
- contextIndex, contextCount, isRtl, advances, advancesIndex);
+ return nGetTextAdvances(mNativePaint, mNativeTypeface, chars, index, count,
+ contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
+ advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
- float res = native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
- contextIndex, contextCount, isRtl, advances, advancesIndex);
+ float res = nGetTextAdvances(mNativePaint, mNativeTypeface, chars, index, count,
+ contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
+ advancesIndex);
setTextSize(oldSize);
if (advances != null) {
@@ -1957,7 +2149,7 @@ public class Paint {
public float getTextRunAdvances(CharSequence text, int start, int end,
int contextStart, int contextEnd, boolean isRtl, float[] advances,
int advancesIndex) {
-
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -2039,7 +2231,7 @@ public class Paint {
*/
public float getTextRunAdvances(String text, int start, int end, int contextStart,
int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
-
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -2056,14 +2248,16 @@ public class Paint {
}
if (!mHasCompatScaling) {
- return native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
- contextStart, contextEnd, isRtl, advances, advancesIndex);
+ return nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end,
+ contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
+ advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
- float totalAdvance = native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
- contextStart, contextEnd, isRtl, advances, advancesIndex);
+ float totalAdvance = nGetTextAdvances(mNativePaint, mNativeTypeface, text, start,
+ end, contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
+ advancesIndex);
setTextSize(oldSize);
if (advances != null) {
@@ -2102,6 +2296,7 @@ public class Paint {
*/
public int getTextRunCursor(char[] text, int contextStart, int contextLength,
int dir, int offset, int cursorOpt) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
int contextEnd = contextStart + contextLength;
if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
| (offset - contextStart) | (contextEnd - offset)
@@ -2110,7 +2305,7 @@ public class Paint {
throw new IndexOutOfBoundsException();
}
- return native_getTextRunCursor(mNativePaint, text,
+ return nGetTextRunCursor(mNativePaint, text,
contextStart, contextLength, dir, offset, cursorOpt);
}
@@ -2189,6 +2384,7 @@ public class Paint {
*/
public int getTextRunCursor(String text, int contextStart, int contextEnd,
int dir, int offset, int cursorOpt) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
| (offset - contextStart) | (contextEnd - offset)
| (text.length() - contextEnd) | cursorOpt) < 0)
@@ -2196,7 +2392,7 @@ public class Paint {
throw new IndexOutOfBoundsException();
}
- return native_getTextRunCursor(mNativePaint, text,
+ return nGetTextRunCursor(mNativePaint, text,
contextStart, contextEnd, dir, offset, cursorOpt);
}
@@ -2215,10 +2411,11 @@ public class Paint {
*/
public void getTextPath(char[] text, int index, int count,
float x, float y, Path path) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if ((index | count) < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
- native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, index, count, x, y,
+ nGetTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, index, count, x, y,
path.ni());
}
@@ -2237,10 +2434,11 @@ public class Paint {
*/
public void getTextPath(String text, int start, int end,
float x, float y, Path path) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
- native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y,
+ nGetTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y,
path.ni());
}
@@ -2255,13 +2453,14 @@ public class Paint {
* allocated by the caller.
*/
public void getTextBounds(String text, int start, int end, Rect bounds) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
if (bounds == null) {
throw new NullPointerException("need bounds Rect");
}
- nativeGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds);
+ nGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds);
}
/**
@@ -2275,13 +2474,14 @@ public class Paint {
* allocated by the caller.
*/
public void getTextBounds(char[] text, int index, int count, Rect bounds) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if ((index | count) < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
if (bounds == null) {
throw new NullPointerException("need bounds Rect");
}
- nativeGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags,
+ nGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags,
bounds);
}
@@ -2302,7 +2502,8 @@ public class Paint {
* @return true if the typeface has a glyph for the string
*/
public boolean hasGlyph(String string) {
- return native_hasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string);
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+ return nHasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string);
}
/**
@@ -2343,6 +2544,7 @@ public class Paint {
*/
public float getRunAdvance(char[] text, int start, int end, int contextStart, int contextEnd,
boolean isRtl, int offset) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -2355,7 +2557,7 @@ public class Paint {
return 0.0f;
}
// TODO: take mCompatScaling into account (or eliminate compat scaling)?
- return native_getRunAdvance(mNativePaint, mNativeTypeface, text, start, end,
+ return nGetRunAdvance(mNativePaint, mNativeTypeface, text, start, end,
contextStart, contextEnd, isRtl, offset);
}
@@ -2373,6 +2575,7 @@ public class Paint {
*/
public float getRunAdvance(CharSequence text, int start, int end, int contextStart,
int contextEnd, boolean isRtl, int offset) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -2423,6 +2626,7 @@ public class Paint {
*/
public int getOffsetForAdvance(char[] text, int start, int end, int contextStart,
int contextEnd, boolean isRtl, float advance) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -2432,7 +2636,7 @@ public class Paint {
throw new IndexOutOfBoundsException();
}
// TODO: take mCompatScaling into account (or eliminate compat scaling)?
- return native_getOffsetForAdvance(mNativePaint, mNativeTypeface, text, start, end,
+ return nGetOffsetForAdvance(mNativePaint, mNativeTypeface, text, start, end,
contextStart, contextEnd, isRtl, advance);
}
@@ -2450,6 +2654,7 @@ public class Paint {
*/
public int getOffsetForAdvance(CharSequence text, int start, int end, int contextStart,
int contextEnd, boolean isRtl, float advance) {
+ if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
@@ -2470,95 +2675,88 @@ public class Paint {
@Override
protected void finalize() throws Throwable {
try {
- finalizer(mNativePaint);
- mNativePaint = 0;
+ if (mNativePaint != 0) {
+ nFinalizer(mNativePaint);
+ mNativePaint = 0;
+ }
} finally {
super.finalize();
}
}
- private static native long native_init();
- private static native long native_initWithPaint(long paint);
- private static native void native_reset(long native_object);
- private static native void native_set(long native_dst, long native_src);
- private static native int native_getStyle(long native_object);
- private static native void native_setStyle(long native_object, int style);
- private static native int native_getStrokeCap(long native_object);
- private static native void native_setStrokeCap(long native_object, int cap);
- private static native int native_getStrokeJoin(long native_object);
- private static native void native_setStrokeJoin(long native_object,
+ private static native long nInit();
+ private static native long nInitWithPaint(long paint);
+ private static native void nReset(long paintPtr);
+ private static native void nSet(long paintPtrDest, long paintPtrSrc);
+ private static native int nGetStyle(long paintPtr);
+ private static native void nSetStyle(long paintPtr, int style);
+ private static native int nGetStrokeCap(long paintPtr);
+ private static native void nSetStrokeCap(long paintPtr, int cap);
+ private static native int nGetStrokeJoin(long paintPtr);
+ private static native void nSetStrokeJoin(long paintPtr,
int join);
- private static native boolean native_getFillPath(long native_object,
+ private static native boolean nGetFillPath(long paintPtr,
long src, long dst);
- private static native long native_setShader(long native_object, long shader);
- private static native long native_setColorFilter(long native_object,
+ private static native long nSetShader(long paintPtr, long shader);
+ private static native long nSetColorFilter(long paintPtr,
long filter);
- private static native long native_setXfermode(long native_object,
+ private static native long nSetXfermode(long paintPtr,
long xfermode);
- private static native long native_setPathEffect(long native_object,
+ private static native long nSetPathEffect(long paintPtr,
long effect);
- private static native long native_setMaskFilter(long native_object,
+ private static native long nSetMaskFilter(long paintPtr,
long maskfilter);
- private static native long native_setTypeface(long native_object,
+ private static native long nSetTypeface(long paintPtr,
long typeface);
- private static native long native_setRasterizer(long native_object,
+ private static native long nSetRasterizer(long paintPtr,
long rasterizer);
- private static native int native_getTextAlign(long native_object);
- private static native void native_setTextAlign(long native_object,
+ private static native int nGetTextAlign(long paintPtr);
+ private static native void nSetTextAlign(long paintPtr,
int align);
- private static native void native_setTextLocale(long native_object,
+ private static native void nSetTextLocale(long paintPtr,
String locale);
- private static native int native_getTextWidths(long native_object, long native_typeface,
- char[] text, int index, int count, int bidiFlags, float[] widths);
- private static native int native_getTextWidths(long native_object, long native_typeface,
- String text, int start, int end, int bidiFlags, float[] widths);
-
- private static native int native_getTextGlyphs(long native_object,
- String text, int start, int end, int contextStart, int contextEnd,
- int flags, char[] glyphs);
-
- private static native float native_getTextRunAdvances(long native_object, long native_typeface,
+ private static native float nGetTextAdvances(long paintPtr, long typefacePtr,
char[] text, int index, int count, int contextIndex, int contextCount,
- boolean isRtl, float[] advances, int advancesIndex);
- private static native float native_getTextRunAdvances(long native_object, long native_typeface,
+ int bidiFlags, float[] advances, int advancesIndex);
+ private static native float nGetTextAdvances(long paintPtr, long typefacePtr,
String text, int start, int end, int contextStart, int contextEnd,
- boolean isRtl, float[] advances, int advancesIndex);
+ int bidiFlags, float[] advances, int advancesIndex);
- private native int native_getTextRunCursor(long native_object, char[] text,
+ private native int nGetTextRunCursor(long paintPtr, char[] text,
int contextStart, int contextLength, int dir, int offset, int cursorOpt);
- private native int native_getTextRunCursor(long native_object, String text,
+ private native int nGetTextRunCursor(long paintPtr, String text,
int contextStart, int contextEnd, int dir, int offset, int cursorOpt);
- private static native void native_getTextPath(long native_object, long native_typeface,
+ private static native void nGetTextPath(long paintPtr, long typefacePtr,
int bidiFlags, char[] text, int index, int count, float x, float y, long path);
- private static native void native_getTextPath(long native_object, long native_typeface,
+ private static native void nGetTextPath(long paintPtr, long typefacePtr,
int bidiFlags, String text, int start, int end, float x, float y, long path);
- private static native void nativeGetStringBounds(long nativePaint, long native_typeface,
+ private static native void nGetStringBounds(long nativePaint, long typefacePtr,
String text, int start, int end, int bidiFlags, Rect bounds);
- private static native void nativeGetCharArrayBounds(long nativePaint, long native_typeface,
+ private static native void nGetCharArrayBounds(long nativePaint, long typefacePtr,
char[] text, int index, int count, int bidiFlags, Rect bounds);
- private static native void finalizer(long nativePaint);
+ private static native void nFinalizer(long nativePaint);
- private static native void native_setShadowLayer(long native_object,
+ private static native void nSetShadowLayer(long paintPtr,
float radius, float dx, float dy, int color);
- private static native boolean native_hasShadowLayer(long native_object);
+ private static native boolean nHasShadowLayer(long paintPtr);
- private static native float native_getLetterSpacing(long native_object);
- private static native void native_setLetterSpacing(long native_object,
+ private static native float nGetLetterSpacing(long paintPtr);
+ private static native void nSetLetterSpacing(long paintPtr,
float letterSpacing);
- private static native void native_setFontFeatureSettings(long native_object,
+ private static native void nSetFontFeatureSettings(long paintPtr,
String settings);
- private static native int native_getHyphenEdit(long native_object);
- private static native void native_setHyphenEdit(long native_object, int hyphen);
- private static native boolean native_hasGlyph(long native_object, long native_typeface,
+ private static native int nGetHyphenEdit(long paintPtr);
+ private static native void nSetHyphenEdit(long paintPtr, int hyphen);
+ private static native boolean nHasGlyph(long paintPtr, long typefacePtr,
int bidiFlags, String string);
- private static native float native_getRunAdvance(long native_object, long native_typeface,
+ private static native float nGetRunAdvance(long paintPtr, long typefacePtr,
char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl,
int offset);
- private static native int native_getOffsetForAdvance(long native_object,
- long native_typeface, char[] text, int start, int end, int contextStart, int contextEnd,
+ private static native int nGetOffsetForAdvance(long paintPtr,
+ long typefacePtr, char[] text, int start, int end, int contextStart, int contextEnd,
boolean isRtl, float advance);
}
diff --git a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
new file mode 100644
index 000000000000..6763dd1970ae
--- /dev/null
+++ b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
@@ -0,0 +1,221 @@
+/*
+ * 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);
+ }
+ }
+}
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index a81ffb9f59fa..018572cabee4 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -44,6 +44,12 @@ namespace uirenderer {
#define DEBUG_COLOR_MERGEDBATCH 0x5f7f7fff
#define DEBUG_COLOR_MERGEDBATCH_SOLO 0x5f7fff7f
+static bool avoidOverdraw() {
+ // Don't avoid overdraw when visualizing it, since that makes it harder to
+ // debug where it's coming from, and when the problem occurs.
+ return !Properties::debugOverdraw;
+};
+
/////////////////////////////////////////////////////////////////////////////////
// Operation Batches
/////////////////////////////////////////////////////////////////////////////////
@@ -495,7 +501,7 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
&& mSaveStack.empty()
&& !state->mRoundRectClipState;
- if (CC_LIKELY(mAvoidOverdraw) && mBatches.size() &&
+ if (CC_LIKELY(avoidOverdraw()) && mBatches.size() &&
state->mClipSideFlags != kClipSide_ConservativeFull &&
deferInfo.opaqueOverBounds && state->mBounds.contains(mBounds)) {
// avoid overdraw by resetting drawing state + discarding drawing ops
@@ -533,7 +539,11 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
if (deferInfo.mergeable) {
// Try to merge with any existing batch with same mergeId.
- if (mMergingBatches[deferInfo.batchId].get(deferInfo.mergeId, targetBatch)) {
+ std::unordered_map<mergeid_t, DrawBatch*>& mergingBatch
+ = mMergingBatches[deferInfo.batchId];
+ auto getResult = mergingBatch.find(deferInfo.mergeId);
+ if (getResult != mergingBatch.end()) {
+ targetBatch = getResult->second;
if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op, state)) {
targetBatch = nullptr;
}
@@ -577,7 +587,8 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
if (deferInfo.mergeable) {
targetBatch = new MergingDrawBatch(deferInfo,
renderer.getViewportWidth(), renderer.getViewportHeight());
- mMergingBatches[deferInfo.batchId].put(deferInfo.mergeId, targetBatch);
+ mMergingBatches[deferInfo.batchId].insert(
+ std::make_pair(deferInfo.mergeId, targetBatch));
} else {
targetBatch = new DrawBatch(deferInfo);
mBatchLookup[deferInfo.batchId] = targetBatch;
@@ -642,7 +653,7 @@ void DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
// save and restore so that reordering doesn't affect final state
renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
- if (CC_LIKELY(mAvoidOverdraw)) {
+ if (CC_LIKELY(avoidOverdraw())) {
for (unsigned int i = 1; i < mBatches.size(); i++) {
if (mBatches[i] && mBatches[i]->coversBounds(mBounds)) {
discardDrawingBatches(i - 1);
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 4f2dca5f3ee1..7873fbdd342a 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -17,9 +17,10 @@
#ifndef ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
#define ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
+#include <unordered_map>
+
#include <utils/Errors.h>
#include <utils/LinearAllocator.h>
-#include <utils/TinyHashMap.h>
#include "Matrix.h"
#include "OpenGLRenderer.h"
@@ -82,8 +83,8 @@ public:
class DeferredDisplayList {
friend struct DeferStateStruct; // used to give access to allocator
public:
- DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) :
- mBounds(bounds), mAvoidOverdraw(avoidOverdraw) {
+ DeferredDisplayList(const Rect& bounds)
+ : mBounds(bounds) {
clear();
}
~DeferredDisplayList() { clear(); }
@@ -151,7 +152,6 @@ private:
// layer space bounds of rendering
Rect mBounds;
- const bool mAvoidOverdraw;
/**
* At defer time, stores the *defer time* savecount of save/saveLayer ops that were deferred, so
@@ -177,7 +177,7 @@ private:
* MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not
* collide, which avoids the need to resolve mergeid collisions.
*/
- TinyHashMap<mergeid_t, DrawBatch*> mMergingBatches[kOpBatch_Count];
+ std::unordered_map<mergeid_t, DrawBatch*> mMergingBatches[kOpBatch_Count];
LinearAllocator mAllocator;
};
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 4ffd4ca0c1fa..96a569649f89 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1431,10 +1431,7 @@ void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t
return;
}
- // Don't avoid overdraw when visualizing, since that makes it harder to
- // debug where it's coming from, and when the problem occurs.
- bool avoidOverdraw = !Properties::debugOverdraw;
- DeferredDisplayList deferredList(mState.currentClipRect(), avoidOverdraw);
+ DeferredDisplayList deferredList(mState.currentClipRect());
DeferStateStruct deferStruct(deferredList, *this, replayFlags);
renderNode->defer(deferStruct, 0);
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9dc5b45a7738..ddfd62141f5d 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -62,7 +62,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
, mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
, mJankTracker(thread.timeLord().frameIntervalNanos())
, mProfiler(mFrames)
- , mContentOverdrawProtectionBounds(0, 0, 0, 0) {
+ , mContentDrawBounds(0, 0, 0, 0) {
mRenderNodes.emplace_back(rootRenderNode);
mRenderThread.renderState().registerCanvasContext(this);
mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
@@ -309,7 +309,7 @@ void CanvasContext::draw() {
Rect outBounds;
// It there are multiple render nodes, they are as follows:
// #0 - backdrop
- // #1 - content (with - and clipped to - bounds mContentOverdrawProtectionBounds)
+ // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds)
// #2 - frame
// Usually the backdrop cannot be seen since it will be entirely covered by the content. While
// resizing however it might become partially visible. The following render loop will crop the
@@ -317,66 +317,72 @@ void CanvasContext::draw() {
// against the backdrop (since that indicates a shrinking of the window) and then the frame
// around everything.
// The bounds of the backdrop against which the content should be clipped.
- Rect backdropBounds = mContentOverdrawProtectionBounds;
+ Rect backdropBounds = mContentDrawBounds;
+ // Usually the contents bounds should be mContentDrawBounds - however - we will
+ // move it towards the fixed edge to give it a more stable appearance (for the moment).
+ Rect contentBounds;
// If there is no content bounds we ignore the layering as stated above and start with 2.
- int layer = mContentOverdrawProtectionBounds.isEmpty() ? 2 : 0;
+ int layer = (mContentDrawBounds.isEmpty() || mRenderNodes.size() <= 2) ? 2 : 0;
// Draw all render nodes. Note that
for (const sp<RenderNode>& node : mRenderNodes) {
if (layer == 0) { // Backdrop.
- // Draw the backdrop clipped to the inverse content bounds.
+ // Draw the backdrop clipped to the inverse content bounds, but assume that the content
+ // was moved to the upper left corner.
const RenderProperties& properties = node->properties();
Rect targetBounds(properties.getLeft(), properties.getTop(),
properties.getRight(), properties.getBottom());
+ // Move the content bounds towards the fixed corner of the backdrop.
+ const int x = targetBounds.left;
+ const int y = targetBounds.top;
+ contentBounds.set(x, y, x + mContentDrawBounds.getWidth(),
+ y + mContentDrawBounds.getHeight());
// Remember the intersection of the target bounds and the intersection bounds against
// which we have to crop the content.
+ backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight());
backdropBounds.intersect(targetBounds);
// Check if we have to draw something on the left side ...
- if (targetBounds.left < mContentOverdrawProtectionBounds.left) {
+ if (targetBounds.left < contentBounds.left) {
mCanvas->save(SkCanvas::kClip_SaveFlag);
if (mCanvas->clipRect(targetBounds.left, targetBounds.top,
- mContentOverdrawProtectionBounds.left, targetBounds.bottom,
+ contentBounds.left, targetBounds.bottom,
SkRegion::kIntersect_Op)) {
mCanvas->drawRenderNode(node.get(), outBounds);
}
// Reduce the target area by the area we have just painted.
- targetBounds.left = std::min(mContentOverdrawProtectionBounds.left,
- targetBounds.right);
+ targetBounds.left = std::min(contentBounds.left, targetBounds.right);
mCanvas->restore();
}
// ... or on the right side ...
- if (targetBounds.right > mContentOverdrawProtectionBounds.right &&
+ if (targetBounds.right > contentBounds.right &&
!targetBounds.isEmpty()) {
mCanvas->save(SkCanvas::kClip_SaveFlag);
- if (mCanvas->clipRect(mContentOverdrawProtectionBounds.right, targetBounds.top,
+ if (mCanvas->clipRect(contentBounds.right, targetBounds.top,
targetBounds.right, targetBounds.bottom,
SkRegion::kIntersect_Op)) {
mCanvas->drawRenderNode(node.get(), outBounds);
}
// Reduce the target area by the area we have just painted.
- targetBounds.right = std::max(targetBounds.left,
- mContentOverdrawProtectionBounds.right);
+ targetBounds.right = std::max(targetBounds.left, contentBounds.right);
mCanvas->restore();
}
// ... or at the top ...
- if (targetBounds.top < mContentOverdrawProtectionBounds.top &&
+ if (targetBounds.top < contentBounds.top &&
!targetBounds.isEmpty()) {
mCanvas->save(SkCanvas::kClip_SaveFlag);
if (mCanvas->clipRect(targetBounds.left, targetBounds.top, targetBounds.right,
- mContentOverdrawProtectionBounds.top,
+ contentBounds.top,
SkRegion::kIntersect_Op)) {
mCanvas->drawRenderNode(node.get(), outBounds);
}
// Reduce the target area by the area we have just painted.
- targetBounds.top = std::min(mContentOverdrawProtectionBounds.top,
- targetBounds.bottom);
+ targetBounds.top = std::min(contentBounds.top, targetBounds.bottom);
mCanvas->restore();
}
// ... or at the bottom.
- if (targetBounds.bottom > mContentOverdrawProtectionBounds.bottom &&
+ if (targetBounds.bottom > contentBounds.bottom &&
!targetBounds.isEmpty()) {
mCanvas->save(SkCanvas::kClip_SaveFlag);
- if (mCanvas->clipRect(targetBounds.left,
- mContentOverdrawProtectionBounds.bottom, targetBounds.right,
+ if (mCanvas->clipRect(targetBounds.left, contentBounds.bottom, targetBounds.right,
targetBounds.bottom, SkRegion::kIntersect_Op)) {
mCanvas->drawRenderNode(node.get(), outBounds);
}
@@ -384,10 +390,17 @@ void CanvasContext::draw() {
}
} else if (layer == 1) { // Content
// It gets cropped against the bounds of the backdrop to stay inside.
- mCanvas->save(SkCanvas::kClip_SaveFlag);
- if (mCanvas->clipRect(backdropBounds.left, backdropBounds.top,
- backdropBounds.right, backdropBounds.bottom,
- SkRegion::kIntersect_Op)) {
+ mCanvas->save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+
+ // We shift and clip the content to match its final location in the window.
+ const float left = mContentDrawBounds.left;
+ const float top = mContentDrawBounds.top;
+ const float dx = backdropBounds.left - left;
+ const float dy = backdropBounds.top - top;
+ const float width = backdropBounds.getWidth();
+ const float height = backdropBounds.getHeight();
+ mCanvas->translate(dx, dy);
+ if (mCanvas->clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op)) {
mCanvas->drawRenderNode(node.get(), outBounds);
}
mCanvas->restore();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 1c3845cac504..e0cbabdc933a 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -126,8 +126,8 @@ public:
mRenderNodes.end());
}
- void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) {
- mContentOverdrawProtectionBounds.set(left, top, right, bottom);
+ void setContentDrawBounds(int left, int top, int right, int bottom) {
+ mContentDrawBounds.set(left, top, right, bottom);
}
private:
@@ -167,7 +167,7 @@ private:
std::set<RenderNode*> mPrefetechedLayers;
// Stores the bounds of the main content.
- Rect mContentOverdrawProtectionBounds;
+ Rect mContentDrawBounds;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index f43a769890a4..26aae90d5990 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -529,15 +529,14 @@ void RenderProxy::drawRenderNode(RenderNode* node) {
staticPostAndWait(task);
}
-CREATE_BRIDGE5(setContentOverdrawProtectionBounds, CanvasContext* context, int left, int top,
+CREATE_BRIDGE5(setContentDrawBounds, CanvasContext* context, int left, int top,
int right, int bottom) {
- args->context->setContentOverdrawProtectionBounds(args->left, args->top, args->right,
- args->bottom);
+ args->context->setContentDrawBounds(args->left, args->top, args->right, args->bottom);
return nullptr;
}
-void RenderProxy::setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) {
- SETUP_TASK(setContentOverdrawProtectionBounds);
+void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom) {
+ SETUP_TASK(setContentDrawBounds);
args->context = mContext;
args->left = left;
args->top = top;
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 046f24ac3f81..d1b62f1f64a6 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -109,7 +109,7 @@ public:
ANDROID_API void addRenderNode(RenderNode* node, bool placeFront);
ANDROID_API void removeRenderNode(RenderNode* node);
ANDROID_API void drawRenderNode(RenderNode* node);
- ANDROID_API void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom);
+ ANDROID_API void setContentDrawBounds(int left, int top, int right, int bottom);
private:
RenderThread& mRenderThread;
diff --git a/libs/hwui/utils/TinyHashMap.h b/libs/hwui/utils/TinyHashMap.h
deleted file mode 100644
index 4ff9a42f6d5d..000000000000
--- a/libs/hwui/utils/TinyHashMap.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_TINYHASHMAP_H
-#define ANDROID_HWUI_TINYHASHMAP_H
-
-#include <utils/BasicHashtable.h>
-
-namespace android {
-namespace uirenderer {
-
-/**
- * A very simple hash map that doesn't allow duplicate keys, overwriting the older entry.
- */
-template <typename TKey, typename TValue>
-class TinyHashMap {
-public:
- typedef key_value_pair_t<TKey, TValue> TEntry;
-
- /**
- * Puts an entry in the hash, removing any existing entry with the same key
- */
- void put(TKey key, TValue value) {
- hash_t hash = android::hash_type(key);
-
- ssize_t index = mTable.find(-1, hash, key);
- if (index != -1) {
- mTable.removeAt(index);
- }
-
- TEntry initEntry(key, value);
- mTable.add(hash, initEntry);
- }
-
- /**
- * Return true if key is in the map, in which case stores the value in the output ref
- */
- bool get(TKey key, TValue& outValue) {
- hash_t hash = android::hash_type(key);
- ssize_t index = mTable.find(-1, hash, key);
- if (index == -1) {
- return false;
- }
- outValue = mTable.entryAt(index).value;
- return true;
- }
-
- void clear() { mTable.clear(); }
-
-private:
- BasicHashtable<TKey, TEntry> mTable;
-};
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_TINYHASHMAP_H
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index 54ad60e4a62d..4b8f81e01a1d 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -18,6 +18,7 @@ package android.media;
import android.os.Parcel;
import android.util.Log;
+import android.util.MathUtils;
import java.util.Calendar;
import java.util.Collections;
@@ -332,7 +333,14 @@ import java.util.TimeZone;
}
// Skip to the next one.
- parcel.setDataPosition(start + size);
+ try {
+ parcel.setDataPosition(MathUtils.addOrThrow(start, size));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Invalid size: " + e.getMessage());
+ error = true;
+ break;
+ }
+
bytesLeft -= size;
++recCount;
}
diff --git a/media/java/android/media/SRTRenderer.java b/media/java/android/media/SRTRenderer.java
index ee4edee3f9f0..a3e2abdaeca2 100644
--- a/media/java/android/media/SRTRenderer.java
+++ b/media/java/android/media/SRTRenderer.java
@@ -165,7 +165,6 @@ class SRTTrack extends WebVttTrack {
return;
}
- final int _ = 0;
for (Cue cue : activeCues) {
TextTrackCue ttc = (TextTrackCue) cue;
@@ -184,7 +183,8 @@ class SRTTrack extends WebVttTrack {
parcel.writeInt(buf.length);
parcel.writeByteArray(buf);
- Message msg = mEventHandler.obtainMessage(MEDIA_TIMED_TEXT, _, _, parcel);
+ Message msg = mEventHandler.obtainMessage(MEDIA_TIMED_TEXT, 0 /* arg1 */, 0 /* arg2 */,
+ parcel);
mEventHandler.sendMessage(msg);
}
activeCues.clear();
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 3cd157e2b74f..95cb5206b9b5 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -18,6 +18,8 @@ package android.mtp;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
/**
@@ -47,7 +49,7 @@ public final class MtpDevice {
/**
* Opens the MTP device. Once the device is open it takes ownership of the
- * {@link android.hardware.usb.UsbDeviceConnection}.
+ * {@link android.hardware.usb.UsbDeviceConnection}.
* The connection will be closed when you call {@link #close()}
* The connection will also be closed if this method fails.
*
@@ -278,6 +280,38 @@ public final class MtpDevice {
return native_send_object_info(info);
}
+ /**
+ * Reads an event from the device. It blocks the current thread until it gets an event.
+ * It throws OperationCanceledException if it is cancelled by signal.
+ *
+ * @param signal signal for cancellation
+ * @return obtained event
+ */
+ public MtpEvent readEvent(CancellationSignal signal) {
+ final int handle = native_submit_event_request();
+
+ if (handle < 0) {
+ throw new IllegalStateException("Other thread is reading an event.");
+ }
+
+ if (signal != null) {
+ signal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
+ @Override
+ public void onCancel() {
+ native_discard_event_request(handle);
+ }
+ });
+ }
+
+ try {
+ return native_reap_event_request(handle);
+ } finally {
+ if (signal != null) {
+ signal.setOnCancelListener(null);
+ }
+ }
+ }
+
// used by the JNI code
private long mNativeContext;
@@ -297,4 +331,7 @@ public final class MtpDevice {
private native boolean native_import_file(int objectHandle, int fd);
private native boolean native_send_object(int objectHandle, int size, int fd);
private native MtpObjectInfo native_send_object_info(MtpObjectInfo info);
+ private native int native_submit_event_request();
+ private native MtpEvent native_reap_event_request(int handle);
+ private native void native_discard_event_request(int handle);
}
diff --git a/media/java/android/mtp/MtpEvent.java b/media/java/android/mtp/MtpEvent.java
new file mode 100644
index 000000000000..0fa7d93e12ca
--- /dev/null
+++ b/media/java/android/mtp/MtpEvent.java
@@ -0,0 +1,31 @@
+/*
+ * 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.mtp;
+
+/**
+ * This class encapsulates information about a MTP event.
+ */
+public class MtpEvent {
+ private int mEventCode;
+
+ /**
+ * Returns event code of MTP event.
+ *
+ * @return event code
+ */
+ public int getEventCode() { return mEventCode; }
+}
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index f11329c7b258..3f4d18386afa 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -46,10 +46,14 @@ static jfieldID field_context;
jclass clazz_deviceInfo;
jclass clazz_storageInfo;
jclass clazz_objectInfo;
+jclass clazz_event;
+jclass clazz_io_exception;
+jclass clazz_operation_canceled_exception;
jmethodID constructor_deviceInfo;
jmethodID constructor_storageInfo;
jmethodID constructor_objectInfo;
+jmethodID constructor_event;
// MtpDeviceInfo fields
static jfieldID field_deviceInfo_manufacturer;
@@ -86,6 +90,9 @@ static jfieldID field_objectInfo_dateCreated;
static jfieldID field_objectInfo_dateModified;
static jfieldID field_objectInfo_keywords;
+// MtpEvent fields
+static jfieldID field_event_eventCode;
+
MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice)
{
return (MtpDevice*)env->GetLongField(javaDevice, field_context);
@@ -488,6 +495,42 @@ android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info)
return result;
}
+static jint android_mtp_MtpDevice_submit_event_request(JNIEnv *env, jobject thiz)
+{
+ MtpDevice* const device = get_device_from_object(env, thiz);
+ if (!device) {
+ env->ThrowNew(clazz_io_exception, "");
+ return -1;
+ }
+ return device->submitEventRequest();
+}
+
+static jobject android_mtp_MtpDevice_reap_event_request(JNIEnv *env, jobject thiz, jint seq)
+{
+ MtpDevice* const device = get_device_from_object(env, thiz);
+ if (!device) {
+ env->ThrowNew(clazz_io_exception, "");
+ return NULL;
+ }
+ const int eventCode = device->reapEventRequest(seq);
+ if (eventCode <= 0) {
+ env->ThrowNew(clazz_operation_canceled_exception, "");
+ return NULL;
+ }
+ jobject result = env->NewObject(clazz_event, constructor_event);
+ env->SetIntField(result, field_event_eventCode, eventCode);
+ return result;
+}
+
+static void android_mtp_MtpDevice_discard_event_request(JNIEnv *env, jobject thiz, jint seq)
+{
+ MtpDevice* const device = get_device_from_object(env, thiz);
+ if (!device) {
+ return;
+ }
+ device->discardEventRequest(seq);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
@@ -513,7 +556,11 @@ static const JNINativeMethod gMethods[] = {
{"native_import_file", "(II)Z",(void *)android_mtp_MtpDevice_import_file_to_fd},
{"native_send_object", "(III)Z",(void *)android_mtp_MtpDevice_send_object},
{"native_send_object_info", "(Landroid/mtp/MtpObjectInfo;)Landroid/mtp/MtpObjectInfo;",
- (void *)android_mtp_MtpDevice_send_object_info}
+ (void *)android_mtp_MtpDevice_send_object_info},
+ {"native_submit_event_request", "()I", (void *)android_mtp_MtpDevice_submit_event_request},
+ {"native_reap_event_request", "(I)Landroid/mtp/MtpEvent;",
+ (void *)android_mtp_MtpDevice_reap_event_request},
+ {"native_discard_event_request", "(I)V", (void *)android_mtp_MtpDevice_discard_event_request},
};
int register_android_mtp_MtpDevice(JNIEnv *env)
@@ -703,6 +750,23 @@ int register_android_mtp_MtpDevice(JNIEnv *env)
}
clazz_objectInfo = (jclass)env->NewGlobalRef(clazz);
+ clazz = env->FindClass("android/mtp/MtpEvent");
+ if (clazz == NULL) {
+ ALOGE("Can't find android/mtp/MtpEvent");
+ return -1;
+ }
+ constructor_event = env->GetMethodID(clazz, "<init>", "()V");
+ if (constructor_event == NULL) {
+ ALOGE("Can't find android/mtp/MtpEvent constructor");
+ return -1;
+ }
+ field_event_eventCode = env->GetFieldID(clazz, "mEventCode", "I");
+ if (field_event_eventCode == NULL) {
+ ALOGE("Can't find MtpObjectInfo.mEventCode");
+ return -1;
+ }
+ clazz_event = (jclass)env->NewGlobalRef(clazz);
+
clazz = env->FindClass("android/mtp/MtpDevice");
if (clazz == NULL) {
ALOGE("Can't find android/mtp/MtpDevice");
@@ -713,6 +777,18 @@ int register_android_mtp_MtpDevice(JNIEnv *env)
ALOGE("Can't find MtpDevice.mNativeContext");
return -1;
}
+ clazz = env->FindClass("java/io/IOException");
+ if (clazz == NULL) {
+ ALOGE("Can't find java.io.IOException");
+ return -1;
+ }
+ clazz_io_exception = (jclass)env->NewGlobalRef(clazz);
+ clazz = env->FindClass("android/os/OperationCanceledException");
+ if (clazz == NULL) {
+ ALOGE("Can't find android.os.OperationCanceledException");
+ return -1;
+ }
+ clazz_operation_canceled_exception = (jclass)env->NewGlobalRef(clazz);
return AndroidRuntime::registerNativeMethods(env,
"android/mtp/MtpDevice", gMethods, NELEM(gMethods));
diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk
index 1b684bb4e28b..175f73007484 100644
--- a/native/graphics/jni/Android.mk
+++ b/native/graphics/jni/Android.mk
@@ -31,7 +31,7 @@ LOCAL_MODULE:= libjnigraphics
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-# TODO: This is to work around b/19059885. Remove after root cause is fixed
+# TODO: This is to work around b/24465209. Remove after root cause is fixed
LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
index 969ec599f00c..6a7dbbdfbc65 100644
--- a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
@@ -18,10 +18,10 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="backup_confirm_title" msgid="827563724209303345">"Copiere de rezervă completă"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"Restabilire completă"</string>
- <string name="backup_confirm_text" msgid="1878021282758896593">"S-a solicitat crearea unei copii de rezervă complete a tuturor datelor pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu aţi solicitat dvs. copierea de rezervă, nu permiteți ca operaţiunea să continue."</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"S-a solicitat crearea unei copii de rezervă complete a tuturor datelor pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu aţi solicitat dvs. copierea de rezervă, nu permiteți ca operațiunea să continue."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"Creaţi copii de rezervă pentru datele dvs."</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Nu creaţi copii de rezervă"</string>
- <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu dvs. aţi solicitat această restabilire, nu permiteți continuarea operaţiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu dvs. aţi solicitat această restabilire, nu permiteți continuarea operațiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Restabiliţi datele dvs."</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Nu restabiliţi"</string>
<string name="current_password_text" msgid="8268189555578298067">"Introduceţi mai jos parola actuală pentru copia de rezervă:"</string>
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index ac6f950a0a82..295cb80ade52 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -3,6 +3,7 @@
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.REMOVE_TASKS" />
+ <uses-permission android:name="android.permission.REORDER_TASKS" />
<application
android:name=".DocumentsApplication"
@@ -49,8 +50,8 @@
</activity>
<activity
- android:name=".FilesActivity"
- android:theme="@style/FilesTheme"
+ android:name=".LauncherActivity"
+ android:theme="@android:style/Theme.NoDisplay"
android:icon="@drawable/ic_files_app"
android:label="@string/files_label"
android:enabled="@bool/productivity_device">
@@ -58,6 +59,17 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
+ </activity>
+
+ <activity
+ android:name=".FilesActivity"
+ android:theme="@style/FilesTheme"
+ android:icon="@drawable/ic_files_app"
+ android:label="@string/files_label"
+ android:documentLaunchMode="intoExisting">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
<intent-filter>
<action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/packages/DocumentsUI/res/layout/drawer_layout.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml
index dec4e923e6ec..0dac0d550eb8 100644
--- a/packages/DocumentsUI/res/layout/drawer_layout.xml
+++ b/packages/DocumentsUI/res/layout/drawer_layout.xml
@@ -14,62 +14,71 @@
limitations under the License.
-->
-<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/drawer_layout"
+<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
+ floating action buttons) to operate correctly. -->
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:id="@+id/coordinator_layout">
- <LinearLayout
+ <android.support.v4.widget.DrawerLayout
+ android:id="@+id/drawer_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <com.android.documentsui.DocumentsToolBar
- android:id="@+id/toolbar"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="?android:attr/actionBarSize"
- android:background="?android:attr/colorPrimary"
- android:elevation="8dp"
- android:theme="?actionBarTheme"
- android:popupTheme="?actionBarPopupTheme">
-
- <Spinner
- android:id="@+id/stack"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="4dp"
- android:overlapAnchor="true" />
-
- </com.android.documentsui.DocumentsToolBar>
-
- <include layout="@layout/directory_cluster"/>
-
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/drawer_roots"
- android:layout_width="256dp"
- android:layout_height="match_parent"
- android:layout_gravity="start"
- android:orientation="vertical"
- android:elevation="16dp"
- android:background="@*android:color/white">
-
- <Toolbar
- android:id="@+id/roots_toolbar"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/actionBarSize"
- android:background="?android:attr/colorPrimary"
- android:elevation="8dp"
- android:theme="?actionBarTheme"
- android:popupTheme="?actionBarPopupTheme" />
-
- <FrameLayout
- android:id="@+id/container_roots"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.android.documentsui.DocumentsToolBar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/actionBarSize"
+ android:background="?android:attr/colorPrimary"
+ android:elevation="8dp"
+ android:theme="?actionBarTheme"
+ android:popupTheme="?actionBarPopupTheme">
+
+ <Spinner
+ android:id="@+id/stack"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:overlapAnchor="true" />
+
+ </com.android.documentsui.DocumentsToolBar>
+
+ <include layout="@layout/directory_cluster"/>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/drawer_roots"
+ android:layout_width="256dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:orientation="vertical"
+ android:elevation="16dp"
+ android:background="@*android:color/white">
+
+ <Toolbar
+ android:id="@+id/roots_toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/actionBarSize"
+ android:background="?android:attr/colorPrimary"
+ android:elevation="8dp"
+ android:theme="?actionBarTheme"
+ android:popupTheme="?actionBarPopupTheme" />
+
+ <FrameLayout
+ android:id="@+id/container_roots"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
- </LinearLayout>
+ </LinearLayout>
-</android.support.v4.widget.DrawerLayout>
+ </android.support.v4.widget.DrawerLayout>
+</android.support.design.widget.CoordinatorLayout>
diff --git a/packages/DocumentsUI/res/layout/fixed_layout.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml
index eba9af4297f7..403c6675ac30 100644
--- a/packages/DocumentsUI/res/layout/fixed_layout.xml
+++ b/packages/DocumentsUI/res/layout/fixed_layout.xml
@@ -14,49 +14,59 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
+ floating action buttons) to operate correctly. -->
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:id="@+id/coordinator_layout">
- <com.android.documentsui.DocumentsToolBar
- android:id="@+id/toolbar"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="?android:attr/actionBarSize"
- android:background="?android:attr/colorPrimary"
- android:elevation="8dp"
- android:theme="?actionBarTheme"
- android:popupTheme="?actionBarPopupTheme">
-
- <Spinner
- android:id="@+id/stack"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="4dp"
- android:overlapAnchor="true" />
-
- </com.android.documentsui.DocumentsToolBar>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:divider="?android:attr/dividerVertical"
- android:showDividers="middle">
-
- <FrameLayout
- android:id="@+id/container_roots"
- android:layout_width="256dp"
- android:layout_height="match_parent" />
-
- <include layout="@layout/directory_cluster"
- android:layout_width="0dp"
- android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.android.documentsui.DocumentsToolBar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/actionBarSize"
+ android:background="?android:attr/colorPrimary"
android:elevation="8dp"
- android:background="@color/material_grey_50" />
+ android:theme="?actionBarTheme"
+ android:popupTheme="?actionBarPopupTheme">
+
+ <Spinner
+ android:id="@+id/stack"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:overlapAnchor="true" />
+
+ </com.android.documentsui.DocumentsToolBar>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:baselineAligned="false"
+ android:divider="?android:attr/dividerVertical"
+ android:showDividers="middle">
+
+ <FrameLayout
+ android:id="@+id/container_roots"
+ android:layout_width="256dp"
+ android:layout_height="match_parent" />
+
+ <include layout="@layout/directory_cluster"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:elevation="8dp"
+ android:background="@color/material_grey_50" />
+
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
+</android.support.design.widget.CoordinatorLayout>
diff --git a/packages/DocumentsUI/res/layout/single_pane_layout.xml b/packages/DocumentsUI/res/layout/single_pane_layout.xml
index 20c3232c9686..c5a574568db0 100644
--- a/packages/DocumentsUI/res/layout/single_pane_layout.xml
+++ b/packages/DocumentsUI/res/layout/single_pane_layout.xml
@@ -14,29 +14,39 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
+ floating action buttons) to operate correctly. -->
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:id="@+id/coordinator_layout">
- <com.android.documentsui.DocumentsToolBar
- android:id="@+id/toolbar"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="?android:attr/actionBarSize"
- android:background="?android:attr/colorPrimary"
- android:elevation="8dp"
- android:theme="?actionBarTheme"
- android:popupTheme="?actionBarPopupTheme">
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <Spinner
- android:id="@+id/stack"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="4dp"
- android:overlapAnchor="true" />
+ <com.android.documentsui.DocumentsToolBar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/actionBarSize"
+ android:background="?android:attr/colorPrimary"
+ android:elevation="8dp"
+ android:theme="?actionBarTheme"
+ android:popupTheme="?actionBarPopupTheme">
- </com.android.documentsui.DocumentsToolBar>
+ <Spinner
+ android:id="@+id/stack"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:overlapAnchor="true" />
- <include layout="@layout/directory_cluster"/>
+ </com.android.documentsui.DocumentsToolBar>
-</LinearLayout>
+ <include layout="@layout/directory_cluster"/>
+
+ </LinearLayout>
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 7df152fb9775..7e0649be722d 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -23,12 +23,6 @@
android:actionViewClass="android.widget.SearchView"
android:imeOptions="actionSearch" />
<item
- android:id="@+id/menu_create_dir"
- android:title="@string/menu_create_dir"
- android:icon="@drawable/ic_menu_new_folder"
- android:showAsAction="always"
- android:visible="false" />
- <item
android:id="@+id/menu_sort"
android:title="@string/menu_sort"
android:icon="@drawable/ic_menu_sortby"
@@ -56,17 +50,31 @@
android:icon="@drawable/ic_menu_view_list"
android:showAsAction="never" />
<item
+ android:id="@+id/menu_new_window"
+ android:title="@string/menu_new_window"
+ android:alphabeticShortcut="n"
+ android:showAsAction="never"
+ android:visible="false" />
+ <item
+ android:id="@+id/menu_create_dir"
+ android:title="@string/menu_create_dir"
+ android:icon="@drawable/ic_menu_new_folder"
+ android:alphabeticShortcut="e"
+ android:showAsAction="always"
+ android:visible="false" />
+ <item
android:id="@+id/menu_paste_from_clipboard"
android:title="@string/menu_paste_from_clipboard"
android:alphabeticShortcut="v"
android:showAsAction="never"
android:visible="false" />
+ <!-- Copy action is defined in mode_directory.xml -->
<item
- android:id="@+id/menu_advanced"
+ android:id="@+id/menu_file_size"
android:showAsAction="never"
android:visible="false" />
<item
- android:id="@+id/menu_file_size"
+ android:id="@+id/menu_advanced"
android:showAsAction="never"
android:visible="false" />
<item
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index 0053f2258e33..c2b6dbcaa791 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Kies"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopieer"</string>
<string name="button_move" msgid="2202666023104202232">"Skuif"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Maak toe"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Probeer weer"</string>
<string name="sort_name" msgid="9183560467917256779">"Volgens naam"</string>
<string name="sort_date" msgid="586080032956151448">"Volgens datum gewysig"</string>
<string name="sort_size" msgid="3350681319735474741">"Volgens grootte"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index eb88830753e6..b82fa937fbac 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"ምረጥ"</string>
<string name="button_copy" msgid="8706475544635021302">"ቅዳ"</string>
<string name="button_move" msgid="2202666023104202232">"አንቀሳቀስ"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"አሰናብት"</string>
+ <string name="button_retry" msgid="4392027584153752797">"እንደገና ይሞክሩ"</string>
<string name="sort_name" msgid="9183560467917256779">"በስም"</string>
<string name="sort_date" msgid="586080032956151448">"በተለወጠበት ቀን"</string>
<string name="sort_size" msgid="3350681319735474741">"በመጠን"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index bf464b606f8f..c7c9ef2405a7 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"تحديد"</string>
<string name="button_copy" msgid="8706475544635021302">"نسخ"</string>
<string name="button_move" msgid="2202666023104202232">"نقل"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"إزالة"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"بحسب الاسم"</string>
<string name="sort_date" msgid="586080032956151448">"بحسب تاريخ التعديل"</string>
<string name="sort_size" msgid="3350681319735474741">"بحسب الحجم"</string>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index 0bd01a5a81ed..8c79cebca33f 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Seçin"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopyala"</string>
<string name="button_move" msgid="2202666023104202232">"Köçürün"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Rədd edin"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Ad üzrə"</string>
<string name="sort_date" msgid="586080032956151448">"Tarix üzrə dəyişmiş"</string>
<string name="sort_size" msgid="3350681319735474741">"Ölçü üzrə"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 669145ed2a1f..fdf57d091926 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Избиране"</string>
<string name="button_copy" msgid="8706475544635021302">"Копиране"</string>
<string name="button_move" msgid="2202666023104202232">"Преместване"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Отхвърляне"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"По име"</string>
<string name="sort_date" msgid="586080032956151448">"По дата на промяната"</string>
<string name="sort_size" msgid="3350681319735474741">"По размер"</string>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index 240ba6cfe371..7caf57fbbed7 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"নির্বাচন করুন"</string>
<string name="button_copy" msgid="8706475544635021302">"অনুলিপি করুন"</string>
<string name="button_move" msgid="2202666023104202232">"সরান"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"খারিজ করুন"</string>
+ <string name="button_retry" msgid="4392027584153752797">"আবার চেষ্টা করুন"</string>
<string name="sort_name" msgid="9183560467917256779">"নামের দ্বারা"</string>
<string name="sort_date" msgid="586080032956151448">"পরিবর্তনের তারিখ দ্বারা"</string>
<string name="sort_size" msgid="3350681319735474741">"আকার অনুযায়ী"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 30accda8fe41..ab365ce82801 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Selecciona"</string>
<string name="button_copy" msgid="8706475544635021302">"Copia"</string>
<string name="button_move" msgid="2202666023104202232">"Desplaça"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Ignora"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Per nom"</string>
<string name="sort_date" msgid="586080032956151448">"Per data de modificació"</string>
<string name="sort_size" msgid="3350681319735474741">"Per mida"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index cb1d9734272b..62b313c94bdc 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Vybrat"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopírovat"</string>
<string name="button_move" msgid="2202666023104202232">"Přesunout"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Zavřít"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Zkusit znovu"</string>
<string name="sort_name" msgid="9183560467917256779">"Podle názvu"</string>
<string name="sort_date" msgid="586080032956151448">"Podle data úpravy"</string>
<string name="sort_size" msgid="3350681319735474741">"Podle velikosti"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index f12737c57bd1..c3d7cdd39d08 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Vælg"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopiér"</string>
<string name="button_move" msgid="2202666023104202232">"Flyt"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Luk"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Prøv igen"</string>
<string name="sort_name" msgid="9183560467917256779">"Efter navn"</string>
<string name="sort_date" msgid="586080032956151448">"Efter ændringsdato"</string>
<string name="sort_size" msgid="3350681319735474741">"Efter størrelse"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index a7be4db41acc..f88b5c4cb92e 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Auswählen"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopieren"</string>
<string name="button_move" msgid="2202666023104202232">"Verschieben"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Schließen"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Erneut versuchen"</string>
<string name="sort_name" msgid="9183560467917256779">"Nach Name"</string>
<string name="sort_date" msgid="586080032956151448">"Nach Änderungsdatum"</string>
<string name="sort_size" msgid="3350681319735474741">"Nach Größe"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 82155a8c11dd..dcca46c776b2 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Επιλογή"</string>
<string name="button_copy" msgid="8706475544635021302">"Αντιγραφή"</string>
<string name="button_move" msgid="2202666023104202232">"Μετακίνηση"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Παράβλεψη"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Δοκιμάστε ξανά"</string>
<string name="sort_name" msgid="9183560467917256779">"Κατά όνομα"</string>
<string name="sort_date" msgid="586080032956151448">"Κατά ημερομηνία τροποποίησης"</string>
<string name="sort_size" msgid="3350681319735474741">"Κατά μέγεθος"</string>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index c6090475b413..26fd30ff9d38 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"select"</string>
<string name="button_copy" msgid="8706475544635021302">"Copy"</string>
<string name="button_move" msgid="2202666023104202232">"Move"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Dismiss"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Try again"</string>
<string name="sort_name" msgid="9183560467917256779">"By name"</string>
<string name="sort_date" msgid="586080032956151448">"By date modified"</string>
<string name="sort_size" msgid="3350681319735474741">"By size"</string>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index c6090475b413..26fd30ff9d38 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"select"</string>
<string name="button_copy" msgid="8706475544635021302">"Copy"</string>
<string name="button_move" msgid="2202666023104202232">"Move"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Dismiss"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Try again"</string>
<string name="sort_name" msgid="9183560467917256779">"By name"</string>
<string name="sort_date" msgid="586080032956151448">"By date modified"</string>
<string name="sort_size" msgid="3350681319735474741">"By size"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index c6090475b413..26fd30ff9d38 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"select"</string>
<string name="button_copy" msgid="8706475544635021302">"Copy"</string>
<string name="button_move" msgid="2202666023104202232">"Move"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Dismiss"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Try again"</string>
<string name="sort_name" msgid="9183560467917256779">"By name"</string>
<string name="sort_date" msgid="586080032956151448">"By date modified"</string>
<string name="sort_size" msgid="3350681319735474741">"By size"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 5936d831acd3..6e805b90d4e4 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Seleccionar"</string>
<string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
<string name="button_move" msgid="2202666023104202232">"Mover"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Descartar"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Reintentar"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
<string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
<string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 2ed67dd08b19..8fa1d2ed4c63 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Seleccionar"</string>
<string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
<string name="button_move" msgid="2202666023104202232">"Mover"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Reintentar"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
<string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
<string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index e32936f5de78..7008885bd348 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Vali"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopeeri"</string>
<string name="button_move" msgid="2202666023104202232">"Teisalda"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Loobu"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Nime järgi"</string>
<string name="sort_date" msgid="586080032956151448">"Muutmiskuupäeva järgi"</string>
<string name="sort_size" msgid="3350681319735474741">"Suuruse järgi"</string>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index a1b6fc2fddb6..17d7c660a1bb 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Hautatu"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopiatu"</string>
<string name="button_move" msgid="2202666023104202232">"Mugitu"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Baztertu"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Izenaren arabera"</string>
<string name="sort_date" msgid="586080032956151448">"Aldatze-dataren arabera"</string>
<string name="sort_size" msgid="3350681319735474741">"Tamainaren arabera"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index bbbfe5236aff..c4f6d588ea1c 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -22,7 +22,7 @@
<string name="title_save" msgid="2433679664882857999">"ذخیره در"</string>
<string name="menu_create_dir" msgid="5947289605844398389">"ایجاد پوشه"</string>
<string name="menu_grid" msgid="6878021334497835259">"نمای جدولی"</string>
- <string name="menu_list" msgid="7279285939892417279">"نمای فهرست‌وار"</string>
+ <string name="menu_list" msgid="7279285939892417279">"نمای فهرستی"</string>
<string name="menu_sort" msgid="7677740407158414452">"مرتب‌سازی براساس"</string>
<string name="menu_search" msgid="3816712084502856974">"جستجو"</string>
<string name="menu_settings" msgid="6008033148948428823">"تنظیمات"</string>
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"انتخاب"</string>
<string name="button_copy" msgid="8706475544635021302">"کپی"</string>
<string name="button_move" msgid="2202666023104202232">"انتقال"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"نپذیرفتن"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"براساس نام"</string>
<string name="sort_date" msgid="586080032956151448">"براساس تاریخ اصلاح"</string>
<string name="sort_size" msgid="3350681319735474741">"براساس اندازه"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index fd289a73b4ce..3e873009ce7a 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Valitse"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopioi"</string>
<string name="button_move" msgid="2202666023104202232">"Siirrä"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Hylkää"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Nimen mukaan"</string>
<string name="sort_date" msgid="586080032956151448">"Muokkauspäivän mukaan"</string>
<string name="sort_size" msgid="3350681319735474741">"Koon mukaan"</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 342fc9702230..3e82f3403cdc 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Sélectionner"</string>
<string name="button_copy" msgid="8706475544635021302">"Copier"</string>
<string name="button_move" msgid="2202666023104202232">"Déplacer"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Faire disparaître"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
<string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
<string name="sort_size" msgid="3350681319735474741">"Par taille"</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 7434e2f17ef9..0512ab15ae18 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Sélectionner"</string>
<string name="button_copy" msgid="8706475544635021302">"Copier"</string>
<string name="button_move" msgid="2202666023104202232">"Déplacer"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Fermer"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Réessayer"</string>
<string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
<string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
<string name="sort_size" msgid="3350681319735474741">"Par taille"</string>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index b74018df88b4..a1cd614f417e 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Seleccionar"</string>
<string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
<string name="button_move" msgid="2202666023104202232">"Mover"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
<string name="sort_date" msgid="586080032956151448">"Por data de modificación"</string>
<string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 58384c92d661..059fb2cb2efb 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"પસંદ કરો"</string>
<string name="button_copy" msgid="8706475544635021302">"કૉપિ કરો"</string>
<string name="button_move" msgid="2202666023104202232">"ખસેડો"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"છોડી દો"</string>
+ <string name="button_retry" msgid="4392027584153752797">"ફરીથી પ્રયત્ન કરો"</string>
<string name="sort_name" msgid="9183560467917256779">"નામ દ્વારા"</string>
<string name="sort_date" msgid="586080032956151448">"સંશોધન તારીખ દ્વારા"</string>
<string name="sort_size" msgid="3350681319735474741">"કદ દ્વારા"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index b42c69c7114a..8e33a005f4cc 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"चुनें"</string>
<string name="button_copy" msgid="8706475544635021302">"कॉपी करें"</string>
<string name="button_move" msgid="2202666023104202232">"ले जाएं"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"ख़ारिज करें"</string>
+ <string name="button_retry" msgid="4392027584153752797">"पुनः प्रयास करें"</string>
<string name="sort_name" msgid="9183560467917256779">"नाम के अनुसार"</string>
<string name="sort_date" msgid="586080032956151448">"बदलाव के दिनांक के अनुसार"</string>
<string name="sort_size" msgid="3350681319735474741">"आकार के अनुसार"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 575c7ffe1d9a..4774753aaf60 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Odaberi"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string>
<string name="button_move" msgid="2202666023104202232">"Premjesti"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Odbaci"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Po nazivu"</string>
<string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string>
<string name="sort_size" msgid="3350681319735474741">"Po veličini"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 2d2e3c8b416c..7a521ecc3239 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Kiválasztás"</string>
<string name="button_copy" msgid="8706475544635021302">"Másolás"</string>
<string name="button_move" msgid="2202666023104202232">"Áthelyezés"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Elvetés"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Név szerint"</string>
<string name="sort_date" msgid="586080032956151448">"Módosítás dátuma szerint"</string>
<string name="sort_size" msgid="3350681319735474741">"Méret szerint"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 0a4e7a3bedff..95d73f0e5b2e 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Ընտրել"</string>
<string name="button_copy" msgid="8706475544635021302">"Պատճենել"</string>
<string name="button_move" msgid="2202666023104202232">"Տեղափոխել"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Փակել"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Ըստ անվան"</string>
<string name="sort_date" msgid="586080032956151448">"Ըստ փոփոխման ամսաթվի"</string>
<string name="sort_size" msgid="3350681319735474741">"Ըստ չափի"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 59aadf12061d..63d415cadf46 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Pilih"</string>
<string name="button_copy" msgid="8706475544635021302">"Salin"</string>
<string name="button_move" msgid="2202666023104202232">"Pindahkan"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Tutup"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Coba Lagi"</string>
<string name="sort_name" msgid="9183560467917256779">"Menurut nama"</string>
<string name="sort_date" msgid="586080032956151448">"Menurut tanggal diubah"</string>
<string name="sort_size" msgid="3350681319735474741">"Menurut ukuran"</string>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index a0f4987ab904..0c0e47fd4716 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Velja"</string>
<string name="button_copy" msgid="8706475544635021302">"Afrita"</string>
<string name="button_move" msgid="2202666023104202232">"Færa"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Hunsa"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Reyna aftur"</string>
<string name="sort_name" msgid="9183560467917256779">"Eftir heiti"</string>
<string name="sort_date" msgid="586080032956151448">"Eftir breytingadags."</string>
<string name="sort_size" msgid="3350681319735474741">"Eftir stærð"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index ce837daad6cc..de129a7ec0cf 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Seleziona"</string>
<string name="button_copy" msgid="8706475544635021302">"Copia"</string>
<string name="button_move" msgid="2202666023104202232">"Sposta"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Ignora"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Riprova"</string>
<string name="sort_name" msgid="9183560467917256779">"Per nome"</string>
<string name="sort_date" msgid="586080032956151448">"Per data di modifica"</string>
<string name="sort_size" msgid="3350681319735474741">"Per dimensioni"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 89e64030124e..dbe463080c82 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"בחר"</string>
<string name="button_copy" msgid="8706475544635021302">"העתק"</string>
<string name="button_move" msgid="2202666023104202232">"העבר"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"הסר"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"לפי שם"</string>
<string name="sort_date" msgid="586080032956151448">"לפי תאריך שינוי"</string>
<string name="sort_size" msgid="3350681319735474741">"לפי גודל"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 92e10234f82e..45f0ea1df6f8 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"選択"</string>
<string name="button_copy" msgid="8706475544635021302">"コピー"</string>
<string name="button_move" msgid="2202666023104202232">"移動"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"表示しない"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"名前順"</string>
<string name="sort_date" msgid="586080032956151448">"更新日順"</string>
<string name="sort_size" msgid="3350681319735474741">"サイズ順"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index 9a324ba6cef9..114e73c75cb5 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"არჩევა"</string>
<string name="button_copy" msgid="8706475544635021302">"კოპირება"</string>
<string name="button_move" msgid="2202666023104202232">"გადაადგილება"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"დახურვა"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"სახელით"</string>
<string name="sort_date" msgid="586080032956151448">"ცვლილების თარიღით"</string>
<string name="sort_size" msgid="3350681319735474741">"ზომით"</string>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index 66f69f529cf1..af123c62b20c 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Таңдау"</string>
<string name="button_copy" msgid="8706475544635021302">"Көшіру"</string>
<string name="button_move" msgid="2202666023104202232">"Жылжыту"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Өшіру"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Атауы бойынша"</string>
<string name="sort_date" msgid="586080032956151448">"Өзгертілген мерзімі бойынша"</string>
<string name="sort_size" msgid="3350681319735474741">"Өлшемі бойынша"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 5249d97f6d97..8f3feaedefd1 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"ជ្រើស"</string>
<string name="button_copy" msgid="8706475544635021302">"ចម្លង"</string>
<string name="button_move" msgid="2202666023104202232">"ផ្លាស់ទី"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"បដិសេធ"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"តាម​ឈ្មោះ"</string>
<string name="sort_date" msgid="586080032956151448">"តាម​កាលបរិច្ឆេទ​បាន​កែប្រែ"</string>
<string name="sort_size" msgid="3350681319735474741">"តាម​​ទំហំ"</string>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index d5eda84388bc..826cf1e3fa73 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"ಆಯ್ಕೆಮಾಡು"</string>
<string name="button_copy" msgid="8706475544635021302">"ನಕಲಿಸು"</string>
<string name="button_move" msgid="2202666023104202232">"ಸರಿಸು"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"ವಜಾಗೊಳಿಸಿ"</string>
+ <string name="button_retry" msgid="4392027584153752797">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="sort_name" msgid="9183560467917256779">"ಹೆಸರಿನ ಪ್ರಕಾರ"</string>
<string name="sort_date" msgid="586080032956151448">"ಮಾರ್ಪಡಿಸಿರುವ ದಿನಾಂಕದ ಪ್ರಕಾರ"</string>
<string name="sort_size" msgid="3350681319735474741">"ಗಾತ್ರದ ಪ್ರಕಾರ"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 77a0df65f4e1..322b43b3bc3a 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"선택"</string>
<string name="button_copy" msgid="8706475544635021302">"복사"</string>
<string name="button_move" msgid="2202666023104202232">"이동"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"닫기"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"이름순"</string>
<string name="sort_date" msgid="586080032956151448">"수정된 날짜순"</string>
<string name="sort_size" msgid="3350681319735474741">"크기순"</string>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index 14a6331fb526..c8aa69eb3c18 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Тандоо"</string>
<string name="button_copy" msgid="8706475544635021302">"Көчүрүү"</string>
<string name="button_move" msgid="2202666023104202232">"Жылдыруу"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Этибарга албоо"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Аты боюнча"</string>
<string name="sort_date" msgid="586080032956151448">"Өзгөртүлгөн күнү боюнча"</string>
<string name="sort_size" msgid="3350681319735474741">"Өлчөмү боюнча"</string>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 2d099f4a2cd6..dedfa0552b36 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"ເລືອກ"</string>
<string name="button_copy" msgid="8706475544635021302">"ສຳເນົາ"</string>
<string name="button_move" msgid="2202666023104202232">"ຍ້າຍ"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"ປິດໄວ້"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"ຕາມຊື່"</string>
<string name="sort_date" msgid="586080032956151448">"ຕາມວັນທີທີ່ແກ້ໄຂ"</string>
<string name="sort_size" msgid="3350681319735474741">"ຕາມຂະໜາດ"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 7b458add0c47..0c8b44388e00 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Pasirinkti"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopijuoti"</string>
<string name="button_move" msgid="2202666023104202232">"Perkelti"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Atsisakyti"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Pagal pavadinimą"</string>
<string name="sort_date" msgid="586080032956151448">"Pagal keitimo datą"</string>
<string name="sort_size" msgid="3350681319735474741">"Pagal dydį"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 44909ce48393..5c79554424f7 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Atlasīt"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopēt"</string>
<string name="button_move" msgid="2202666023104202232">"Pārvietot"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Noraidīt"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Pēc nosaukuma"</string>
<string name="sort_date" msgid="586080032956151448">"Pēc pārveidošanas datuma"</string>
<string name="sort_size" msgid="3350681319735474741">"Pēc lieluma"</string>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 7408d0bea25a..b2cb9f1ca2ea 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Избери"</string>
<string name="button_copy" msgid="8706475544635021302">"Копирај"</string>
<string name="button_move" msgid="2202666023104202232">"Премести"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Отфрли"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"По име"</string>
<string name="sort_date" msgid="586080032956151448">"Изменети по датум"</string>
<string name="sort_size" msgid="3350681319735474741">"По големина"</string>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index af21db914126..07efa66bc871 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"തിരഞ്ഞെടുക്കുക"</string>
<string name="button_copy" msgid="8706475544635021302">"പകര്‍ത്തുക"</string>
<string name="button_move" msgid="2202666023104202232">"നീക്കുക"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"ഡിസ്മിസ് ചെയ്യുക"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"പേര് പ്രകാരം"</string>
<string name="sort_date" msgid="586080032956151448">"പരിഷ്‌ക്കരിച്ച തീയതി പ്രകാരം"</string>
<string name="sort_size" msgid="3350681319735474741">"വലുപ്പം പ്രകാരം"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 1475e080bf98..d45778cab5bd 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Сонгох"</string>
<string name="button_copy" msgid="8706475544635021302">"Хуулах"</string>
<string name="button_move" msgid="2202666023104202232">"Зөөх"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Алгасах"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Нэрээр"</string>
<string name="sort_date" msgid="586080032956151448">"Өөрчлөгдсөн огноогоор"</string>
<string name="sort_size" msgid="3350681319735474741">"Хэмжээгээр"</string>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index b7654881aad3..8d70143ffc0a 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"निवडा"</string>
<string name="button_copy" msgid="8706475544635021302">"कॉपी करा"</string>
<string name="button_move" msgid="2202666023104202232">"हलवा"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"डिसमिस करा"</string>
+ <string name="button_retry" msgid="4392027584153752797">"पुन्‍हा प्रयत्न करा"</string>
<string name="sort_name" msgid="9183560467917256779">"नावानुसार"</string>
<string name="sort_date" msgid="586080032956151448">"सुधारित केलेल्‍या तारखेनुसार"</string>
<string name="sort_size" msgid="3350681319735474741">"आकारानुसार"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 46829576e525..22501095b614 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Pilih"</string>
<string name="button_copy" msgid="8706475544635021302">"Salin"</string>
<string name="button_move" msgid="2202666023104202232">"Alihkan"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Tolak"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Mengikut nama"</string>
<string name="sort_date" msgid="586080032956151448">"Mengikut tarikh diubah"</string>
<string name="sort_size" msgid="3350681319735474741">"Mengikut saiz"</string>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index a422898d8f6d..480c27b1ddfb 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"ရွေးရန်"</string>
<string name="button_copy" msgid="8706475544635021302">"ကူးယူရန်"</string>
<string name="button_move" msgid="2202666023104202232">"ရွေ့မည်"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"ပယ်ရန်"</string>
+ <string name="button_retry" msgid="4392027584153752797">"ထပ် စမ်းကြည့်ပါ"</string>
<string name="sort_name" msgid="9183560467917256779">"အမည်ဖြင့်"</string>
<string name="sort_date" msgid="586080032956151448">"ပြင်ဆင်မှု ရက်စွဲဖြင့်"</string>
<string name="sort_size" msgid="3350681319735474741">"အရွယ်အစားဖြင့်"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 5bcc50f0a62c..48355aab72ba 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Velg"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopiér"</string>
<string name="button_move" msgid="2202666023104202232">"Flytt"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Avvis"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Prøv på nytt"</string>
<string name="sort_name" msgid="9183560467917256779">"Etter navn"</string>
<string name="sort_date" msgid="586080032956151448">"Etter endringsdato"</string>
<string name="sort_size" msgid="3350681319735474741">"Etter størrelse"</string>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index b121035d1490..53942c192ac3 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"चयन गर्नुहोस्"</string>
<string name="button_copy" msgid="8706475544635021302">"प्रतिलिपि बनाउनुहोस्"</string>
<string name="button_move" msgid="2202666023104202232">"सार्नुहोस्"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"खारेज गर्नुहोस्"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"नाम अनुसार"</string>
<string name="sort_date" msgid="586080032956151448">"परिमार्जित मिति अनुसार"</string>
<string name="sort_size" msgid="3350681319735474741">"आकार अनुसार"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 88ef0bf10ab6..d3e6bbe9cae2 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Selecteren"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopiëren"</string>
<string name="button_move" msgid="2202666023104202232">"Verplaatsen"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Sluiten"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Opnieuw proberen"</string>
<string name="sort_name" msgid="9183560467917256779">"Op naam"</string>
<string name="sort_date" msgid="586080032956151448">"Op aanpassingsdatum"</string>
<string name="sort_size" msgid="3350681319735474741">"Op grootte"</string>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index a55fc276cb65..3b1439653708 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"ਚੁਣੋ"</string>
<string name="button_copy" msgid="8706475544635021302">"ਕਾਪੀ ਕਰੋ"</string>
<string name="button_move" msgid="2202666023104202232">"ਮੂਵ ਕਰੋ"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"ਬਰਖਾਸਤ ਕਰੋ"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"ਨਾਮ ਮੁਤਾਬਕ"</string>
<string name="sort_date" msgid="586080032956151448">"ਤਾਰੀਖ ਮੁਤਾਬਕ ਸੰਸ਼ੋਧਿਤ"</string>
<string name="sort_size" msgid="3350681319735474741">"ਆਕਾਰ ਮੁਤਾਬਕ"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 0099e5a5c061..3e4ef6837726 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Wybierz"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopiuj"</string>
<string name="button_move" msgid="2202666023104202232">"Przenieś"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Zamknij"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string>
<string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string>
<string name="sort_size" msgid="3350681319735474741">"Według rozmiaru"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index 18506dc6f385..ca984cffe69d 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Selecionar"</string>
<string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
<string name="button_move" msgid="2202666023104202232">"Mover"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Dispensar"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Tentar novamente"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
<string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
<string name="sort_size" msgid="3350681319735474741">"Por tamanho"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index adf6ec904a32..ab673580ba19 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Selecionar"</string>
<string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
<string name="button_move" msgid="2202666023104202232">"Mover"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Tentar novamente"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
<string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
<string name="sort_size" msgid="3350681319735474741">"Por tamanho"</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 18506dc6f385..ca984cffe69d 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Selecionar"</string>
<string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
<string name="button_move" msgid="2202666023104202232">"Mover"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Dispensar"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Tentar novamente"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
<string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
<string name="sort_size" msgid="3350681319735474741">"Por tamanho"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 1b046a3c940e..e927b785e2f7 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Selectați"</string>
<string name="button_copy" msgid="8706475544635021302">"Copiați"</string>
<string name="button_move" msgid="2202666023104202232">"Mutați"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Închideți"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Încercați din nou"</string>
<string name="sort_name" msgid="9183560467917256779">"După nume"</string>
<string name="sort_date" msgid="586080032956151448">"După data modificării"</string>
<string name="sort_size" msgid="3350681319735474741">"După dimensiune"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 84ae160acf38..cdf20cadfc61 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Выбрать"</string>
<string name="button_copy" msgid="8706475544635021302">"Копировать"</string>
<string name="button_move" msgid="2202666023104202232">"Переместить"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Скрыть"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"По названию"</string>
<string name="sort_date" msgid="586080032956151448">"По дате изменения"</string>
<string name="sort_size" msgid="3350681319735474741">"По размеру"</string>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index d9d5818c4943..138f8a6c6b76 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"තෝරන්න"</string>
<string name="button_copy" msgid="8706475544635021302">"පිටපත් කිරීම"</string>
<string name="button_move" msgid="2202666023104202232">"ගෙන යන්න"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"ඉවතලන්න"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"නමින්"</string>
<string name="sort_date" msgid="586080032956151448">"වෙනස් කරන ලද දිනයෙන්"</string>
<string name="sort_size" msgid="3350681319735474741">"ප්‍රමාණය මගින්"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index e0ff5fc0c14e..4310819f08a4 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Vybrať"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopírovať"</string>
<string name="button_move" msgid="2202666023104202232">"Presunúť"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Odmietnuť"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Podľa názvu"</string>
<string name="sort_date" msgid="586080032956151448">"Podľa dátumu zmeny"</string>
<string name="sort_size" msgid="3350681319735474741">"Podľa veľkosti"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index 83e51244e15c..c9982a7a0233 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Izberi"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string>
<string name="button_move" msgid="2202666023104202232">"Premik"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Opusti"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Po imenu"</string>
<string name="sort_date" msgid="586080032956151448">"Po datumu spremembe"</string>
<string name="sort_size" msgid="3350681319735474741">"Po velikosti"</string>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index 981daf252893..f1ee1bca33eb 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Zgjidh"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopjo"</string>
<string name="button_move" msgid="2202666023104202232">"Zhvendos"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Largoje"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Sipas emrit"</string>
<string name="sort_date" msgid="586080032956151448">"Sipas datës së modifikimit"</string>
<string name="sort_size" msgid="3350681319735474741">"Sipas madhësisë"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index bd0e9af9723d..c5116c2f78a9 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Изабери"</string>
<string name="button_copy" msgid="8706475544635021302">"Копирај"</string>
<string name="button_move" msgid="2202666023104202232">"Премести"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Одбаци"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Према имену"</string>
<string name="sort_date" msgid="586080032956151448">"Према датуму измене"</string>
<string name="sort_size" msgid="3350681319735474741">"Према величини"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 2569e00128ed..06e6514d8afb 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Välj"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopiera"</string>
<string name="button_move" msgid="2202666023104202232">"Flytta"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Ta bort permanent"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Försök igen"</string>
<string name="sort_name" msgid="9183560467917256779">"Efter namn"</string>
<string name="sort_date" msgid="586080032956151448">"Efter ändringsdatum"</string>
<string name="sort_size" msgid="3350681319735474741">"Efter storlek"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index ce186d7b3be7..79bae1f94cc8 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Teua"</string>
<string name="button_copy" msgid="8706475544635021302">"Nakili"</string>
<string name="button_move" msgid="2202666023104202232">"Hamisha"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Ondoa"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Jaribu Tena"</string>
<string name="sort_name" msgid="9183560467917256779">"Kwa jina"</string>
<string name="sort_date" msgid="586080032956151448">"Kwa tarehe viliporekebishwa"</string>
<string name="sort_size" msgid="3350681319735474741">"Kwa ukubwa"</string>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index b7b9c093cad5..117aabce296e 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"தேர்ந்தெடு"</string>
<string name="button_copy" msgid="8706475544635021302">"நகலெடு"</string>
<string name="button_move" msgid="2202666023104202232">"நகர்த்து"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"நிராகரி"</string>
+ <string name="button_retry" msgid="4392027584153752797">"மீண்டும் முயற்சிக்கவும்"</string>
<string name="sort_name" msgid="9183560467917256779">"பெயரின்படி"</string>
<string name="sort_date" msgid="586080032956151448">"திருத்தப்பட்ட தேதியின்படி"</string>
<string name="sort_size" msgid="3350681319735474741">"அளவின்படி"</string>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index 7a814862c656..21b7f586c3d6 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"ఎంచుకోండి"</string>
<string name="button_copy" msgid="8706475544635021302">"కాపీ చేయి"</string>
<string name="button_move" msgid="2202666023104202232">"తరలించు"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"తీసివేయి"</string>
+ <string name="button_retry" msgid="4392027584153752797">"మళ్లీ ప్రయత్నించు"</string>
<string name="sort_name" msgid="9183560467917256779">"పేరు ద్వారా"</string>
<string name="sort_date" msgid="586080032956151448">"సవరించిన తేదీ ద్వారా"</string>
<string name="sort_size" msgid="3350681319735474741">"పరిమాణం ద్వారా"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 87c0a739cf17..8a49708ad591 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"เลือก"</string>
<string name="button_copy" msgid="8706475544635021302">"คัดลอก"</string>
<string name="button_move" msgid="2202666023104202232">"ย้าย"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"ปิด"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"ตามชื่อ"</string>
<string name="sort_date" msgid="586080032956151448">"ตามวันที่ที่ปรับเปลี่ยน"</string>
<string name="sort_size" msgid="3350681319735474741">"ตามขนาด"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index eaef936365e2..5c0dc12e0353 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Pumili"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopyahin"</string>
<string name="button_move" msgid="2202666023104202232">"Ilipat"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"I-dismiss"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Ayon sa pangalan"</string>
<string name="sort_date" msgid="586080032956151448">"Ayon sa petsa ng pagbago"</string>
<string name="sort_size" msgid="3350681319735474741">"Ayon sa laki"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 8c0596f418cc..092b38ee7eef 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Seç"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopyala"</string>
<string name="button_move" msgid="2202666023104202232">"Taşı"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Kapat"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Ada göre"</string>
<string name="sort_date" msgid="586080032956151448">"Değişiklik tarihine göre"</string>
<string name="sort_size" msgid="3350681319735474741">"Boyuta göre"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 9bbc59abb0d2..dff37c3eb316 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Вибрати"</string>
<string name="button_copy" msgid="8706475544635021302">"Копіювати"</string>
<string name="button_move" msgid="2202666023104202232">"Перемістити"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Закрити"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Повторити спробу"</string>
<string name="sort_name" msgid="9183560467917256779">"За назвою"</string>
<string name="sort_date" msgid="586080032956151448">"За датою змінення"</string>
<string name="sort_size" msgid="3350681319735474741">"За розміром"</string>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 0c12aa1bcd7a..82822ecdfe8d 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"منتخب کریں"</string>
<string name="button_copy" msgid="8706475544635021302">"کاپی کریں"</string>
<string name="button_move" msgid="2202666023104202232">"منتقل کریں"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"برخاست کریں"</string>
+ <string name="button_retry" msgid="4392027584153752797">"دوبارہ کوشش کریں"</string>
<string name="sort_name" msgid="9183560467917256779">"نام کے لحاظ سے"</string>
<string name="sort_date" msgid="586080032956151448">"ترمیم کی تاریخ کے لحاظ سے"</string>
<string name="sort_size" msgid="3350681319735474741">"سائز کے لحاظ سے"</string>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index ec918857d09d..d0cfacc8bc8c 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -24,7 +24,7 @@
<string name="menu_grid" msgid="6878021334497835259">"Katak ko‘rinishida"</string>
<string name="menu_list" msgid="7279285939892417279">"Ro‘yxat ko‘rinishida"</string>
<string name="menu_sort" msgid="7677740407158414452">"Saralash"</string>
- <string name="menu_search" msgid="3816712084502856974">"Izlash"</string>
+ <string name="menu_search" msgid="3816712084502856974">"Qidirish"</string>
<string name="menu_settings" msgid="6008033148948428823">"Sozlamalar"</string>
<string name="menu_open" msgid="432922957274920903">"Ochish"</string>
<string name="menu_save" msgid="2394743337684426338">"Saqlash"</string>
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Tanlash"</string>
<string name="button_copy" msgid="8706475544635021302">"Nusxalash"</string>
<string name="button_move" msgid="2202666023104202232">"Ko‘chirib o‘tkazish"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"O‘chirish"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Nomi bo‘yicha"</string>
<string name="sort_date" msgid="586080032956151448">"Tahrir sanasi bo‘yicha"</string>
<string name="sort_size" msgid="3350681319735474741">"Hajmi bo‘yicha"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index a652ecc950bf..4583362fc6ab 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"Chọn"</string>
<string name="button_copy" msgid="8706475544635021302">"Sao chép"</string>
<string name="button_move" msgid="2202666023104202232">"Di chuyển"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Loại bỏ"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"Theo tên"</string>
<string name="sort_date" msgid="586080032956151448">"Theo ngày sửa đổi"</string>
<string name="sort_size" msgid="3350681319735474741">"Theo kích thước"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index b0f548083cff..d577e14c8f40 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"选择"</string>
<string name="button_copy" msgid="8706475544635021302">"复制"</string>
<string name="button_move" msgid="2202666023104202232">"移动"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"关闭"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"按名称"</string>
<string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
<string name="sort_size" msgid="3350681319735474741">"按大小"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 220b71695685..3d44047126b9 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"選取"</string>
<string name="button_copy" msgid="8706475544635021302">"複製"</string>
<string name="button_move" msgid="2202666023104202232">"移動"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"關閉"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"按名稱"</string>
<string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
<string name="sort_size" msgid="3350681319735474741">"按大小"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 9c21aa59fbaa..aaad98c89851 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -44,6 +44,9 @@
<string name="button_select" msgid="527196987259139214">"選取"</string>
<string name="button_copy" msgid="8706475544635021302">"複製"</string>
<string name="button_move" msgid="2202666023104202232">"移動"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"關閉"</string>
+ <!-- no translation found for button_retry (4392027584153752797) -->
+ <skip />
<string name="sort_name" msgid="9183560467917256779">"依名稱"</string>
<string name="sort_date" msgid="586080032956151448">"依修改日期"</string>
<string name="sort_size" msgid="3350681319735474741">"依大小"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index 5ce9f12a3867..8f20cc4db941 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -44,6 +44,8 @@
<string name="button_select" msgid="527196987259139214">"Khetha"</string>
<string name="button_copy" msgid="8706475544635021302">"Kopisha"</string>
<string name="button_move" msgid="2202666023104202232">"Hambisa"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Cashisa"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Zama futhi"</string>
<string name="sort_name" msgid="9183560467917256779">"Ngegama"</string>
<string name="sort_date" msgid="586080032956151448">"Ngedethi yokuguqula"</string>
<string name="sort_size" msgid="3350681319735474741">"Ngosayizi"</string>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index a12edf397178..d21b5eec7d4f 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -27,7 +27,7 @@
<string name="title_save">Save to</string>
<!-- Menu item that creates a new directory/folder at the current location [CHAR LIMIT=24] -->
- <string name="menu_create_dir">Create folder</string>
+ <string name="menu_create_dir">New folder</string>
<!-- Menu item that switches view to show documents as a large-format grid of thumbnails [CHAR LIMIT=24] -->
<string name="menu_grid">Grid view</string>
<!-- Menu item that switches view to show documents as a list [CHAR LIMIT=24] -->
@@ -54,6 +54,8 @@
<!-- Menu item title that moves the selected documents [CHAR LIMIT=24] -->
<string name="menu_move">Move to\u2026</string>
+ <!-- Menu item title that creates a new window in the activity [CHAR LIMIT=24] -->
+ <string name="menu_new_window">New window</string>
<!-- Menu item title that copies the selected documents to clipboard [CHAR LIMIT=24] -->
<string name="menu_copy_to_clipboard">Copy</string>
<!-- Menu item title that pastes files from the clipboard [CHAR LIMIT=24] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index c8ec4dc2c510..caaa2b9be0a3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -20,6 +20,7 @@ import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
import static com.android.documentsui.DirectoryFragment.ANIM_UP;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.internal.util.Preconditions.checkArgument;
import android.app.Activity;
@@ -75,10 +76,11 @@ abstract class BaseActivity extends Activity {
RootsCache mRoots;
SearchManager mSearchManager;
DrawerController mDrawer;
+ boolean mProductivityDevice;
+ private final String mTag;
@LayoutRes
private int mLayoutId;
- private final String mTag;
private DirectoryContainerView mDirectoryContainer;
public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings);
@@ -99,6 +101,7 @@ abstract class BaseActivity extends Activity {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ mProductivityDevice = getResources().getBoolean(R.bool.productivity_device);
mState = (icicle != null)
? icicle.<State>getParcelable(EXTRA_STATE)
: buildState();
@@ -125,10 +128,10 @@ abstract class BaseActivity extends Activity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
- boolean shown = super.onPrepareOptionsMenu(menu);
+ super.onPrepareOptionsMenu(menu);
final RootInfo root = getCurrentRoot();
- final DocumentInfo cwd = getCurrentDirectory();
+ final boolean inRecents = getCurrentDirectory() == null;
final MenuItem sort = menu.findItem(R.id.menu_sort);
final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
@@ -138,26 +141,28 @@ abstract class BaseActivity extends Activity {
final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
final MenuItem settings = menu.findItem(R.id.menu_settings);
- mSearchManager.update(root);
+ // I'm thinkin' this isn't necesary here. If it is...'cuz of a bug....
+ // then uncomment the linke and let's get a proper bug reference here.
+ // mSearchManager.update(root);
// Search uses backend ranking; no sorting
- sort.setVisible(cwd != null && !mSearchManager.isSearching());
+ sort.setVisible(!inRecents && !mSearchManager.isSearching());
+
+ // grid/list is effectively a toggle.
+ grid.setVisible(mState.derivedMode != State.MODE_GRID);
+ list.setVisible(mState.derivedMode != State.MODE_LIST);
+
+ sortSize.setVisible(mState.showSize); // Only sort by size when visible
+ fileSize.setVisible(!mState.forceSize);
+ advanced.setVisible(!mState.forceAdvanced);
+ settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0);
advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this)
? R.string.menu_advanced_hide : R.string.menu_advanced_show);
fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
? R.string.menu_file_size_hide : R.string.menu_file_size_show);
- State state = getDisplayState();
-
- sortSize.setVisible(state.showSize); // Only sort by size when visible
- fileSize.setVisible(!state.showSize);
- grid.setVisible(state.derivedMode != State.MODE_GRID);
- list.setVisible(state.derivedMode != State.MODE_LIST);
- advanced.setVisible(!mState.showAdvanced);
- settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0);
-
- return shown;
+ return true;
}
State buildDefaultState() {
@@ -183,12 +188,10 @@ abstract class BaseActivity extends Activity {
void onStackRestored(boolean restored, boolean external) {}
void onRootPicked(RootInfo root) {
- State state = getDisplayState();
-
// Clear entire backstack and start in new root
- state.stack.root = root;
- state.stack.clear();
- state.stackTouched = true;
+ mState.stack.root = root;
+ mState.stack.clear();
+ mState.stackTouched = true;
mSearchManager.update(root);
@@ -208,6 +211,7 @@ abstract class BaseActivity extends Activity {
switch (item.getItemId()) {
case R.id.menu_advanced:
case R.id.menu_file_size:
+ case R.id.menu_new_window:
break;
default:
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
@@ -277,6 +281,7 @@ abstract class BaseActivity extends Activity {
return cwd != null
&& cwd.isCreateSupported()
&& !mSearchManager.isSearching()
+ && !root.isRecents()
&& !root.isDownloads();
}
@@ -286,8 +291,8 @@ abstract class BaseActivity extends Activity {
}
void openDirectory(DocumentInfo doc) {
- getDisplayState().stack.push(doc);
- getDisplayState().stackTouched = true;
+ mState.stack.push(doc);
+ mState.stackTouched = true;
onCurrentDirectoryChanged(ANIM_DOWN);
}
@@ -364,16 +369,15 @@ abstract class BaseActivity extends Activity {
}
void setDisplayAdvancedDevices(boolean display) {
- State state = getDisplayState();
LocalPreferences.setDisplayAdvancedDevices(this, display);
- state.showAdvanced = state.forceAdvanced | display;
+ mState.showAdvanced = mState.forceAdvanced | display;
RootsFragment.get(getFragmentManager()).onDisplayStateChanged();
invalidateOptionsMenu();
}
void setDisplayFileSize(boolean display) {
LocalPreferences.setDisplayFileSize(this, display);
- getDisplayState().showSize = display;
+ mState.showSize = display;
DirectoryFragment.get(getFragmentManager()).onDisplayStateChanged();
invalidateOptionsMenu();
}
@@ -386,7 +390,7 @@ abstract class BaseActivity extends Activity {
* Set state sort order based on explicit user action.
*/
void setUserSortOrder(int sortOrder) {
- getDisplayState().userSortOrder = sortOrder;
+ mState.userSortOrder = sortOrder;
DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged();
}
@@ -394,7 +398,7 @@ abstract class BaseActivity extends Activity {
* Set state mode based on explicit user action.
*/
void setUserMode(int mode) {
- getDisplayState().userMode = mode;
+ mState.userMode = mode;
DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
}
@@ -408,7 +412,7 @@ abstract class BaseActivity extends Activity {
@Override
protected void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
- state.putParcelable(EXTRA_STATE, getDisplayState());
+ state.putParcelable(EXTRA_STATE, mState);
}
@Override
@@ -417,16 +421,15 @@ abstract class BaseActivity extends Activity {
}
RootInfo getCurrentRoot() {
- State state = getDisplayState();
- if (state.stack.root != null) {
- return state.stack.root;
+ if (mState.stack.root != null) {
+ return mState.stack.root;
} else {
return mRoots.getRecentsRoot();
}
}
public DocumentInfo getCurrentDirectory() {
- return getDisplayState().stack.peek();
+ return mState.stack.peek();
}
public Executor getExecutorForCurrentDirectory() {
@@ -467,9 +470,8 @@ abstract class BaseActivity extends Activity {
// Update the restored stack to ensure we have freshest data
stack.updateDocuments(getContentResolver());
- State state = getDisplayState();
- state.stack = stack;
- state.stackTouched = true;
+ mState.stack = stack;
+ mState.stackTouched = true;
onCurrentDirectoryChanged(ANIM_SIDE);
} catch (FileNotFoundException e) {
@@ -499,9 +501,8 @@ abstract class BaseActivity extends Activity {
@Override
protected void onPostExecute(DocumentInfo result) {
if (result != null) {
- State state = getDisplayState();
- state.stack.push(result);
- state.stackTouched = true;
+ mState.stack.push(result);
+ mState.stackTouched = true;
onCurrentDirectoryChanged(ANIM_SIDE);
}
}
@@ -513,7 +514,9 @@ abstract class BaseActivity extends Activity {
@Override
protected Void doInBackground(Void... params) {
- State state = getDisplayState();
+ if (DEBUG && !mState.stack.isEmpty()) {
+ Log.w(mTag, "Overwriting existing stack.");
+ }
RootsCache roots = DocumentsApplication.getRootsCache(BaseActivity.this);
// Restore last stack for calling package
@@ -525,7 +528,7 @@ abstract class BaseActivity extends Activity {
mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0;
final byte[] rawStack = cursor.getBlob(
cursor.getColumnIndex(ResumeColumns.STACK));
- DurableUtils.readFromArray(rawStack, state.stack);
+ DurableUtils.readFromArray(rawStack, mState.stack);
mRestoredStack = true;
}
} catch (IOException e) {
@@ -536,13 +539,13 @@ abstract class BaseActivity extends Activity {
if (mRestoredStack) {
// Update the restored stack to ensure we have freshest data
- final Collection<RootInfo> matchingRoots = roots.getMatchingRootsBlocking(state);
+ final Collection<RootInfo> matchingRoots = roots.getMatchingRootsBlocking(mState);
try {
- state.stack.updateRoot(matchingRoots);
- state.stack.updateDocuments(getContentResolver());
+ mState.stack.updateRoot(matchingRoots);
+ mState.stack.updateDocuments(getContentResolver());
} catch (FileNotFoundException e) {
Log.w(mTag, "Failed to restore stack: " + e);
- state.stack.reset();
+ mState.stack.reset();
mRestoredStack = false;
}
}
@@ -553,7 +556,7 @@ abstract class BaseActivity extends Activity {
@Override
protected void onPostExecute(Void result) {
if (isDestroyed()) return;
- getDisplayState().restored = true;
+ mState.restored = true;
onCurrentDirectoryChanged(ANIM_NONE);
onStackRestored(mRestoredStack, mExternal);
}
@@ -597,10 +600,9 @@ abstract class BaseActivity extends Activity {
return;
}
- State state = getDisplayState();
- while (state.stack.size() > position + 1) {
- state.stackTouched = true;
- state.stack.pop();
+ while (mState.stack.size() > position + 1) {
+ mState.stackTouched = true;
+ mState.stack.pop();
}
onCurrentDirectoryChanged(ANIM_UP);
}
@@ -617,13 +619,12 @@ abstract class BaseActivity extends Activity {
final class StackAdapter extends BaseAdapter {
@Override
public int getCount() {
- return getDisplayState().stack.size();
+ return mState.stack.size();
}
@Override
public DocumentInfo getItem(int position) {
- State state = getDisplayState();
- return state.stack.get(state.stack.size() - position - 1);
+ return mState.stack.get(mState.stack.size() - position - 1);
}
@Override
@@ -711,13 +712,12 @@ abstract class BaseActivity extends Activity {
return;
}
- State state = getDisplayState();
- if (state.currentSearch != null) {
+ if (mState.currentSearch != null) {
mMenu.expandActionView();
mView.setIconified(false);
mView.clearFocus();
- mView.setQuery(state.currentSearch, false);
+ mView.setQuery(mState.currentSearch, false);
} else {
mView.clearFocus();
if (!mView.isIconified()) {
@@ -743,7 +743,7 @@ abstract class BaseActivity extends Activity {
mMenu.setVisible(visible);
if (!visible) {
- getDisplayState().currentSearch = null;
+ mState.currentSearch = null;
}
}
@@ -761,7 +761,7 @@ abstract class BaseActivity extends Activity {
}
boolean isSearching() {
- return getDisplayState().currentSearch != null;
+ return mState.currentSearch != null;
}
boolean isExpanded() {
@@ -776,7 +776,7 @@ abstract class BaseActivity extends Activity {
return false;
}
- getDisplayState().currentSearch = null;
+ mState.currentSearch = null;
onCurrentDirectoryChanged(ANIM_NONE);
return false;
}
@@ -795,7 +795,7 @@ abstract class BaseActivity extends Activity {
mIgnoreNextCollapse = false;
return true;
}
- getDisplayState().currentSearch = null;
+ mState.currentSearch = null;
onCurrentDirectoryChanged(ANIM_NONE);
return true;
}
@@ -803,7 +803,7 @@ abstract class BaseActivity extends Activity {
@Override
public boolean onQueryTextSubmit(String query) {
mSearchExpanded = true;
- getDisplayState().currentSearch = query;
+ mState.currentSearch = query;
mView.clearFocus();
onCurrentDirectoryChanged(ANIM_NONE);
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index f1492dc7b185..66f8acd3fc50 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -20,6 +20,7 @@ import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import android.app.Activity;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
@@ -37,6 +38,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
+import android.support.design.widget.Snackbar;
import android.text.format.DateUtils;
import android.util.Log;
import android.widget.Toast;
@@ -60,7 +62,6 @@ public class CopyService extends IntentService {
private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
- public static final String EXTRA_STACK = "com.android.documentsui.STACK";
public static final String EXTRA_FAILURE = "com.android.documentsui.FAILURE";
public static final String EXTRA_TRANSFER_MODE = "com.android.documentsui.TRANSFER_MODE";
@@ -107,21 +108,21 @@ public class CopyService extends IntentService {
* @param srcDocs A list of src files to copy.
* @param dstStack The copy destination stack.
*/
- public static void start(Context context, List<DocumentInfo> srcDocs, DocumentStack dstStack,
+ public static void start(Activity activity, List<DocumentInfo> srcDocs, DocumentStack dstStack,
int mode) {
- final Resources res = context.getResources();
- final Intent copyIntent = new Intent(context, CopyService.class);
+ final Resources res = activity.getResources();
+ final Intent copyIntent = new Intent(activity, CopyService.class);
copyIntent.putParcelableArrayListExtra(
EXTRA_SRC_LIST, new ArrayList<DocumentInfo>(srcDocs));
- copyIntent.putExtra(EXTRA_STACK, (Parcelable) dstStack);
+ copyIntent.putExtra(Shared.EXTRA_STACK, (Parcelable) dstStack);
copyIntent.putExtra(EXTRA_TRANSFER_MODE, mode);
int toastMessage = (mode == TRANSFER_MODE_COPY) ? R.plurals.copy_begin
: R.plurals.move_begin;
- Toast.makeText(context,
+ Snackbars.makeSnackbar(activity,
res.getQuantityString(toastMessage, srcDocs.size(), srcDocs.size()),
- Toast.LENGTH_SHORT).show();
- context.startService(copyIntent);
+ Snackbar.LENGTH_SHORT).show();
+ activity.startService(copyIntent);
}
@Override
@@ -140,7 +141,7 @@ public class CopyService extends IntentService {
}
final ArrayList<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST);
- final DocumentStack stack = intent.getParcelableExtra(EXTRA_STACK);
+ final DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK);
// Copy by default.
final int transferMode = intent.getIntExtra(EXTRA_TRANSFER_MODE, TRANSFER_MODE_COPY);
@@ -171,7 +172,7 @@ public class CopyService extends IntentService {
Log.e(TAG, mFailedFiles.size() + " files failed to copy");
final Context context = getApplicationContext();
final Intent navigateIntent = new Intent(context, FilesActivity.class);
- navigateIntent.putExtra(EXTRA_STACK, (Parcelable) stack);
+ navigateIntent.putExtra(Shared.EXTRA_STACK, (Parcelable) stack);
navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY);
navigateIntent.putExtra(EXTRA_TRANSFER_MODE, transferMode);
navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, mFailedFiles);
@@ -219,7 +220,7 @@ public class CopyService extends IntentService {
final Context context = getApplicationContext();
final Intent navigateIntent = new Intent(context, FilesActivity.class);
- navigateIntent.putExtra(EXTRA_STACK, (Parcelable) stack);
+ navigateIntent.putExtra(Shared.EXTRA_STACK, (Parcelable) stack);
final String contentTitle = getString(copying ? R.string.copy_notification_title
: R.string.move_notification_title);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index e408e6eb821d..c6425a6e41f2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -32,6 +32,7 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
+import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -39,7 +40,6 @@ import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
-import android.widget.Toast;
import com.android.documentsui.model.DocumentInfo;
@@ -147,7 +147,7 @@ public class CreateDirectoryFragment extends DialogFragment {
// Navigate into newly created child
mActivity.onDirectoryCreated(result);
} else {
- Toast.makeText(mActivity, R.string.create_error, Toast.LENGTH_SHORT).show();
+ Snackbars.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT).show();
}
mActivity.setPending(false);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 5eacf2132a3c..0abbf4e4996f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -44,7 +44,6 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
-import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -54,7 +53,6 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.CancellationSignal;
-import android.os.Handler;
import android.os.Looper;
import android.os.OperationCanceledException;
import android.os.Parcelable;
@@ -91,7 +89,6 @@ import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ImageView;
import android.widget.TextView;
-import android.widget.Toast;
import com.android.documentsui.BaseActivity.DocumentContext;
import com.android.documentsui.MultiSelectManager.Selection;
@@ -135,8 +132,6 @@ public class DirectoryFragment extends Fragment {
private Model mModel;
private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
- private final Handler mHandler = new Handler(Looper.getMainLooper());
-
private View mEmptyView;
private RecyclerView mRecView;
@@ -218,8 +213,6 @@ public class DirectoryFragment extends Fragment {
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- final Context context = inflater.getContext();
- final Resources res = context.getResources();
final View view = inflater.inflate(R.layout.fragment_directory, container, false);
mMessageBar = MessageBar.create(getChildFragmentManager());
@@ -424,7 +417,7 @@ public class DirectoryFragment extends Fragment {
}
CopyService.start(getActivity(), getDisplayState(this).selectedDocumentsForCopy,
- (DocumentStack) data.getParcelableExtra(CopyService.EXTRA_STACK),
+ (DocumentStack) data.getParcelableExtra(Shared.EXTRA_STACK),
data.getIntExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_NONE));
}
@@ -679,6 +672,7 @@ public class DirectoryFragment extends Fragment {
checkNotNull(mMenu);
// Delegate update logic to our owning action, since specialized logic is desired.
mFragmentTuner.updateActionMenu(mMenu, mType, mNoDeleteCount == 0);
+ Menus.disableHiddenItems(mMenu);
}
@Override
@@ -800,13 +794,12 @@ public class DirectoryFragment extends Fragment {
private void deleteDocuments(final Selection selected) {
Context context = getActivity();
- ContentResolver resolver = context.getContentResolver();
String message = Shared.getQuantityString(context, R.plurals.deleting, selected.size());
mModel.markForDeletion(selected);
- Activity activity = getActivity();
- Snackbar.make(this.getView(), message, Snackbar.LENGTH_LONG)
+ final Activity activity = getActivity();
+ Snackbars.makeSnackbar(activity, message, Snackbar.LENGTH_LONG)
.setAction(
R.string.undo,
new android.view.View.OnClickListener() {
@@ -821,11 +814,11 @@ public class DirectoryFragment extends Fragment {
mModel.undoDeletion();
} else {
mModel.finalizeDeletion(
- new Runnable() {
+ new Model.DeletionListener() {
@Override
- public void run() {
- Snackbar.make(
- DirectoryFragment.this.getView(),
+ public void onError() {
+ Snackbars.makeSnackbar(
+ activity,
R.string.toast_failed_delete,
Snackbar.LENGTH_LONG)
.show();
@@ -1245,9 +1238,11 @@ public class DirectoryFragment extends Fragment {
private void copyDocuments(final List<DocumentInfo> docs, final DocumentInfo destination) {
if (!canCopy(docs, destination)) {
- Toast.makeText(
+ Snackbars.makeSnackbar(
getActivity(),
- R.string.clipboard_files_cannot_paste, Toast.LENGTH_SHORT).show();
+ R.string.clipboard_files_cannot_paste,
+ Snackbar.LENGTH_SHORT)
+ .show();
return;
}
@@ -1297,10 +1292,10 @@ public class DirectoryFragment extends Fragment {
void onDocumentsReady(List<DocumentInfo> docs) {
mClipper.clipDocuments(docs);
Activity activity = getActivity();
- Toast.makeText(activity,
+ Snackbars.makeSnackbar(activity,
activity.getResources().getQuantityString(
R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
- Toast.LENGTH_SHORT).show();
+ Snackbar.LENGTH_SHORT).show();
}
}.execute(items);
}
@@ -1607,23 +1602,25 @@ public class DirectoryFragment extends Fragment {
@Override
public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+ boolean copyEnabled = mManaging && dirType != TYPE_RECENT_OPEN;
+ // TODO: The selection needs to be deletable.
+ boolean moveEnabled =
+ SystemProperties.getBoolean("debug.documentsui.enable_move", false);
+ menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(copyEnabled);
final MenuItem open = menu.findItem(R.id.menu_open);
final MenuItem share = menu.findItem(R.id.menu_share);
final MenuItem delete = menu.findItem(R.id.menu_delete);
final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
- final MenuItem copyToClipboard = menu.findItem(R.id.menu_copy_to_clipboard);
open.setVisible(!mManaging);
share.setVisible(mManaging);
delete.setVisible(mManaging && canDelete);
- // Disable copying from the Recents view.
- copyTo.setVisible(mManaging && dirType != TYPE_RECENT_OPEN);
- moveTo.setVisible(SystemProperties.getBoolean("debug.documentsui.enable_move", false));
-
- // Only shown in files mode.
- copyToClipboard.setVisible(false);
+ copyTo.setVisible(copyEnabled);
+ copyTo.setEnabled(copyEnabled);
+ moveTo.setVisible(moveEnabled);
+ moveTo.setEnabled(moveEnabled);
}
@Override
@@ -1637,13 +1634,14 @@ public class DirectoryFragment extends Fragment {
@Override
public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+ menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(dirType != TYPE_RECENT_OPEN);
+
menu.findItem(R.id.menu_share).setVisible(true);
menu.findItem(R.id.menu_delete).setVisible(canDelete);
- menu.findItem(R.id.menu_copy_to_clipboard).setVisible(true);
menu.findItem(R.id.menu_open).setVisible(false);
- menu.findItem(R.id.menu_copy_to).setVisible(false);
- menu.findItem(R.id.menu_move_to).setVisible(false);
+ menu.findItem(R.id.menu_copy_to).setVisible(true);
+ menu.findItem(R.id.menu_move_to).setVisible(true);
}
@Override
@@ -1864,9 +1862,9 @@ public class DirectoryFragment extends Fragment {
* @param view The view which will be used to interact with the user (e.g. surfacing
* snackbars) for errors, info, etc.
*/
- void finalizeDeletion(Runnable errorCallback) {
+ void finalizeDeletion(DeletionListener listener) {
final ContentResolver resolver = mContext.getContentResolver();
- DeleteFilesTask task = new DeleteFilesTask(resolver, errorCallback);
+ DeleteFilesTask task = new DeleteFilesTask(resolver, listener);
task.execute();
}
@@ -1876,16 +1874,16 @@ public class DirectoryFragment extends Fragment {
*/
private class DeleteFilesTask extends AsyncTask<Void, Void, List<DocumentInfo>> {
private ContentResolver mResolver;
- private Runnable mErrorCallback;
+ private DeletionListener mListener;
/**
* @param resolver A ContentResolver for performing the actual file deletions.
* @param errorCallback A Runnable that is executed in the event that one or more errors
* occured while copying files. Execution will occur on the UI thread.
*/
- public DeleteFilesTask(ContentResolver resolver, Runnable errorCallback) {
+ public DeleteFilesTask(ContentResolver resolver, DeletionListener listener) {
mResolver = resolver;
- mErrorCallback = errorCallback;
+ mListener = listener;
}
@Override
@@ -1919,15 +1917,29 @@ public class DirectoryFragment extends Fragment {
if (hadTrouble) {
// TODO show which files failed? b/23720103
- mErrorCallback.run();
+ mListener.onError();
if (DEBUG) Log.d(TAG, "Deletion task completed. Some deletions failed.");
} else {
if (DEBUG) Log.d(TAG, "Deletion task completed successfully.");
}
mMarkedForDeletion.clear();
+
+ mListener.onCompletion();
}
}
+ static class DeletionListener {
+ /**
+ * Called when deletion has completed (regardless of whether an error occurred).
+ */
+ void onCompletion() {}
+
+ /**
+ * Called at the end of a deletion operation that produced one or more errors.
+ */
+ void onError() {}
+ }
+
void addUpdateListener(UpdateListener listener) {
checkState(mUpdateListener == null);
mUpdateListener = listener;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 4658fe366bd8..6b428f58441c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -41,6 +41,7 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.DocumentsContract;
+import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -48,7 +49,6 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.Spinner;
-import android.widget.Toast;
import android.widget.Toolbar;
import com.android.documentsui.RecentsProvider.RecentColumns;
@@ -89,8 +89,6 @@ public class DocumentsActivity extends BaseActivity {
setTheme(R.style.DocumentsNonDialogTheme);
}
- final Context context = this;
-
if (mShowAsDialog) {
mDrawer = DrawerController.createDummy();
@@ -314,42 +312,36 @@ public class DocumentsActivity extends BaseActivity {
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- final RootInfo root = getCurrentRoot();
final DocumentInfo cwd = getCurrentDirectory();
final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
final MenuItem grid = menu.findItem(R.id.menu_grid);
final MenuItem list = menu.findItem(R.id.menu_list);
- final MenuItem advanced = menu.findItem(R.id.menu_advanced);
final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
final MenuItem settings = menu.findItem(R.id.menu_settings);
- boolean fileSizeVisible = mState.showSize && !mState.forceSize;
- if (mState.action == ACTION_CREATE
+ boolean recents = cwd == null;
+ boolean picking = mState.action == ACTION_CREATE
|| mState.action == ACTION_OPEN_TREE
- || mState.action == ACTION_OPEN_COPY_DESTINATION) {
- createDir.setVisible(cwd != null && cwd.isCreateSupported());
- mSearchManager.showMenu(false);
-
- // No display options in recent directories
- if (cwd == null) {
- grid.setVisible(false);
- list.setVisible(false);
- fileSizeVisible = false;
- }
+ || mState.action == ACTION_OPEN_COPY_DESTINATION;
- if (mState.action == ACTION_CREATE) {
- final FragmentManager fm = getFragmentManager();
- SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
- }
- } else {
- createDir.setVisible(false);
- }
+ createDir.setVisible(picking && !recents && cwd.isCreateSupported());
+ mSearchManager.showMenu(!picking);
- advanced.setVisible(!mState.forceAdvanced);
- fileSize.setVisible(fileSizeVisible);
+ // No display options in recent directories
+ grid.setVisible(!(picking && recents));
+ list.setVisible(!(picking && recents));
+
+ fileSize.setVisible(fileSize.isVisible() && !picking);
settings.setVisible(false);
+ if (mState.action == ACTION_CREATE) {
+ final FragmentManager fm = getFragmentManager();
+ SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
+ }
+
+ Menus.disableHiddenItems(menu);
+
return true;
}
@@ -510,7 +502,7 @@ public class DocumentsActivity extends BaseActivity {
} else if (mState.action == ACTION_OPEN_COPY_DESTINATION) {
// Picking a copy destination is only used internally by us, so we
// don't need to extend permissions to the caller.
- intent.putExtra(CopyService.EXTRA_STACK, (Parcelable) mState.stack);
+ intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack);
intent.putExtra(CopyService.EXTRA_TRANSFER_MODE, mState.transferMode);
} else {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
@@ -611,8 +603,8 @@ public class DocumentsActivity extends BaseActivity {
if (result != null) {
onTaskFinished(result);
} else {
- Toast.makeText(DocumentsActivity.this, R.string.save_error, Toast.LENGTH_SHORT)
- .show();
+ Snackbars.makeSnackbar(
+ DocumentsActivity.this, R.string.save_error, Snackbar.LENGTH_SHORT).show();
}
setPending(false);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java b/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java
index ea0c18acf26f..120f6106a7a0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java
@@ -66,7 +66,7 @@ public class FailureDialogFragment extends DialogFragment
if (whichButton == DialogInterface.BUTTON_POSITIVE) {
CopyService.start(getActivity(), mFailedSrcList,
(DocumentStack) getActivity().getIntent().getParcelableExtra(
- CopyService.EXTRA_STACK),
+ Shared.EXTRA_STACK),
mTransferMode);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 7e9531b777fa..70ddf5916f2c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -19,6 +19,7 @@ package com.android.documentsui;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.Shared.DEBUG;
import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.internal.util.Preconditions.checkState;
import android.app.Activity;
import android.app.FragmentManager;
@@ -29,7 +30,10 @@ import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Parcelable;
+import android.provider.DocumentsContract;
import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
@@ -37,7 +41,6 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.BaseAdapter;
import android.widget.Spinner;
-import android.widget.Toast;
import android.widget.Toolbar;
import com.android.documentsui.RecentsProvider.ResumeColumns;
@@ -84,32 +87,49 @@ public class FilesActivity extends BaseActivity {
mDrawer = DrawerController.create(this);
RootsFragment.show(getFragmentManager(), null);
- if (!mState.restored) {
- Uri rootUri = getIntent().getData();
-
- // If we've got a specific root to display, restore that root using a dedicated
- // authority. That way a misbehaving provider won't result in an ANR.
- if (rootUri != null) {
- new RestoreRootTask(rootUri).executeOnExecutor(
- ProviderExecutor.forAuthority(rootUri.getAuthority()));
+
+ if (mState.restored) {
+ onCurrentDirectoryChanged(ANIM_NONE);
+ } else {
+ Intent intent = getIntent();
+ Uri uri = intent.getData();
+
+ // If a non-empty stack is present in our state it was read (presumably)
+ // from EXTRA_STACK intent extra. In this case, we'll skip other means of
+ // loading or restoring the stack.
+ if (!mState.stack.isEmpty()) {
+ // When restoring from a stack, if a URI is present, it should only ever
+ // be a launch URI. Launch URIs support sensible activity management, but
+ // don't specify an real content target.
+ if (uri != null) {
+ checkState(LauncherActivity.isLaunchUri(uri));
+ }
+ onCurrentDirectoryChanged(ANIM_NONE);
+ } else if (DocumentsContract.isRootUri(this, uri)) {
+ // If we've got a specific root to display, restore that root using a dedicated
+ // authority. That way a misbehaving provider won't result in an ANR.
+ new RestoreRootTask(uri).executeOnExecutor(
+ ProviderExecutor.forAuthority(uri.getAuthority()));
} else {
+ // Finally, we try to restore a stack from recents.
new RestoreStackTask().execute();
}
+ // TODO: Ensure we're handling CopyService errors correctly across all activities.
// Show a failure dialog if there was a failed operation.
- final Intent intent = getIntent();
- final DocumentStack dstStack = intent.getParcelableExtra(CopyService.EXTRA_STACK);
final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0);
final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
CopyService.TRANSFER_MODE_NONE);
if (failure != 0) {
final ArrayList<DocumentInfo> failedSrcList =
intent.getParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST);
- FailureDialogFragment.show(getFragmentManager(), failure, failedSrcList, dstStack,
+ FailureDialogFragment.show(
+ getFragmentManager(),
+ failure,
+ failedSrcList,
+ mState.stack,
transferMode);
}
- } else {
- onCurrentDirectoryChanged(ANIM_NONE);
}
}
@@ -125,7 +145,7 @@ public class FilesActivity extends BaseActivity {
// Options specific to the DocumentsActivity.
checkArgument(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
- final DocumentStack stack = intent.getParcelableExtra(CopyService.EXTRA_STACK);
+ final DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK);
if (stack != null) {
state.stack = stack;
}
@@ -205,36 +225,51 @@ public class FilesActivity extends BaseActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
- boolean shown = super.onPrepareOptionsMenu(menu);
+ super.onPrepareOptionsMenu(menu);
- final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
-
- boolean canCreateDir = canCreateDirectory();
+ final MenuItem newWindow = menu.findItem(R.id.menu_new_window);
+ final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
createDir.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
- createDir.setVisible(canCreateDir);
+ createDir.setVisible(true);
+ createDir.setEnabled(canCreateDirectory());
- pasteFromCb.setVisible(true);
- pasteFromCb.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
- return shown;
+ newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ newWindow.setVisible(mProductivityDevice);
+
+ Menus.disableHiddenItems(menu, pasteFromCb);
+ return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- final int id = item.getItemId();
- if (id == R.id.menu_paste_from_clipboard) {
- DirectoryFragment dir = DirectoryFragment.get(getFragmentManager());
- dir = DirectoryFragment.get(getFragmentManager());
- dir.pasteFromClipboard();
- return true;
+ switch (item.getItemId()) {
+ case R.id.menu_create_dir:
+ checkState(canCreateDirectory());
+ showCreateDirectoryDialog();
+ return true;
+ case R.id.menu_new_window:
+ createNewWindow();
+ return true;
+ case R.id.menu_paste_from_clipboard:
+ DirectoryFragment dir = DirectoryFragment.get(getFragmentManager());
+ dir = DirectoryFragment.get(getFragmentManager());
+ dir.pasteFromClipboard();
+ return true;
}
return super.onOptionsItemSelected(item);
}
+ private void createNewWindow() {
+ Intent intent = LauncherActivity.createLaunchIntent(this);
+ intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack);
+ startActivity(intent);
+ }
+
@Override
void onDirectoryChanged(int anim) {
final FragmentManager fm = getFragmentManager();
@@ -305,7 +340,7 @@ public class FilesActivity extends BaseActivity {
try {
startActivity(intent);
} catch (ActivityNotFoundException ex2) {
- Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
+ Snackbars.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT).show();
}
}
@@ -317,19 +352,13 @@ public class FilesActivity extends BaseActivity {
dir = DirectoryFragment.get(getFragmentManager());
dir.selectAllFiles();
return true;
- case KeyEvent.KEYCODE_N:
- if (event.isShiftPressed() && canCreateDirectory()) {
- showCreateDirectoryDialog();
- return true;
- }
case KeyEvent.KEYCODE_C:
// TODO: Should be statically bound using alphabeticShortcut. See b/21330356.
dir = DirectoryFragment.get(getFragmentManager());
dir.copySelectedToClipboard();
- // TODO: Cancel action mode in directory fragment.
}
- return super.onKeyUp(keyCode, event);
+ return super.onKeyShortcut(keyCode, event);
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
new file mode 100644
index 000000000000..c29937d68cdf
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
@@ -0,0 +1,93 @@
+/*
+ * 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.documentsui;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.AppTask;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Provides FilesActivity task grouping support. This allows multiple FilesActivities to be
+ * launched (a behavior imparted by way of {@code documentLaunchMode="intoExisting"} and
+ * our use of pseudo document {@link Uri}s. This also lets us move an existing task
+ * to the foreground when a suitable task exists.
+ *
+ * Requires that {@code documentLaunchMode="intoExisting"} be set on target activity.
+ *
+ */
+public class LauncherActivity extends Activity {
+
+ public static final String LAUNCH_CONTROL_AUTHORITY = "com.android.documentsui.launchControl";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ ActivityManager activities = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ List<AppTask> tasks = activities.getAppTasks();
+
+ AppTask raiseTask = null;
+ for (AppTask task : tasks) {
+ Uri taskUri = task.getTaskInfo().baseIntent.getData();
+ if (taskUri != null && isLaunchUri(taskUri)) {
+ raiseTask = task;
+ }
+ }
+
+ if (raiseTask == null) {
+ launchFilesTask();
+ } else {
+ raiseFilesTask(activities, raiseTask.getTaskInfo());
+ }
+
+ finish();
+ }
+
+ private void launchFilesTask() {
+ Intent intent = createLaunchIntent(this);
+ startActivity(intent);
+ }
+
+ private void raiseFilesTask(ActivityManager activities, RecentTaskInfo task) {
+ activities.moveTaskToFront(task.id, 0);
+ }
+
+ static Intent createLaunchIntent(Context context) {
+ Intent intent = new Intent(context, FilesActivity.class);
+ intent.setData(buildLaunchUri());
+ return intent;
+ }
+
+ private static Uri buildLaunchUri() {
+ return new Uri.Builder()
+ .authority(LAUNCH_CONTROL_AUTHORITY)
+ .fragment(String.valueOf(System.currentTimeMillis()))
+ .build();
+ }
+
+ static boolean isLaunchUri(@Nullable Uri uri) {
+ return uri != null && LAUNCH_CONTROL_AUTHORITY.equals(uri.getAuthority());
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
index 4754899b95cc..14a33f9c1cc1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
@@ -31,12 +31,12 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.DocumentsContract;
+import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.BaseAdapter;
import android.widget.Spinner;
-import android.widget.Toast;
import android.widget.Toolbar;
import com.android.documentsui.RecentsProvider.ResumeColumns;
@@ -140,6 +140,7 @@ public class ManageRootActivity extends BaseActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
+ Menus.disableHiddenItems(menu);
return true;
}
@@ -184,7 +185,8 @@ public class ManageRootActivity extends BaseActivity {
try {
startActivity(view);
} catch (ActivityNotFoundException ex2) {
- Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
+ Snackbars.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT)
+ .show();
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Menus.java b/packages/DocumentsUI/src/com/android/documentsui/Menus.java
new file mode 100644
index 000000000000..3f43a3d30c8d
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/Menus.java
@@ -0,0 +1,50 @@
+/*
+ * 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.documentsui;
+
+import android.view.Menu;
+import android.view.MenuItem;
+
+final class Menus {
+
+ private Menus() {}
+
+ /**
+ * Disables hidden menu items so that they are not invokable via command shortcuts
+ */
+ static void disableHiddenItems(Menu menu, MenuItem... exclusions) {
+ for (int i = 0; i < menu.size(); i++) {
+ MenuItem item = menu.getItem(i);
+ if (item.isVisible()) {
+ continue;
+ }
+ if (contains(exclusions, item)) {
+ continue;
+ }
+ item.setEnabled(false);
+ }
+ }
+
+ private static boolean contains(MenuItem[] exclusions, MenuItem item) {
+ for (int x = 0; x < exclusions.length; x++) {
+ if (exclusions[x] == item) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 9c884d4ef8c6..a4d6dc57cd34 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -18,12 +18,11 @@ package com.android.documentsui;
import android.content.Context;
-/**
- * @hide
- */
+/** @hide */
public final class Shared {
public static final boolean DEBUG = true;
public static final String TAG = "Documents";
+ public static final String EXTRA_STACK = "com.android.documentsui.STACK";
/**
* Generates a formatted quantity string.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java b/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
new file mode 100644
index 000000000000..f48b298a4f2f
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
@@ -0,0 +1,37 @@
+/*
+ * 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.documentsui;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.app.Activity;
+import android.support.design.widget.Snackbar;
+import android.view.View;
+
+final class Snackbars {
+ private Snackbars() {}
+
+ public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) {
+ return Snackbars.makeSnackbar(activity, activity.getResources().getText(messageId), duration);
+ }
+
+ public static final Snackbar makeSnackbar(Activity activity, CharSequence message, int duration)
+ {
+ final View view = checkNotNull(activity.findViewById(R.id.coordinator_layout));
+ return Snackbar.make(view, message, duration);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index bbffad326dff..4306a0e024a2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -44,14 +44,14 @@ public class State implements android.os.Parcelable {
public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
public boolean allowMultiple;
- public boolean forceSize ;
+ public boolean forceSize;
public boolean showSize;
- public boolean localOnly ;
- public boolean forceAdvanced ;
- public boolean showAdvanced ;
- public boolean stackTouched ;
- public boolean restored ;
- public boolean directoryCopy ;
+ public boolean localOnly;
+ public boolean forceAdvanced;
+ public boolean showAdvanced;
+ public boolean stackTouched;
+ public boolean restored;
+ public boolean directoryCopy;
/** Transfer mode for file copy/move operations. */
public int transferMode;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java
index 568e9e403960..fc42c3b12545 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java
@@ -425,7 +425,7 @@ public class CopyTest extends ServiceTestCase<CopyService> {
stack.push(DocumentInfo.fromUri(mResolver, dst));
final Intent copyIntent = new Intent(mContext, CopyService.class);
copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST, srcDocs);
- copyIntent.putExtra(CopyService.EXTRA_STACK, (Parcelable) stack);
+ copyIntent.putExtra(Shared.EXTRA_STACK, (Parcelable) stack);
// startService(copyIntent);
return copyIntent;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
index 1895a6e66450..98ffb77c4cd6 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
@@ -34,6 +34,9 @@ import com.android.documentsui.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
public class DirectoryFragmentModelTest extends AndroidTestCase {
@@ -77,14 +80,6 @@ public class DirectoryFragmentModelTest extends AndroidTestCase {
delete(2, 4);
assertEquals(ITEM_COUNT - 2, model.getItemCount());
-
- // Finalize the deletion. Provide a callback that just ignores errors.
- model.finalizeDeletion(
- new Runnable() {
- @Override
- public void run() {}
- });
- assertEquals(ITEM_COUNT - 2, model.getItemCount());
}
// Tests that the item count is correct after a deletion is undone.
@@ -95,7 +90,6 @@ public class DirectoryFragmentModelTest extends AndroidTestCase {
// Undo the deletion
model.undoDeletion();
assertEquals(ITEM_COUNT, model.getItemCount());
-
}
// Tests that the right things are marked for deletion.
@@ -125,6 +119,15 @@ public class DirectoryFragmentModelTest extends AndroidTestCase {
assertEquals("0", docs.get(0).documentId);
assertEquals("1", docs.get(1).documentId);
assertEquals("4", docs.get(2).documentId);
+
+ TestDeletionListener testListener = new TestDeletionListener();
+ model.finalizeDeletion(testListener);
+ testListener.waitForDone();
+
+ docs = getDocumentInfo(0, 1, 2);
+ assertEquals("0", docs.get(0).documentId);
+ assertEquals("1", docs.get(1).documentId);
+ assertEquals("2", docs.get(2).documentId);
}
// Tests that Model.getItem returns the right items after a deletion is undone.
@@ -176,4 +179,20 @@ public class DirectoryFragmentModelTest extends AndroidTestCase {
return null;
}
}
+
+ private static class TestDeletionListener extends Model.DeletionListener {
+ final CountDownLatch mSignal = new CountDownLatch(1);
+
+ @Override
+ public void onCompletion() {
+ mSignal.countDown();
+ }
+
+ public void waitForDone() {
+ try {
+ boolean timeout = mSignal.await(10, TimeUnit.SECONDS);
+ assertTrue("Timed out waiting for deletion completion", timeout);
+ } catch (InterruptedException e) {}
+ }
+ }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
index 25d4ed4183f0..2447469f9c64 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.support.v7.widget.RecyclerView;
+import android.test.AndroidTestCase;
import android.util.SparseBooleanArray;
import android.view.MotionEvent;
import android.view.View;
@@ -27,8 +28,6 @@ import android.view.ViewGroup;
import com.android.documentsui.MultiSelectManager.Selection;
-import org.junit.Before;
-import org.junit.Test;
import org.mockito.Mockito;
import java.util.ArrayList;
@@ -36,7 +35,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
-public class MultiSelectManagerTest {
+public class MultiSelectManagerTest extends AndroidTestCase {
private static final List<String> items;
static {
@@ -54,7 +53,6 @@ public class MultiSelectManagerTest {
private TestCallback mCallback;
private EventHelper mEventHelper;
- @Before
public void setUp() throws Exception {
mAdapter = new TestAdapter(items);
mCallback = new TestCallback();
@@ -63,65 +61,61 @@ public class MultiSelectManagerTest {
mManager.addCallback(mCallback);
}
- @Test
- public void mouseClick_StartsSelectionMode() {
+ public void testMouseClick_StartsSelectionMode() {
click(7);
assertSelection(7);
}
- @Test
- public void mouseClick_ShiftClickExtendsSelection() {
+ public void testMouseClick_NotifiesSelectionChanged() {
+ click(7);
+ mCallback.assertSelectionChanged();
+ }
+
+ public void testMouseClick_ShiftClickExtendsSelection() {
longPress(7);
shiftClick(11);
assertRangeSelection(7, 11);
}
- @Test
- public void mouseClick_NoPosition_ClearsSelection() {
+ public void testMouseClick_NoPosition_ClearsSelection() {
longPress(7);
click(11);
click(RecyclerView.NO_POSITION);
assertSelection();
}
- @Test
- public void setSelectionFocusBegin() {
+ public void testSetSelectionFocusBegin() {
mManager.setItemSelected(7, true);
mManager.setSelectionFocusBegin(7);
shiftClick(11);
assertRangeSelection(7, 11);
}
- @Test
- public void longPress_StartsSelectionMode() {
+ public void testLongPress_StartsSelectionMode() {
longPress(7);
assertSelection(7);
}
- @Test
- public void longPress_SecondPressExtendsSelection() {
+ public void testLongPress_SecondPressExtendsSelection() {
longPress(7);
longPress(99);
assertSelection(7, 99);
}
- @Test
- public void singleTapUp_UnselectsSelectedItem() {
+ public void testSingleTapUp_UnselectsSelectedItem() {
longPress(7);
tap(7);
assertSelection();
}
- @Test
- public void singleTapUp_NoPosition_ClearsSelection() {
+ public void testSingleTapUp_NoPosition_ClearsSelection() {
longPress(7);
tap(11);
tap(RecyclerView.NO_POSITION);
assertSelection();
}
- @Test
- public void singleTapUp_ExtendsSelection() {
+ public void testSingleTapUp_ExtendsSelection() {
longPress(99);
tap(7);
tap(13);
@@ -129,30 +123,26 @@ public class MultiSelectManagerTest {
assertSelection(7, 99, 13, 129899);
}
- @Test
- public void singleTapUp_ShiftCreatesRangeSelection() {
+ public void testSingleTapUp_ShiftCreatesRangeSelection() {
longPress(7);
shiftTap(17);
assertRangeSelection(7, 17);
}
- @Test
- public void singleTapUp_ShiftCreatesRangeSeletion_Backwards() {
+ public void testSingleTapUp_ShiftCreatesRangeSeletion_Backwards() {
longPress(17);
shiftTap(7);
assertRangeSelection(7, 17);
}
- @Test
- public void singleTapUp_SecondShiftClickExtendsSelection() {
+ public void testSingleTapUp_SecondShiftClickExtendsSelection() {
longPress(7);
shiftTap(11);
shiftTap(17);
assertRangeSelection(7, 17);
}
- @Test
- public void singleTapUp_MultipleContiguousRangesSelected() {
+ public void testSingleTapUp_MultipleContiguousRangesSelected() {
longPress(7);
shiftTap(11);
tap(20);
@@ -162,16 +152,14 @@ public class MultiSelectManagerTest {
assertSelectionSize(11);
}
- @Test
- public void singleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick() {
+ public void testSingleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick() {
longPress(7);
shiftTap(17);
shiftTap(10);
assertRangeSelection(7, 10);
}
- @Test
- public void singleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick_Backwards() {
+ public void testSingleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick_Backwards() {
mManager.onLongPress(TestInputEvent.tap(17));
shiftTap(7);
shiftTap(14);
@@ -179,16 +167,14 @@ public class MultiSelectManagerTest {
}
- @Test
- public void singleTapUp_ShiftReversesSelectionDirection() {
+ public void testSingleTapUp_ShiftReversesSelectionDirection() {
longPress(7);
shiftTap(17);
shiftTap(0);
assertRangeSelection(0, 7);
}
- @Test
- public void singleSelectMode() {
+ public void testSingleSelectMode() {
mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE);
mManager.addCallback(mCallback);
longPress(20);
@@ -196,8 +182,7 @@ public class MultiSelectManagerTest {
assertSelection(13);
}
- @Test
- public void singleSelectMode_ShiftTap() {
+ public void testSingleSelectMode_ShiftTap() {
mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE);
mManager.addCallback(mCallback);
longPress(13);
@@ -205,8 +190,7 @@ public class MultiSelectManagerTest {
assertSelection(20);
}
- @Test
- public void provisionaSelection() {
+ public void testProvisionalSelection() {
Selection s = mManager.getSelection();
assertSelection();
@@ -298,6 +282,7 @@ public class MultiSelectManagerTest {
Set<Integer> ignored = new HashSet<>();
private int mLastChangedPosition;
private boolean mLastChangedSelected;
+ private boolean mSelectionChanged = false;
@Override
public void onItemStateChanged(int position, boolean selected) {
@@ -311,7 +296,13 @@ public class MultiSelectManagerTest {
}
@Override
- public void onSelectionChanged() {}
+ public void onSelectionChanged() {
+ mSelectionChanged = true;
+ }
+
+ void assertSelectionChanged() {
+ assertTrue(mSelectionChanged);
+ }
}
private static final class TestHolder extends RecyclerView.ViewHolder {
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java
index 87d7e15a4072..aa50b48e6c16 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java
@@ -22,14 +22,12 @@ import static org.junit.Assert.assertTrue;
import android.graphics.Point;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.test.AndroidTestCase;
import android.util.SparseBooleanArray;
import com.android.documentsui.MultiSelectManager.GridModel;
-import org.junit.After;
-import org.junit.Test;
-
-public class MultiSelectManager_GridModelTest {
+public class MultiSelectManager_GridModelTest extends AndroidTestCase {
private static final int VIEW_PADDING_PX = 5;
private static final int CHILD_VIEW_EDGE_PX = 100;
@@ -53,14 +51,13 @@ public class MultiSelectManager_GridModelTest {
});
}
- @After
+ @Override
public void tearDown() {
model = null;
helper = null;
lastSelection = null;
}
- @Test
public void testSelectionLeftOfItems() {
setUp(20, 5);
model.startSelection(new Point(0, 10));
@@ -69,7 +66,6 @@ public class MultiSelectManager_GridModelTest {
assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
}
- @Test
public void testSelectionRightOfItems() {
setUp(20, 4);
model.startSelection(new Point(viewWidth - 1, 10));
@@ -78,7 +74,6 @@ public class MultiSelectManager_GridModelTest {
assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
}
- @Test
public void testSelectionAboveItems() {
setUp(20, 4);
model.startSelection(new Point(10, 0));
@@ -87,7 +82,6 @@ public class MultiSelectManager_GridModelTest {
assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
}
- @Test
public void testSelectionBelowItems() {
setUp(5, 4);
model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
@@ -96,7 +90,6 @@ public class MultiSelectManager_GridModelTest {
assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
}
- @Test
public void testVerticalSelectionBetweenItems() {
setUp(20, 4);
model.startSelection(new Point(106, 0));
@@ -105,7 +98,6 @@ public class MultiSelectManager_GridModelTest {
assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
}
- @Test
public void testHorizontalSelectionBetweenItems() {
setUp(20, 4);
model.startSelection(new Point(0, 105));
@@ -114,7 +106,6 @@ public class MultiSelectManager_GridModelTest {
assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
}
- @Test
public void testGrowingAndShrinkingSelection() {
setUp(20, 4);
model.startSelection(new Point(0, 0));
@@ -145,7 +136,6 @@ public class MultiSelectManager_GridModelTest {
assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
}
- @Test
public void testSelectionMovingAroundOrigin() {
setUp(16, 4);
model.startSelection(new Point(210, 210));
@@ -160,7 +150,6 @@ public class MultiSelectManager_GridModelTest {
assertEquals(10, model.getPositionNearestOrigin());
}
- @Test
public void testScrollingBandSelect() {
setUp(40, 4);
model.startSelection(new Point(0, 0));
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java
index 51b542b2ae8c..eddf4ef6fede 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java
@@ -18,16 +18,16 @@ package com.android.documentsui;
import static org.junit.Assert.*;
+import android.test.AndroidTestCase;
+
import com.android.documentsui.MultiSelectManager.Selection;
-import org.junit.Before;
-import org.junit.Test;
-public class MultiSelectManager_SelectionTest {
+public class MultiSelectManager_SelectionTest extends AndroidTestCase{
private Selection selection;
- @Before
+ @Override
public void setUp() throws Exception {
selection = new Selection();
selection.add(3);
@@ -35,8 +35,7 @@ public class MultiSelectManager_SelectionTest {
selection.add(9);
}
- @Test
- public void add() {
+ public void testAdd() {
// We added in setUp.
assertEquals(3, selection.size());
assertContains(3);
@@ -44,29 +43,25 @@ public class MultiSelectManager_SelectionTest {
assertContains(9);
}
- @Test
- public void remove() {
+ public void testRemove() {
selection.remove(3);
selection.remove(5);
assertEquals(1, selection.size());
assertContains(9);
}
- @Test
- public void clear() {
+ public void testClear() {
selection.clear();
assertEquals(0, selection.size());
}
- @Test
- public void isEmpty() {
+ public void testIsEmpty() {
assertTrue(new Selection().isEmpty());
selection.clear();
assertTrue(selection.isEmpty());
}
- @Test
- public void sizeAndGet() {
+ public void testSizeAndGet() {
Selection other = new Selection();
for (int i = 0; i < selection.size(); i++) {
other.add(selection.get(i));
@@ -74,13 +69,11 @@ public class MultiSelectManager_SelectionTest {
assertEquals(selection.size(), other.size());
}
- @Test
- public void equalsSelf() {
+ public void testEqualsSelf() {
assertEquals(selection, selection);
}
- @Test
- public void equalsOther() {
+ public void testEqualsOther() {
Selection other = new Selection();
other.add(3);
other.add(5);
@@ -89,23 +82,20 @@ public class MultiSelectManager_SelectionTest {
assertEquals(selection.hashCode(), other.hashCode());
}
- @Test
- public void equalsCopy() {
+ public void testEqualsCopy() {
Selection other = new Selection();
other.copyFrom(selection);
assertEquals(selection, other);
assertEquals(selection.hashCode(), other.hashCode());
}
- @Test
- public void notEquals() {
+ public void testNotEquals() {
Selection other = new Selection();
other.add(789);
assertFalse(selection.equals(other));
}
- @Test
- public void expandBefore() {
+ public void testExpandBefore() {
selection.expand(2, 10);
assertEquals(3, selection.size());
assertContains(13);
@@ -113,8 +103,7 @@ public class MultiSelectManager_SelectionTest {
assertContains(19);
}
- @Test
- public void expandAfter() {
+ public void testExpandAfter() {
selection.expand(10, 10);
assertEquals(3, selection.size());
assertContains(3);
@@ -122,8 +111,7 @@ public class MultiSelectManager_SelectionTest {
assertContains(9);
}
- @Test
- public void expandSplit() {
+ public void testExpandSplit() {
selection.expand(5, 10);
assertEquals(3, selection.size());
assertContains(3);
@@ -131,8 +119,7 @@ public class MultiSelectManager_SelectionTest {
assertContains(19);
}
- @Test
- public void expandEncompased() {
+ public void testExpandEncompased() {
selection.expand(2, 10);
assertEquals(3, selection.size());
assertContains(13);
@@ -140,8 +127,7 @@ public class MultiSelectManager_SelectionTest {
assertContains(19);
}
- @Test
- public void collapseBefore() {
+ public void testCollapseBefore() {
selection.collapse(0, 2);
assertEquals(3, selection.size());
assertContains(1);
@@ -149,8 +135,7 @@ public class MultiSelectManager_SelectionTest {
assertContains(7);
}
- @Test
- public void collapseAfter() {
+ public void testCollapseAfter() {
selection.collapse(10, 10);
assertEquals(3, selection.size());
assertContains(3);
@@ -158,8 +143,7 @@ public class MultiSelectManager_SelectionTest {
assertContains(9);
}
- @Test
- public void collapseAcross() {
+ public void testCollapseAcross() {
selection.collapse(0, 10);
assertEquals(0, selection.size());
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
deleted file mode 100644
index be3f2515057e..000000000000
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
+++ /dev/null
@@ -1,46 +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.documentsui;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-import org.junit.runners.Suite.SuiteClasses;
-
-@RunWith(Suite.class)
-@SuiteClasses({
- MultiSelectManager_GridModelTest.class,
- MultiSelectManager_SelectionTest.class,
- MultiSelectManagerTest.class
-})
-
-/**
- * This test suite can be run using the "art" runtime (which can be built
- * via the `build-art-host` target.) You'll also need to "mma -j32" the
- * DocumentsUI package to ensure all deps are built.
- *
- * <p>Once the dependencies have been built, the tests can be executed as follows:
- *
- * <pre>
- * CP=$OUT/system/framework/framework.jar:\
- * $OUT/system/framework/core-junit.jar:\
- * $OUT/system/app/DocumentsUI/DocumentsUI.apk:\
- * $OUT/data/app/DocumentsUITests/DocumentsUITests.apk
- *
- * art -cp $CP org.junit.runner.JUnitCore com.android.documentsui.UnitTests
- * </pre>
- */
-public class UnitTests {}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 393771a9b447..18335b6586a8 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -38,6 +38,7 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
+import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.DebugUtils;
@@ -380,12 +381,31 @@ public class ExternalStorageProvider extends DocumentsProvider {
@Override
public void deleteDocument(String docId) throws FileNotFoundException {
final File file = getFileForDocId(docId);
- if (file.isDirectory()) {
+ final boolean isDirectory = file.isDirectory();
+ if (isDirectory) {
FileUtils.deleteContents(file);
}
if (!file.delete()) {
throw new IllegalStateException("Failed to delete " + file);
}
+
+ final ContentResolver resolver = getContext().getContentResolver();
+ final Uri externalUri = MediaStore.Files.getContentUri("external");
+
+ // Remove media store entries for any files inside this directory, using
+ // path prefix match. Logic borrowed from MtpDatabase.
+ if (isDirectory) {
+ final String path = file.getAbsolutePath() + "/";
+ resolver.delete(externalUri,
+ "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
+ new String[] { path + "%", Integer.toString(path.length()), path });
+ }
+
+ // Remove media store entry for this exact file.
+ final String path = file.getAbsolutePath();
+ resolver.delete(externalUri,
+ "_data LIKE ?1 AND lower(_data)=lower(?2)",
+ new String[] { path, path });
}
@Override
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 7cc7413bab3d..af7f691bdd64 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -22,12 +22,14 @@ import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.mtp.MtpConstants;
import android.mtp.MtpDevice;
+import android.mtp.MtpEvent;
import android.mtp.MtpObjectInfo;
+import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -188,7 +190,13 @@ class MtpManager {
}
}
- private MtpDevice getDevice(int deviceId) throws IOException {
+ @VisibleForTesting
+ MtpEvent readEvent(int deviceId, CancellationSignal signal) throws IOException {
+ final MtpDevice device = getDevice(deviceId);
+ return device.readEvent(signal);
+ }
+
+ private synchronized MtpDevice getDevice(int deviceId) throws IOException {
final MtpDevice device = mDevices.get(deviceId);
if (device == null) {
throw new IOException("USB device " + deviceId + " is not opened.");
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
index 2c1f115ec92b..554777160792 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
@@ -16,35 +16,101 @@
package com.android.mtp;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
import android.test.InstrumentationTestCase;
+import java.io.IOException;
import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
+@RealDeviceTest
public class MtpManagerTest extends InstrumentationTestCase {
- @RealDeviceTest
- public void testBasic() throws Exception {
- final UsbDevice usbDevice = findDevice();
- final MtpManager manager = new MtpManager(getContext());
- manager.openDevice(usbDevice.getDeviceId());
- waitForStorages(manager, usbDevice.getDeviceId());
- manager.closeDevice(usbDevice.getDeviceId());
+ private static final String ACTION_USB_PERMISSION =
+ "com.android.mtp.USB_PERMISSION";
+ private static final int TIMEOUT_MS = 1000;
+ UsbManager mUsbManager;
+ MtpManager mManager;
+ UsbDevice mUsbDevice;
+ int mRequest;
+
+ @Override
+ public void setUp() throws Exception {
+ mUsbManager = getContext().getSystemService(UsbManager.class);
+ mUsbDevice = findDevice();
+ mManager = new MtpManager(getContext());
+ mManager.openDevice(mUsbDevice.getDeviceId());
+ waitForStorages(mManager, mUsbDevice.getDeviceId());
+ }
+
+ @Override
+ public void tearDown() throws IOException {
+ mManager.closeDevice(mUsbDevice.getDeviceId());
+ }
+
+ public void testCancelEvent() throws Exception {
+ final CancellationSignal signal = new CancellationSignal();
+ final Thread thread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ mManager.readEvent(mUsbDevice.getDeviceId(), signal);
+ } catch (OperationCanceledException | IOException e) {
+ show(e.getMessage());
+ }
+ }
+ };
+ thread.start();
+ Thread.sleep(TIMEOUT_MS);
+ signal.cancel();
+ thread.join(TIMEOUT_MS);
+ }
+
+ private void requestPermission(UsbDevice device) throws InterruptedException {
+ if (mUsbManager.hasPermission(device)) {
+ return;
+ }
+ final CountDownLatch latch = new CountDownLatch(1);
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ latch.countDown();
+ getInstrumentation().getTargetContext().unregisterReceiver(this);
+ }
+ };
+ getInstrumentation().getTargetContext().registerReceiver(
+ receiver, new IntentFilter(ACTION_USB_PERMISSION));
+ mUsbManager.requestPermission(device, PendingIntent.getBroadcast(
+ getInstrumentation().getTargetContext(),
+ 0 /* requstCode */,
+ new Intent(ACTION_USB_PERMISSION),
+ 0 /* flags */));
+ latch.await();
+ assertTrue(mUsbManager.hasPermission(device));
}
private UsbDevice findDevice() throws InterruptedException {
- final UsbManager usbManager = getContext().getSystemService(UsbManager.class);
while (true) {
- final HashMap<String,UsbDevice> devices = usbManager.getDeviceList();
+ final HashMap<String,UsbDevice> devices = mUsbManager.getDeviceList();
if (devices.size() == 0) {
show("Wait for devices.");
Thread.sleep(1000);
continue;
}
final UsbDevice device = devices.values().iterator().next();
- final UsbDeviceConnection connection = usbManager.openDevice(device);
+ requestPermission(device);
+ final UsbDeviceConnection connection = mUsbManager.openDevice(device);
+ if (connection == null) {
+ fail("Cannot open USB connection.");
+ }
for (int i = 0; i < device.getInterfaceCount(); i++) {
// Since the test runs real environment, we need to call claim interface with
// force = true to rob interfaces from other applications.
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java
index 9641ad764fae..22daaf2971e6 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java
@@ -17,7 +17,10 @@
package com.android.mtp;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
@interface RealDeviceTest {}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
index 9824d28e1fe4..a24337534e5b 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
@@ -45,8 +45,11 @@ public class TestResultInstrumentation extends InstrumentationTestRunner impleme
}
private void show(String tag, Test test, Throwable t) {
+ String message = "";
+ if (t != null && t.getMessage() != null) {
+ message = t.getMessage();
+ }
TestResultActivity.show(
- getContext(),
- String.format("[%s] %s %s", tag, test.toString(), t != null ? t.getMessage() : ""));
+ getContext(), String.format("[%s] %s %s", tag, test.toString(), message));
}
}
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index 8e41a349fde3..f88eca56d32a 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -46,7 +46,7 @@
<string name="savetopdf_button" msgid="2976186791686924743">"PDF sifatida saqlash"</string>
<string name="print_options_expanded" msgid="6944679157471691859">"Chop qilish tanlamalari yoyildi"</string>
<string name="print_options_collapsed" msgid="7455930445670414332">"Chop qilish tanlamalari yig‘ildi"</string>
- <string name="search" msgid="5421724265322228497">"Izlash"</string>
+ <string name="search" msgid="5421724265322228497">"Qidirish"</string>
<string name="all_printers_label" msgid="3178848870161526399">"Barcha printerlar"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"Xizmat qo‘shish"</string>
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Izlash oynasi ko‘rsatildi"</string>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 1cd2908e77e9..c324abd0dd22 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -204,9 +204,6 @@
<!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED -->
<bool name="def_wake_gesture_enabled">true</bool>
- <!-- Default for Settings.Global.GUEST_USER_ENABLED -->
- <bool name="def_guest_user_enabled">true</bool>
-
<!-- Default state of tap to wake -->
<bool name="def_double_tap_to_wake">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index ee296d90608f..d4e428e280b6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1693,20 +1693,7 @@ class DatabaseHelper extends SQLiteOpenHelper {
}
if (upgradeVersion < 105) {
- if (mUserHandle == UserHandle.USER_SYSTEM) {
- db.beginTransaction();
- SQLiteStatement stmt = null;
- try {
- stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
- + " VALUES(?,?);");
- loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
- R.bool.def_guest_user_enabled);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- if (stmt != null) stmt.close();
- }
- }
+ // No-op: GUEST_USER_ENABLED setting was removed
upgradeVersion = 105;
}
@@ -2705,8 +2692,6 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
- loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
- R.bool.def_guest_user_enabled);
loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
ImsConfig.FeatureValueConstants.ON);
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 93dc88950fe5..8fc7ad089427 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -206,7 +206,7 @@
android:resumeWhilePausing="true"
android:screenOrientation="behind"
android:resizeableActivity="true"
- android:theme="@style/config_recents_activity_theme">
+ android:theme="@style/RecentsTheme.Wallpaper">
<intent-filter>
<action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
</intent-filter>
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 47e24e8e82f3..368f9f79a20b 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -13,3 +13,11 @@
-keep class com.android.systemui.statusbar.phone.PhoneStatusBar
-keep class com.android.systemui.statusbar.tv.TvStatusBar
-keep class com.android.systemui.recents.*
+
+-keepclassmembers class ** {
+ public void onBusEvent(**);
+ public void onInterprocessBusEvent(**);
+}
+-keepclassmembers class ** extends **.EventBus$InterprocessEvent {
+ public <init>(android.os.Bundle);
+} \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_lock.xml b/packages/SystemUI/res/drawable/ic_qs_lock.xml
new file mode 100644
index 000000000000..204af7e81f4c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_lock.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
+ <path
+ android:fillColor="@color/keyguard_affordance"
+ android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_lock_open.xml b/packages/SystemUI/res/drawable/ic_qs_lock_open.xml
new file mode 100644
index 000000000000..c877f063b7a8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_lock_open.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
+ <path
+ android:fillColor="@color/keyguard_affordance"
+ android:pathData="M12.0,17.0c1.1,0.0 2.0,-0.9 2.0,-2.0s-0.9,-2.0 -2.0,-2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0S10.9,17.0 12.0,17.0zM18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l1.9,0.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM18.0,20.0L6.0,20.0L6.0,10.0l12.0,0.0L18.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
new file mode 100644
index 000000000000..f11b690b90af
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF0000FF"
+ android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,10.0l16.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml
new file mode 100644
index 000000000000..79ade42cc94e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF0000FF"
+ android:pathData="M24.0,0.0L0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0zM14.0,4.0l0.0,16.0L4.0,20.0L4.0,4.0L14.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml
new file mode 100644
index 000000000000..49c2a38ce48e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF0000FF"
+ android:pathData="M0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0L0.0,24.0zM10.0,20.0L10.0,4.0l10.0,0.0l0.0,16.0L10.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml
new file mode 100644
index 000000000000..c3abec222e7d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF0000FF"
+ android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM20.0,14.0L4.0,14.0L4.0,4.0l16.0,0.0L20.0,14.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
index a718d4d57a56..0a4c0868fbd6 100644
--- a/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
@@ -27,6 +27,20 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
+ android:id="@+id/place_dock_left"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_dock_left" />
+ <Button
+ android:id="@+id/place_dock_right"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_dock_right" />
+ <Button
android:id="@+id/place_left"
android:layout_width="36dp"
android:layout_height="36dp"
diff --git a/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
index 250f53da1cea..bf5207a7e43c 100644
--- a/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
@@ -27,6 +27,20 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
+ android:id="@+id/place_dock_top"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_dock_top" />
+ <Button
+ android:id="@+id/place_dock_bottom"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_dock_bottom" />
+ <Button
android:id="@+id/place_top"
android:layout_width="36dp"
android:layout_height="36dp"
diff --git a/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
index 26c9b1af5bc1..6e92afc6d0bf 100644
--- a/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
@@ -27,6 +27,20 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
+ android:id="@+id/place_dock_left"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_dock_left" />
+ <Button
+ android:id="@+id/place_dock_right"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_dock_right" />
+ <Button
android:id="@+id/place_left"
android:layout_width="36dp"
android:layout_height="36dp"
diff --git a/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
index e180daa7f415..faa5f4be8d68 100644
--- a/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
@@ -27,6 +27,20 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
+ android:id="@+id/place_dock_top"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_dock_top" />
+ <Button
+ android:id="@+id/place_dock_bottom"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_dock_bottom" />
+ <Button
android:id="@+id/place_top"
android:layout_width="36dp"
android:layout_height="36dp"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 1473f24bae42..c7c7f1a7e53b 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Net\nprioriteit"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Net\nwekkers"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Laai tans vinnig (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Laai tans stadig (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Wissel gebruiker"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Wissel gebruiker, huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7ab6af9cb72d..f49f5bc60c11 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ቅድሚያ ተሰጪ\nብቻ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ማንቂያዎች\nብቻ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ኃይል በፍጥነት በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ኃይል በዝግታ በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ተጠቃሚ ቀይር"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ተጠቃሚ ይለውጡ፣ የአሁን ተጠቃሚ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"የአሁን ተጠቃሚ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index bd026501dc45..aaf20cce429a 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -329,6 +329,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"الأولوية \nفقط"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"التنبيهات\nفقط"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"جارٍ الشحن سريعًا (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الاكتمال)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"جارٍ الشحن ببطء (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الاكتمال)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"تبديل المستخدم"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"تبديل المستخدم، المستخدم الحالي <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"المستخدم الحالي <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index a0d7d2b21c7c..0efc82b03b2b 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnız\nprioritet"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnız\nalarmlar"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Sürətli qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Ləng qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"İstifadəçiləri dəyişin, indiki istifadəçi: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Cari istifadəçi <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a14d0fc70c07..680577947a35 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nс приоритет"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nбудилници"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Зарежда се бързо (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Зарежда се бавно (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Превключване между потребителите"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Превключване на потребителя – текущият е <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Текущ потребител – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index e819d54e0901..c0ffe2c720e6 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"শুধুমাত্র\nঅগ্রাধিকার"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"শুধুমাত্র\nঅ্যালার্মগুলি"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"দ্রুত চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ধীরে ধীরে চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ব্যবহারকারী পাল্টে দিন"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ব্যবহারকারী পাল্টান, বর্তমান ব্যবহারকারী <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"<xliff:g id="CURRENT_USER_NAME">%s</xliff:g> হল বর্তমান ব্যবহারকারী"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index cc37162f99c1..c955f34ad8c3 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Només\ninterr. prior."</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Només\nalarmes"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Càrrega ràpida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Càrrega lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Canvia d\'usuari"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Canvia l\'usuari. Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -406,7 +408,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> és el diàleg de volum"</string>
<string name="volumeui_notification_text" msgid="1826889705095768656">"Toca per restaurar l\'original."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estàs utilitzant el perfil professional"</string>
- <string name="system_ui_tuner" msgid="708224127392452018">"Configurador de la IU del sistema"</string>
+ <string name="system_ui_tuner" msgid="708224127392452018">"Personalitzador d\'interfície d\'usuari"</string>
<string name="show_battery_percentage" msgid="5444136600512968798">"Mostra el percentatge de la bateria inserit"</string>
<string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostra el percentatge del nivell de bateria dins de la icona de la barra d\'estat quan no s\'estigui carregant"</string>
<string name="quick_settings" msgid="10042998191725428">"Configuració ràpida"</string>
@@ -428,12 +430,12 @@
<string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Zona Wi-Fi"</string>
<string name="accessibility_managed_profile" msgid="6613641363112584120">"Perfil professional"</string>
<string name="tuner_warning_title" msgid="7094689930793031682">"Diversió per a uns quants, però no per a tothom"</string>
- <string name="tuner_warning" msgid="8730648121973575701">"El Configurador de la IU del sistema presenta opcions addicionals per canviar i personalitzar la interfície d\'usuari d\'Android. És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string>
+ <string name="tuner_warning" msgid="8730648121973575701">"El Personalitzador d\'interfície d\'usuari presenta opcions addicionals per canviar i personalitzar la interfície d\'usuari d\'Android. És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string>
<string name="tuner_persistent_warning" msgid="8597333795565621795">"És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string>
<string name="got_it" msgid="2239653834387972602">"D\'acord"</string>
- <string name="tuner_toast" msgid="603429811084428439">"Enhorabona! El Configurador de la IU del sistema s\'ha afegit a Configuració."</string>
+ <string name="tuner_toast" msgid="603429811084428439">"Enhorabona! El Personalitzador d\'interfície d\'usuari s\'ha afegit a Configuració."</string>
<string name="remove_from_settings" msgid="8389591916603406378">"Treu de Configuració"</string>
- <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vols treure el Configurador de la UI del sistema de Configuració i deixar d\'utilitzar-ne totes les funcions?"</string>
+ <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vols suprimir el Personalitzador d\'interfície d\'usuari de Configuració i deixar d\'utilitzar-ne totes les funcions?"</string>
<string name="activity_not_found" msgid="348423244327799974">"L\'aplicació no està instal·lada al dispositiu"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Mostra els segons del rellotge"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index a73947fdfb05..18fd994f232e 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -329,6 +329,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Pouze\nprioritní"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Pouze\nbudíky"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Rychlé nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Pomalé nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Přepnout uživatele"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Přepnout uživatele, aktuální uživatel: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktuální uživatel <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 6f491874e6a8..5a2dd3300b23 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -183,12 +183,12 @@
<string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Flytilstand er slået til."</string>
<string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Flytilstand er slået fra."</string>
<string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Flytilstand er slået til."</string>
- <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Vil ikke forstyrres\" er slået til, kun prioritet."</string>
- <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"\"Vil ikke forstyrres\" er slået til, total stilhed."</string>
- <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Vil ikke forstyrres\" er slået til, kun alarmer."</string>
- <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Vil ikke forstyrres\" er slået fra."</string>
- <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Vil ikke forstyrres\" er slået fra."</string>
- <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Vil ikke forstyrres\" er slået til."</string>
+ <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Forstyr ikke\" er slået til, kun prioritet."</string>
+ <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"\"Forstyr ikke\" er slået til, total stilhed."</string>
+ <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Forstyr ikke\" er slået til, kun alarmer."</string>
+ <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Forstyr ikke\" er slået fra."</string>
+ <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Forstyr ikke\" er slået fra."</string>
+ <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Forstyr ikke\" er slået til."</string>
<string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth er slået fra."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth er slået til."</string>
<string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Opretter forbindelse til Bluetooth."</string>
@@ -236,7 +236,7 @@
<string name="dessert_case" msgid="1295161776223959221">"Dessertcase"</string>
<string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string>
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
- <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Vil ikke forstyrres"</string>
+ <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Forstyr ikke"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Kun prioritet"</string>
<string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Kun Alarmer"</string>
<string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Total stilhed"</string>
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kun\nprioritet"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kun\nalarmer"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Oplader (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hurtig opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Langsom opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Skift bruger"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Skift bruger. Nuværende bruger er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Nuværende bruger: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index a659077bd821..a8143a461090 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Nur\nwichtige"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Nur\nWecker"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Wird schnell aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Wird langsam aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Nutzer wechseln"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Nutzer wechseln. Aktueller Nutzer: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktueller Nutzer <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index bcfc4589a6b8..6031d3bb4fff 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Μόνο\nπροτεραιότητας"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Μόνο\nειδοποιήσεις"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Γρήγορη φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Αργή φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Εναλλαγή χρήστη"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Εναλλαγή χρήστη, τρέχων χρήστης <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Τρέχων χρήστης <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index fb781d4d91ea..bef7661a52ef 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index fb781d4d91ea..bef7661a52ef 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index fb781d4d91ea..bef7661a52ef 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en/donottranslate.xml b/packages/SystemUI/res/values-en/donottranslate.xml
new file mode 100644
index 000000000000..9f04e1f50b14
--- /dev/null
+++ b/packages/SystemUI/res/values-en/donottranslate.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<resources>
+ <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
+ <item type="string" name="keyguard_indication_charging_time_fast_if_translated">@string/keyguard_indication_charging_time_fast</item>
+ <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
+ <item type="string" name="keyguard_indication_charging_time_slowly_if_translated">@string/keyguard_indication_charging_time_slowly</item>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 10834a23baa7..15902653a7f2 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\nprioridad"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carga rápida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar la carga)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carga lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar la carga)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar usuario"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar de usuario (usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"El usuario actual es <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 37c81f4936c0..082e7624cbd0 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\ncon prioridad"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Cargando rápidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Cargando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar de usuario"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar de usuario (usuario actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index f4218a3a6eb3..4add1471be93 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Ainult\nprioriteetsed"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ainult\nalarmid"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Kiirlaadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Aeglane laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Kasutaja vahetamine"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Kasutaja vahetamine, praegune kasutaja: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Praegune kasutaja <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 0e5532cd9db7..4f5c9f26799e 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Lehentasunezkoak\nsoilik"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmak\nsoilik"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Bizkor kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mantso kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Aldatu erabiltzailea"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Aldatu erabiltzailez. <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> da saioa hasita duena."</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Uneko erabiltzailea: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 7593f46e6c70..6fa7e1c19efd 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -275,7 +275,7 @@
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"برگردان رنگ‌ها"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"حالت تصحیح رنگ"</string>
<string name="quick_settings_more_settings" msgid="326112621462813682">"تنظیمات بیشتر"</string>
- <string name="quick_settings_done" msgid="3402999958839153376">"انجام شد"</string>
+ <string name="quick_settings_done" msgid="3402999958839153376">"تمام"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"متصل"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"در حال اتصال..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"اتصال به اینترنت با تلفن همراه"</string>
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"فقط\nاولویت‌دار"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"فقط\nهشدارها"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"در حال شارژ سریع (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"در حال شارژ آهسته (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"تغییر کاربر"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"تعویض کاربر، کاربر کنونی <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"کاربر کنونی <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 6c4a0299069b..655cf312b5dd 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vain\ntärkeät"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vain\nherätykset"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Nopea lataus (latausaikaa jäljellä <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Hidas lataus (latausaikaa jäljellä <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Vaihda käyttäjää"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Vaihda käyttäjä (nyt <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Nykyinen käyttäjä: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 07a2fc349f5e..2f2c3319ac17 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorités\nuniquement"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide en cours... (chargé dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente en cours... (chargé dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 0aa45ae8a393..9f3443197a52 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorité\nuniquement"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index ec64f229ea4e..df90ef4dd550 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Só\nprioridade"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Só\nalarmas"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para finalizar a carga)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Cargando rápido (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para rematar a carga)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Cargando lento (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para rematar a carga)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar usuario"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar usuario, usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuario actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index e873c95f14f7..42ee460ad880 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ફક્ત\nપ્રાધાન્યતા"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ફક્ત\nએલાર્મ્સ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ચાર્જ થઈ રહ્યું છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ઝડપથી ચાર્જિંગ થઇ રહી છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ધીમેથી ચાર્જિંગ થઇ રહી છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"વપરાશકર્તા સ્વિચ કરો"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"વપરાશકર્તાને સ્વિચ કરો, વર્તમાન વપરાશકર્તા <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"વર્તમાન વપરાશકર્તા <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 83ac46eaf42d..86f536dce040 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवल\nप्राथमिकता"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवल\nअलार्म"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूरा होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> बाकी)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"तेज़ी से चार्ज हो रहा है (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> में हो जाएगा)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"धीरे चार्ज हो रहा है (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> में पूरा हो जाएगा)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"उपयोगकर्ता स्विच करें"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"उपयोगकर्ता स्विच करें, वर्तमान उपयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"वर्तमान उपयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b5d993117334..043e7ada0ddc 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -326,6 +326,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprioritetno"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Brzo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sporo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Promjena korisnika"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Promjena korisnika, trenutačni korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Trenutačan korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 79390a69990e..e2b08129eabc 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Csak\nprioritás"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Csak\nriasztások"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Gyors töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lassú töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Felhasználóváltás"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Felhasználóváltás (a jelenlegi felhasználó: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Jelenlegi felhasználó (<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 9f48b2618e3e..f8fc232106bb 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Միայն\nկարևորները"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Միայն\nզարթուցիչ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Արագ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև լցվելը)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Դանդաղ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև լցվելը)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Անջատել օգտվողին"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Փոխել օգտվողին. ներկայիս օգտվողն է՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Ընթացիկ օգտվողը՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 600241151aab..7dbcda92ede1 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Hanya\nprioritas"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Hanya\nalarm"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mengisi daya dengan cepat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mengisi daya dengan lambat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Beralih pengguna"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Ganti pengguna, pengguna saat ini <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Pengguna saat ini <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index e8e053090fda..b28b6fd80e31 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Aðeins\nforgangur"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Aðeins\nvekjarar"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Í hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Í hraðri hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Í hægri hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Skipta um notanda"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Skipta um notanda; núverandi notandi er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Núverandi notandi er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8ee5f078a806..54e6f560ca67 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo con\npriorità"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nsveglie"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Ricarica veloce (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Ricarica lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambio utente"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambia utente, utente corrente <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utente corrente <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -354,7 +356,7 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"Rimuovere l\'utente?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Tutte le app e i dati di questo utente verranno eliminati."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Rimuovi"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio batteria attivo"</string>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio energetico attivo"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Riduce le prestazioni e i dati in background"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Disattiva risparmio energetico"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 44058a34db49..c959febd9ab9 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"התראות בעדיפות\nבלבד"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"התראות\nבלבד"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"בטעינה מהירה (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"בטעינה איטית (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"החלפת משתמש"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"החלף משתמש. המשתמש הנוכחי הוא <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"משתמש נוכחי <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index a73f4c1d9fc6..29476d80e094 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -327,10 +327,12 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"重要な\n通知のみ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"アラーム\nのみ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フル充電まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"急速充電中(完了まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"低速充電中(完了まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ユーザーを切り替える"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ユーザーを切り替える、現在のユーザーは<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"現在のユーザー: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
- <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"プロフィールを表示"</string>
+ <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"プロファイルを表示"</string>
<string name="user_add_user" msgid="5110251524486079492">"ユーザーを追加"</string>
<string name="user_new_user_name" msgid="426540612051178753">"新しいユーザー"</string>
<string name="guest_nickname" msgid="8059989128963789678">"ゲスト"</string>
@@ -364,10 +366,10 @@
<string name="media_projection_action_text" msgid="8470872969457985954">"今すぐ開始"</string>
<string name="empty_shade_text" msgid="708135716272867002">"通知はありません"</string>
<string name="device_owned_footer" msgid="3802752663326030053">"端末が監視されている可能性があります"</string>
- <string name="profile_owned_footer" msgid="8021888108553696069">"プロフィールが監視されている可能性があります"</string>
+ <string name="profile_owned_footer" msgid="8021888108553696069">"プロファイルが監視されている可能性があります"</string>
<string name="vpn_footer" msgid="2388611096129106812">"ネットワークが監視されている可能性があります"</string>
<string name="monitoring_title_device_owned" msgid="7121079311903859610">"端末の監視"</string>
- <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"プロフィールの監視"</string>
+ <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"プロファイルの監視"</string>
<string name="monitoring_title" msgid="169206259253048106">"ネットワーク監視"</string>
<string name="disable_vpn" msgid="4435534311510272506">"VPNを無効にする"</string>
<string name="disconnect_vpn" msgid="1324915059568548655">"VPNを切断"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index f1035a8d8fc5..d83c9e9e8ede 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"მხოლოდ\nპრიორიტეტულები"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"მხოლოდ\nგაფრთხილებები"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"იტენება სწრაფად (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> სრულ დატენვამდე)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"იტენება ნელა (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> სრულ დატენვამდე)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"მომხმარებლის გადართვა"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"მომხმარებლის გდართვა. ამჟამინდელი მომხმარებელი <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ამჟამინდელი მომხმარებელი <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 8b82e5fce6c9..5c066b3c9d14 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Тек\nбасымдық"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Тек\nдабылдар"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Жылдам зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Баяу зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Пайдаланушыны ауыстыру"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Пайдаланушыны ауыстыру, ағымдағы пайдаланушы <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Ағымдағы пайдаланушы: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index b8db00f9067c..4c469b05e7e4 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"អាទិភាព\nប៉ុណ្ណោះ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"សំឡេងរោទ៍\nប៉ុណ្ណោះ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុង​បញ្ចូល​ថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើប​ពេញ)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ថ្មកំពុងសាកលឿន (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ថ្មកំពុងសាកយឺតៗ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ប្ដូរ​អ្នក​ប្រើ"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ប្ដូរ​អ្នកប្រើ ​អ្នកប្រើ​បច្ចុប្បន្ន <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"អ្នកប្រើបច្ចុប្បន្ន <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 316c04fe12a2..4215a9193cd7 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ಆದ್ಯತೆ\nಮಾತ್ರ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ಅಲಾರಮ್‌ಗಳು\nಮಾತ್ರ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ ( ಪೂರ್ತಿ ಆಗುವವರೆಗೆ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ವೇಗವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ನಿಧಾನ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ, ಪ್ರಸ್ತುತ ಬಳಕೆದಾರ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"<xliff:g id="CURRENT_USER_NAME">%s</xliff:g> ಪ್ರಸ್ತುತ ಬಳಕೆದಾರ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index d7f1543a87d0..8ee594652bd3 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"중요 알림만\n허용"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"알람만\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"고속 충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"저속 충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"사용자 전환"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"사용자 전환, 현재 사용자 <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"현재 사용자: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 65f91a2d62a6..ce0afd42d6de 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Артыкчылыктуу\nгана"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ойготкучтар\nгана"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Кубатталууда (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> толгонго чейин)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Тез кубатталууда (толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> калды)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Жай кубатталууда (толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> калды)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Колдонуучуну которуу"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Колдонуучуну күйгүзүү, учурдагы колдонуучу <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Учурдагы колдонуучу <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index d608e25ebeba..f7e23449fa0a 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -20,10 +20,6 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
- <!-- Whether we're using the tablet-optimized recents interface (we use this
- value at runtime for some things) -->
- <integer name="status_bar_recents_bg_gradient_degrees">90</integer>
-
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">2</integer>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index a9e7735ea660..6ef1adac3e02 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -19,28 +19,6 @@
<!-- thickness (width) of the navigation bar on phones that require it -->
<dimen name="navigation_bar_size">@*android:dimen/navigation_bar_width</dimen>
- <!-- Recent Applications parameters -->
- <!-- How far the thumbnail for a recent app appears from left edge -->
- <dimen name="status_bar_recents_thumbnail_left_margin">0dp</dimen>
- <!-- How far the thumbnail for a recent app appears from top edge -->
- <dimen name="status_bar_recents_thumbnail_top_margin">28dp</dimen>
- <!-- Padding for text descriptions -->
- <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
- <!-- Width of application label text -->
- <dimen name="status_bar_recents_app_label_width">156dip</dimen>
- <!-- Left margin of application label text -->
- <dimen name="status_bar_recents_app_label_left_margin">12dip</dimen>
- <!-- Margin between recents container and glow on the right -->
- <dimen name="status_bar_recents_right_glow_margin">0dip</dimen>
- <!-- Padding between recents items -->
- <dimen name="status_bar_recents_item_padding">2dip</dimen>
- <!-- Where to place the app icon over the thumbnail -->
- <dimen name="status_bar_recents_app_icon_left_margin">8dp</dimen>
- <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
-
- <!-- The side padding for the task stack as a percentage of the width. -->
- <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.26</item>
-
<!-- Standard notification width + gravity -->
<dimen name="notification_panel_width">@dimen/standard_notification_panel_width</dimen>
<integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 50b4522caabf..b45395efd6ef 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ບຸ​ລິ​ມະ​ສິດ\nເທົ່າ​ນັ້ນ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ໂມງ​ປຸກ\nເທົ່າ​ນັ້ນ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ສະ​ລັບ​ຜູ່ໃຊ້"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ປ່ຽນຜູ່ໃຊ້, ຜູ່ໃຊ້ປະຈຸບັນ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ຜູ້ໃຊ້ປະຈຸບັນ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 90827785d109..194668b8b922 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tik\nprioritetiniai"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tik\nsignalai"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Greitai kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lėtai kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Perjungti naudotoją"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Perjungti naudotoją, dabartinis naudotojas <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Dabartinis naudotojas <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5fb4bb0c2f86..2b3be5838d23 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -326,6 +326,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tikai\nprioritārie"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tikai\nsignāli"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Ātra uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lēna uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Mainīt lietotāju"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Pārslēgt lietotāju; pašreizējais lietotājs: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Pašreizējais lietotājs: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 8571b3f441f1..912c30f1c225 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприоритетни"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Се полни (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Брзо полнење (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Бавно полнење (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Промени го корисникот"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Промени го корисникот, тековен корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Тековен корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 4b11962a91c4..c85ecc7b8441 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"മുൻഗണന\nമാത്രം"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"അലാറങ്ങൾ\nമാത്രം"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ചാർജ്ജുചെയ്യുന്നു (പൂർണ്ണമാകുന്നതിന്, <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"വേഗത്തിൽ ചാർജുചെയ്യുന്നു (പൂർണ്ണമാകാൻ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"പതുക്കെ ചാർജുചെയ്യുന്നു (പൂർണ്ണമാകാൻ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ഉപയോക്താവ് മാറുക"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ഉപയോക്താവിനെ മാറ്റുക, <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> എന്നയാളാണ് നിലവിലുള്ള ഉപയോക്താവ്"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"നിലവിലെ ഉപയോക്താവ് <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index d1dbd6dbf2d4..6b29affcfb6c 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -323,6 +323,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Зөвхөн\nхамгийн чухлыг"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Зөвхөн\nсэрүүлэг"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> шаардлагатай)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> шаардлагатай)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Хэрэглэгчийг сэлгэх"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Хэрэглэгчийг сэлгэх, одоогийн хэрэглэгч <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Одоогийн хэрэглэгч <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 2b9d953486b9..9d518a0c7008 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवळ\nप्राधान्य"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवळ\nअलार्म"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) चार्ज होत आहे"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) वेगाने चार्ज होत आहे"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) हळूहळू चार्ज होत आहे"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"वापरकर्ता स्विच करा"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"वापरकर्ता स्विच करा, वर्तमान वापरकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"वर्तमान वापरकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 01f7edfd6066..10dca3e4545b 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Keutamaan\nsahaja"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Penggera\nsahaja"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mengecas cepat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mengecas perlahan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Tukar pengguna"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Tukar pengguna, pengguna semasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Pengguna semasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index d0eaccfaf550..adfd9f821f02 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ဦးစားပေးမှု\nသာ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"နှိုးစက်များ\nသာ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> အပြည့် အထိ) အားသွင်းနေ"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"လျှင်မြန်စွာအားသွင်းခြင်း (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ပြည့်သည်အထိ)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"နှေးကွေးစွာ အားသွင်းခြင်း (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ပြည့်သည်အထိ)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"အသုံးပြုသူကို ပြောင်းရန်၊ လက်ရှိ အသုံးပြုသူ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"လတ်တလော သုံးစွဲသူ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index e582039142db..ecfb7f24741f 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Bare\nPrioritet"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Bare\nalarmer"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Lader raskt (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lader sakte (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Bytt bruker"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Bytt bruker, gjeldende bruker er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Gjeldende bruker: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index c3dc703e72ad..d997affa6b8a 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"प्राथमिकता \nमात्र"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"अलार्महरू \nमात्र"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण भएसम्म)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"छिटो चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण नभएसम्म)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"बिस्तारै चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण नभएसम्म)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"प्रयोगकर्ता फेर्नुहोस्"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"प्रयोगकर्ता, हालको प्रयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> मा स्विच गर्नुहोस्"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"हालको प्रयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 79f3333ead53..c6bab06f0acd 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Alleen\nprioriteit"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alleen\nalarmen"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Snel opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Langzaam opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Gebruiker wijzigen"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Schakelen tussen gebruikers, huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index ef3d2f3585bd..74e5fcb2096a 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ਕੇਵਲ\nਤਰਜੀਹੀ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ਕੇਵਲ\nਅਲਾਰਮ"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ਚਾਰਜਿੰਗ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰਾ ਹੋਣ ਤੱਕ)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ਉਪਭੋਗਤਾ ਸਵਿਚ ਕਰੋ"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ਉਪਭੋਗਤਾ, ਵਰਤਮਾਨ ਉਪਭੋਗਤਾ ਸਵਿਚ ਕਰੋ<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ਮੌਜੂਦਾ ਉਪਭੋਗਤਾ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 8c2c5c430213..e04fd71a1b55 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tylko\npriorytetowe"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tylko\nalarmy"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Szybkie ładowanie (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do końca)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Wolne ładowanie (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do końca)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Przełącz użytkownika"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Przełącz użytkownika. Bieżący użytkownik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Bieżący użytkownik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 3803b812013d..2a8e3ab51483 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carregando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carregando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Trocar usuário"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Alternar usuário. Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 12609c747e59..8453e5bc3106 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Apenas\nprioridade"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Apenas\nalarmes"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"A carregar rapid. (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"A carregar lentam. (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Mudar utilizador"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Mudar de utilizador; o utilizador atual é <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilizador atual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 3803b812013d..2a8e3ab51483 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carregando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carregando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Trocar usuário"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Alternar usuário. Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index bb8f2c3fe6b5..d85e791d0454 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -326,6 +326,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Numai\ncu prioritate"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Numai\nalarme"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Se încarcă rapid (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Se încarcă lent (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Comutați între utilizatori"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Schimbați utilizatorul (utilizator actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilizator actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9609f40bdff8..39d861747968 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -329,6 +329,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Только\nважные"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Только\nбудильник"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Быстрая зарядка (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Медленная зарядка (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Сменить пользователя."</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Сменить аккаунт. Вход выполнен под именем <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>."</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Выбран аккаунт пользователя <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 9e7883422230..51bb047e5360 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ප්‍රමුඛතා\nපමණි"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ඇඟවීම්\nපමණි"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ඉක්මනින් ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"සෙමින් ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"පරිශීලක මාරුව"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"පරිශීලකයා මාරු කරන්න,දැන් සිටින පරිශීලකයා <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"වත්මන් පරිශීලක <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 2e41b2969dd2..2886e36c9667 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -329,6 +329,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Iba\nprioritné"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Iba\nbudíky"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Nabíja sa rýchlo (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Nabíja sa pomaly (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Prepnutie používateľa"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Prepnúť používateľa (súčasný používateľ: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktuálny používateľ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 4dffcfa2bcd1..e325ef1b8771 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprednostno"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hitro polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Počasno polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Preklop med uporabniki"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Preklop med uporabniki, trenutni uporabnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Trenutni uporabnik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 20c342638aaa..5bcf941216eb 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vetëm\nme prioritet"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vetëm\nalarmet"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Po ngarkohet (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> deri sa të mbushet)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Po ngarkon me shpejtësi (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> derisa të mbushet)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Po ngarkon me ngadalë (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> derisa të mbushet)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Ndërro përdorues"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Ndërro përdoruesin. Përdoruesi aktual është <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Përdoruesi aktual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 1dcde3a1b0bb..522b2af32221 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -326,6 +326,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприорит. прекиди"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Брзо се пуни (напуниће се за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Споро се пуни (напуниће се за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Замени корисника"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Промените корисника, актуелни корисник је <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Актуелни корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0abeb1eb4d85..d91335c28279 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Endast\nprioriterade"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Endast\nalarm"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Laddas snabbt (batteriet fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Laddas sakta (batteriet fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Byt användare"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Byt användare. Aktuell användare: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktuell användare <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d000004c530a..1cf429380b34 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kipaumbele\npekee"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kengele\npekee"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ijae)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Inachaji kwa kasi (itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Inachaji pole pole (itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Badili mtumiaji"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Badili mtumiaji, mtumiaji wa sasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Mtumiaji wa sasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 3a62ad94f2c7..f084bc2c3ddb 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -16,12 +16,6 @@
*/
-->
<resources>
- <!-- Recent Applications parameters -->
- <dimen name="status_bar_recents_app_label_width">190dip</dimen>
-
- <!-- The side padding for the task stack as a percentage of the width. -->
- <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.25</item>
-
<fraction name="keyguard_clock_y_fraction_max">37%</fraction>
<fraction name="keyguard_clock_y_fraction_min">20%</fraction>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 83477c03d1e4..4f6d209b3f7a 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -32,9 +32,4 @@
<!-- Set to true to enable the user switcher on the keyguard. -->
<bool name="config_keyguardUserSwitcher">true</bool>
-
- <!-- Transposes the search bar layout in landscape. -->
- <bool name="recents_has_transposed_search_bar">true</bool>
- <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
- <bool name="recents_has_transposed_nav_bar">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 1af4ab1f4b15..49dbac2f5f65 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -32,10 +32,6 @@
<!-- The width of the view containing the menu/ime navigation bar icons -->
<dimen name="navigation_extra_key_width">48dip</dimen>
- <!-- Size of application thumbnail -->
- <dimen name="status_bar_recents_thumbnail_width">200dp</dimen>
- <dimen name="status_bar_recents_thumbnail_height">177dp</dimen>
-
<!-- Minimum fraction of the screen that should be taken up by the notification panel. -->
<item type="dimen" name="notification_panel_min_height_frac">40%</item>
@@ -43,12 +39,6 @@
<!-- On tablets this is just the close_handle_height -->
<dimen name="peek_height">@dimen/close_handle_height</dimen>
- <!-- The side padding for the task stack as a percentage of the width. -->
- <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.075</item>
-
- <!-- The height of the search bar space. -->
- <dimen name="recents_search_bar_space_height">72dp</dimen>
-
<!-- The fraction of the screen height where the clock on the Keyguard has its center. The
max value is used when no notifications are displaying, and the min value is when the
highest possible number of notifications are showing. -->
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index fbeadcd56da7..64e2760e7778 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -22,27 +22,8 @@
<resources>
<integer name="status_bar_config_maxNotificationIcons">5</integer>
- <!-- Whether we're using the tablet-optimized recents interface (we use this
- value at runtime for some things) -->
- <bool name="config_recents_interface_for_tablets">true</bool>
-
- <!-- Whether recents thumbnails should stretch in both x and y to fill their
- ImageView -->
- <bool name="config_recents_thumbnail_image_fits_to_xy">true</bool>
-
- <!-- Min alpha % that recent items will fade to while being dismissed -->
- <integer name="config_recent_item_min_alpha">0</integer>
-
- <!-- Transposes the search bar layout in landscape -->
- <bool name="recents_transpose_search_layout_with_orientation">false</bool>
-
<!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
card. -->
<integer name="keyguard_max_notification_count">5</integer>
-
- <!-- Transposes the search bar layout in landscape. -->
- <bool name="recents_has_transposed_search_bar">false</bool>
- <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
- <bool name="recents_has_transposed_nav_bar">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index dd158c2c70bc..7cee38140fe7 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -29,42 +29,9 @@
<!-- Bottom margin (from display edge) for status bar panels -->
<dimen name="panel_float">56dp</dimen>
- <!-- Recent Applications parameters -->
- <!-- How far the thumbnail for a recent app appears from left edge -->
- <dimen name="status_bar_recents_thumbnail_left_margin">28dp</dimen>
- <!-- Upper width limit for application icon -->
- <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen>
- <!-- Upper height limit for application icon -->
- <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen>
-
- <!-- Size of application icon -->
- <dimen name="status_bar_recents_thumbnail_width">208dp</dimen>
- <dimen name="status_bar_recents_thumbnail_height">130dp</dimen>
-
- <!-- Width of recents panel -->
- <dimen name="status_bar_recents_width">600dp</dimen>
- <!-- Padding for text descriptions -->
- <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
- <!-- Size of application label text -->
- <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
- <!-- Size of application description text -->
- <dimen name="status_bar_recents_app_description_text_size">18dip</dimen>
- <!-- Width of application label text -->
- <dimen name="status_bar_recents_app_label_width">97dip</dimen>
- <!-- Left margin for application label -->
- <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
- <!-- Size of fading edge for text -->
- <dimen name="status_bar_recents_text_fading_edge_length">20dip</dimen>
- <!-- Size of fading edge for scrolling -->
- <dimen name="status_bar_recents_scroll_fading_edge_length">10dip</dimen>
-
<!-- The radius of the rounded corners on a task view. -->
<dimen name="recents_task_view_rounded_corners_radius">3dp</dimen>
- <!-- Where to place the app icon over the thumbnail -->
- <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen>
- <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
-
<!-- The fraction of the screen height where the clock on the Keyguard has its center. The
max value is used when no notifications are displaying, and the min value is when the
highest possible number of notifications are showing. -->
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 7b1ded375bac..670bccc71320 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"முன்னுரிமைகள்\nமட்டும்"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"அலாரங்கள்\nமட்டும்"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"சார்ஜாகிறது (முழு சார்ஜிற்கு <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ஆகும்)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"வேகமாக சார்ஜாகிறது (முழு சார்ஜிற்கு: <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"மெதுவாக சார்ஜாகிறது (முழு சார்ஜிற்கு: <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"பயனரை மாற்று"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"பயனரை மாற்று, தற்போதைய பயனர் <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"தற்போதைய பயனர்: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 06762bd7ef4e..bbd9979d0585 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ప్రాధాన్యమైనవి\nమాత్రమే"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"అలారాలు\nమాత్రమే"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ఛార్జ్ అవుతోంది (పూర్తిగా నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"వేగంగా ఛార్జ్ అవుతోంది (నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"నెమ్మదిగా ఛార్జ్ అవుతోంది (నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"వినియోగదారుని మార్చు"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"వినియోగదారుని మార్చు, ప్రస్తుత వినియోగదారు <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ప్రస్తుత వినియోగదారు <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 52c7af7f2f27..2486519f019f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"เฉพาะเรื่อง\nสำคัญ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"เฉพาะปลุก\nเท่านั้น"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"กำลังชาร์จอย่างรวดเร็ว (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> จะเต็ม)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"กำลังชาร์จอย่างช้าๆ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> จะเต็ม)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"สลับผู้ใช้"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"เปลี่ยนผู้ใช้จากผู้ใช้ปัจจุบัน <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ผู้ใช้ปัจจุบัน <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 66056d10dc64..3d1243e2f585 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priyoridad\nlang"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Mga alarm\nlang"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mabilis mag-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang sa mapuno)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mabagal mag-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang sa mapuno)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Magpalit ng user"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Magpalit ng user, kasalukuyang user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Kasalukuyang user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 49edb5746548..4dadfbc9e74f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnızca\nöncelik"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnızca\nalarmlar"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hızlı şarj oluyor (tam dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Yavaş şarj oluyor (tam dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Kullanıcı değiştirme"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Kullanıcı değiştir. Geçerli kullanıcı: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Geçerli kullanıcı: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 9dde80178d2d..d158dbef756b 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Лише\nприорітетні"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Лише\nсигнали"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Швидке заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного заряду)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Повільне заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного заряду)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Змінити користувача"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Змінити користувача, поточний користувач – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Поточний користувач: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index a4ef16acae62..f8d8c71e8f85 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"صرف\nترجیحی"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"صرف\nالارمز"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"چارج ہو رہا ہے (مکمل ہونے تک <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> باقی ہیں)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"تیزی سے چارج ہو رہا ہے (مکمل ہونے میں <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"آہستہ چارج ہو رہا ہے (مکمل ہونے میں <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"صارف سوئچ کریں"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"صارف سوئچ کریں، موجودہ صارف <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"موجودہ صارف <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 04ec78b07526..018680956bdf 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -82,7 +82,7 @@
<string name="accessibility_home" msgid="8217216074895377641">"Uyga"</string>
<string name="accessibility_menu" msgid="316839303324695949">"Menyu"</string>
<string name="accessibility_recent" msgid="5208608566793607626">"Umumiy nazar"</string>
- <string name="accessibility_search_light" msgid="1103867596330271848">"Izlash"</string>
+ <string name="accessibility_search_light" msgid="1103867596330271848">"Qidirish"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
<string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="487611083884852965">"Ovozli yordam"</string>
@@ -303,7 +303,7 @@
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>da to‘ladi"</string>
<string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Quvvat olmayapti"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tarmoq nazorat\nostida bo‘lishi mumkin"</string>
- <string name="description_target_search" msgid="3091587249776033139">"Izlash"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Qidirish"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun yuqoriga suring."</string>
<string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun chapga suring."</string>
<string name="zen_priority_introduction" msgid="3070506961866919502">"Turli ovoz va tebranishlar endi sizni bezovta qilmaydi. Biroq uyg‘otkich signallari, eslatmalar, tadbirlar haqidagi bildirishnomalar va siz tanlagan abonentlardan kelgan qo‘ng‘iroqlar bundan mustasno."</string>
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Faqat\nmuhimlar"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Faqat\nsignallar"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Quvvat olmoqda (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>da to‘ladi)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Tez quvvat olmoqda (to‘lishiga <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> qoldi)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sekin quvvat olmoqda (to‘lishiga <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> qoldi)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Foydalanuvchini almashtirish"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Foydalanuvchini o‘zgartirish. Joriy foydalanuvchi – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Joriy foydalanuvchi <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 460d57ae4410..49b5d1d29617 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Chỉ\nưu tiên"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Chỉ\nbáo thức"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Sạc nhanh (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho tới khi đầy)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sạc chậm (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho tới khi đầy)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Chuyển đổi người dùng"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Chuyển người dùng, người dùng hiện tại <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Người dùng hiện tại <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 4d70f24b9ea8..93ed5ca876a5 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"仅限\n优先打扰"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"仅限\n闹钟"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>充满)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"正在快速充电(还需 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"正在慢速充电(还需 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切换用户"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切换用户,当前用户为<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"当前用户为<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index f7cac90e1522..219611133f50 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅限\n優先"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅限\n鬧鐘"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"正在快速充電 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"正在緩慢充電 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切換使用者"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切換使用者,目前使用者是<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"目前的使用者是 <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 369172f36836..fe4fe0600254 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -327,6 +327,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅允許\n優先通知"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅允許\n鬧鐘"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"快速充電中 (充飽需要 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"慢速充電中 (充飽需要 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切換使用者"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切換使用者,目前使用者是<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"目前使用者是「<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>」"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 2a14a9f2b6d4..2f068af66dfc 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -325,6 +325,8 @@
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Okubalulekile\nkuphela"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ama-alamu\nkuphela"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Iyashaja ngokushesha (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Iyashaja kancane (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Shintsha umsebenzisi"</string>
<string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Shintsha umsebenzisi, umsebenzisi wamanje ngu-<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Umsebenzisi wamanje <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index da210843bd28..f40f0d9aecdb 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -24,11 +24,8 @@
<color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
<color name="system_bar_background_transparent">#00000000</color>
<color name="notification_panel_solid_background">#ff000000</color>
- <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
- <color name="status_bar_recents_app_label_color">#ffffffff</color>
<drawable name="status_bar_notification_row_background_color">#ff090909</drawable>
<color name="notification_list_shadow_top">#80000000</color>
- <drawable name="recents_callout_line">#99ffffff</drawable>
<drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
<color name="batterymeter_frame_color">#4DFFFFFF</color><!-- 30% white -->
<color name="batterymeter_charge_color">#FFFFFFFF</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8da11488c482..1d1958943e94 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -20,15 +20,6 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
-
- <!-- Whether we're using the tablet-optimized recents interface (we use this
- value at runtime for some things) -->
- <bool name="config_recents_interface_for_tablets">false</bool>
-
- <!-- Whether recents thumbnails should stretch in both x and y to fill their
- ImageView -->
- <bool name="config_recents_thumbnail_image_fits_to_xy">false</bool>
-
<!-- Whether recents should use hardware layers for its taskviews. This flag can be enabled
for devices where the java drawing of round rects may be slow -->
<bool name="config_recents_use_hardware_layers">false</bool>
@@ -46,9 +37,6 @@
certain GPU's and thus can be turned off with only minimal visual impact. -->
<bool name="config_notifications_round_rect_clipping">true</bool>
- <!-- The theme to use for RecentsActivity. -->
- <item type="style" name="config_recents_activity_theme">@style/RecentsTheme.Wallpaper</item>
-
<!-- Control whether status bar should distinguish HSPA data icon form UMTS
data icon on devices -->
<bool name="config_hspa_data_distinguishable">false</bool>
@@ -92,10 +80,6 @@
<!-- The length of the vibration when the notification pops open. -->
<integer name="one_finger_pop_duration_ms">10</integer>
- <!-- Whether we're using the tablet-optimized recents interface (we use this
- value at runtime for some things) -->
- <integer name="status_bar_recents_bg_gradient_degrees">90</integer>
-
<!-- decay duration (from size_max -> size), in ms -->
<integer name="navigation_bar_deadzone_hold">333</integer>
<integer name="navigation_bar_deadzone_decay">333</integer>
@@ -205,12 +189,6 @@
<!-- The delay to enforce between each alt-tab key press. -->
<integer name="recents_alt_tab_key_delay">200</integer>
- <!-- Transposes the search bar layout in landscape. -->
- <bool name="recents_has_transposed_search_bar">true</bool>
-
- <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
- <bool name="recents_has_transposed_nav_bar">true</bool>
-
<!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
<integer name="recents_svelte_level">0</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 96a77256bc42..abfd86383776 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -16,45 +16,6 @@
*/
-->
<resources>
- <!-- Recent Applications parameters -->
- <!-- Upper width limit for application icon -->
- <dimen name="status_bar_recents_app_icon_max_width">48dp</dimen>
- <!-- Upper height limit for application icon -->
- <dimen name="status_bar_recents_app_icon_max_height">48dp</dimen>
-
- <!-- Size of application thumbnail -->
- <dimen name="status_bar_recents_thumbnail_width">164dp</dimen>
- <dimen name="status_bar_recents_thumbnail_height">145dp</dimen>
- <dimen name="status_bar_recents_thumbnail_bg_padding">4dp</dimen>
-
- <!-- Size of application label text -->
- <dimen name="status_bar_recents_app_label_text_size">14dip</dimen>
- <!-- Size of application description text -->
- <dimen name="status_bar_recents_app_description_text_size">14dip</dimen>
- <!-- Size of fading edge for text -->
- <dimen name="status_bar_recents_text_fading_edge_length">20dip</dimen>
- <!-- Size of fading edge for scrolling -->
- <dimen name="status_bar_recents_scroll_fading_edge_length">10dip</dimen>
- <!-- Margin between recents container and glow on the right -->
- <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
- <!-- How far the thumbnail for a recent app appears from left edge -->
- <dimen name="status_bar_recents_thumbnail_left_margin">20dp</dimen>
- <!-- Padding for text descriptions -->
- <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
- <!-- Width of application label text -->
- <dimen name="status_bar_recents_app_label_width">88dip</dimen>
- <!-- Left margin of application label text -->
- <dimen name="status_bar_recents_app_label_left_margin">0dip</dimen>
- <!-- Padding between recents items -->
- <dimen name="status_bar_recents_item_padding">0dip</dimen>
- <!-- When recents first appears, how far the icon and label of the primary activity
- travel -->
- <dimen name="status_bar_recents_app_icon_translate_distance">35dip</dimen>
-
- <!-- Where to place the app icon over the thumbnail -->
- <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen>
- <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
-
<!-- Amount to offset bottom of notification peek window from top of status bar. -->
<dimen name="peek_window_y_offset">-12dp</dimen>
diff --git a/packages/SystemUI/res/values/donottranslate.xml b/packages/SystemUI/res/values/donottranslate.xml
index 351a1fdbda07..30ff7043f688 100644
--- a/packages/SystemUI/res/values/donottranslate.xml
+++ b/packages/SystemUI/res/values/donottranslate.xml
@@ -20,4 +20,10 @@
<!-- Date format for display: should match the lockscreen in /policy. -->
<string name="system_ui_date_pattern">@*android:string/system_ui_date_pattern</string>
+ <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
+ <item type="string" name="keyguard_indication_charging_time_fast_if_translated">@string/keyguard_indication_charging_time</item>
+
+ <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
+ <item type="string" name="keyguard_indication_charging_time_slowly_if_translated">@string/keyguard_indication_charging_time</item>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index db1e688c1244..d567e9759966 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -793,6 +793,12 @@
<!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
<string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+ <!-- Indication on the keyguard that is shown when the device is charging rapidly. Should match keyguard_plugged_in_charging_fast [CHAR LIMIT=40]-->
+ <string name="keyguard_indication_charging_time_fast">Charging rapidly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+
+ <!-- Indication on the keyguard that is shown when the device is charging slowly. Should match keyguard_plugged_in_charging_slowly [CHAR LIMIT=40]-->
+ <string name="keyguard_indication_charging_time_slowly">Charging slowly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+
<!-- Related to user switcher --><skip/>
<!-- Accessibility label for the button that opens the user switcher. -->
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
new file mode 100755
index 000000000000..3eb12711d1a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -0,0 +1,464 @@
+/*
+ * 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.systemui;
+
+import android.animation.ArgbEvaluator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.ContentObserver;
+import android.graphics.*;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.provider.Settings;
+import com.android.systemui.statusbar.policy.BatteryController;
+
+public class BatteryMeterDrawable extends Drawable implements DemoMode,
+ BatteryController.BatteryStateChangeCallback {
+
+ private static final float ASPECT_RATIO = 9.5f / 14.5f;
+ public static final String TAG = BatteryMeterDrawable.class.getSimpleName();
+ public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
+
+ private static final boolean SINGLE_DIGIT_PERCENT = false;
+
+ private static final int FULL = 96;
+
+ private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction
+
+ private final int[] mColors;
+
+ private boolean mShowPercent;
+ private float mButtonHeightFraction;
+ private float mSubpixelSmoothingLeft;
+ private float mSubpixelSmoothingRight;
+ private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
+ private float mTextHeight, mWarningTextHeight;
+ private int mIconTint = Color.WHITE;
+
+ private int mHeight;
+ private int mWidth;
+ private String mWarningString;
+ private final int mCriticalLevel;
+ private int mChargeColor;
+ private final float[] mBoltPoints;
+ private final Path mBoltPath = new Path();
+
+ private final RectF mFrame = new RectF();
+ private final RectF mButtonFrame = new RectF();
+ private final RectF mBoltFrame = new RectF();
+
+ private final Path mShapePath = new Path();
+ private final Path mClipPath = new Path();
+ private final Path mTextPath = new Path();
+
+ private BatteryController mBatteryController;
+ private boolean mPowerSaveEnabled;
+
+ private int mDarkModeBackgroundColor;
+ private int mDarkModeFillColor;
+
+ private int mLightModeBackgroundColor;
+ private int mLightModeFillColor;
+
+ private final SettingObserver mSettingObserver = new SettingObserver();
+
+ private final Context mContext;
+ private final Handler mHandler;
+
+ private int mLevel = -1;
+ private boolean mPluggedIn;
+ private boolean mListening;
+
+ public BatteryMeterDrawable(Context context, Handler handler, int frameColor) {
+ mContext = context;
+ mHandler = handler;
+ final Resources res = context.getResources();
+ TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
+ TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
+
+ final int N = levels.length();
+ mColors = new int[2*N];
+ for (int i=0; i<N; i++) {
+ mColors[2*i] = levels.getInt(i, 0);
+ mColors[2*i+1] = colors.getColor(i, 0);
+ }
+ levels.recycle();
+ colors.recycle();
+ updateShowPercent();
+ mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
+ mCriticalLevel = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+ mButtonHeightFraction = context.getResources().getFraction(
+ R.fraction.battery_button_height_fraction, 1, 1);
+ mSubpixelSmoothingLeft = context.getResources().getFraction(
+ R.fraction.battery_subpixel_smoothing_left, 1, 1);
+ mSubpixelSmoothingRight = context.getResources().getFraction(
+ R.fraction.battery_subpixel_smoothing_right, 1, 1);
+
+ mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mFramePaint.setColor(frameColor);
+ mFramePaint.setDither(true);
+ mFramePaint.setStrokeWidth(0);
+ mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBatteryPaint.setDither(true);
+ mBatteryPaint.setStrokeWidth(0);
+ mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
+ mTextPaint.setTypeface(font);
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+
+ mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mWarningTextPaint.setColor(mColors[1]);
+ font = Typeface.create("sans-serif", Typeface.BOLD);
+ mWarningTextPaint.setTypeface(font);
+ mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
+
+ mChargeColor = context.getColor(R.color.batterymeter_charge_color);
+
+ mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
+ mBoltPoints = loadBoltPoints(res);
+
+ mDarkModeBackgroundColor =
+ context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
+ mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
+ mLightModeBackgroundColor =
+ context.getColor(R.color.light_mode_icon_color_dual_tone_background);
+ mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
+ }
+
+ public void startListening() {
+ mListening = true;
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
+ if (mDemoMode) return;
+ mBatteryController.addStateChangedCallback(this);
+ }
+
+ public void stopListening() {
+ mListening = false;
+ mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
+ if (mDemoMode) return;
+ mBatteryController.removeStateChangedCallback(this);
+ }
+
+ private void postInvalidate() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ invalidateSelf();
+ }
+ });
+ }
+
+ public void setBatteryController(BatteryController batteryController) {
+ mBatteryController = batteryController;
+ mPowerSaveEnabled = mBatteryController.isPowerSave();
+ }
+
+ @Override
+ public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ mLevel = level;
+ mPluggedIn = pluggedIn;
+
+ postInvalidate();
+ }
+
+ @Override
+ public void onPowerSaveChanged() {
+ mPowerSaveEnabled = mBatteryController.isPowerSave();
+ invalidateSelf();
+ }
+
+ private static float[] loadBoltPoints(Resources res) {
+ final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
+ int maxX = 0, maxY = 0;
+ for (int i = 0; i < pts.length; i += 2) {
+ maxX = Math.max(maxX, pts[i]);
+ maxY = Math.max(maxY, pts[i + 1]);
+ }
+ final float[] ptsF = new float[pts.length];
+ for (int i = 0; i < pts.length; i += 2) {
+ ptsF[i] = (float)pts[i] / maxX;
+ ptsF[i + 1] = (float)pts[i + 1] / maxY;
+ }
+ return ptsF;
+ }
+
+ @Override
+ public void setBounds(int left, int top, int right, int bottom) {
+ super.setBounds(left, top, right, bottom);
+ mHeight = bottom - top;
+ mWidth = right - left;
+ mWarningTextPaint.setTextSize(mHeight * 0.75f);
+ mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
+ }
+
+ private void updateShowPercent() {
+ mShowPercent = 0 != Settings.System.getInt(mContext.getContentResolver(),
+ SHOW_PERCENT_SETTING, 0);
+ }
+
+ private int getColorForLevel(int percent) {
+
+ // If we are in power save mode, always use the normal color.
+ if (mPowerSaveEnabled) {
+ return mColors[mColors.length-1];
+ }
+ int thresh, color = 0;
+ for (int i=0; i<mColors.length; i+=2) {
+ thresh = mColors[i];
+ color = mColors[i+1];
+ if (percent <= thresh) {
+
+ // Respect tinting for "normal" level
+ if (i == mColors.length-2) {
+ return mIconTint;
+ } else {
+ return color;
+ }
+ }
+ }
+ return color;
+ }
+
+ public void setDarkIntensity(float darkIntensity) {
+ int backgroundColor = getBackgroundColor(darkIntensity);
+ int fillColor = getFillColor(darkIntensity);
+ mIconTint = fillColor;
+ mFramePaint.setColor(backgroundColor);
+ mBoltPaint.setColor(fillColor);
+ mChargeColor = fillColor;
+ invalidateSelf();
+ }
+
+ private int getBackgroundColor(float darkIntensity) {
+ return getColorForDarkIntensity(
+ darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
+ }
+
+ private int getFillColor(float darkIntensity) {
+ return getColorForDarkIntensity(
+ darkIntensity, mLightModeFillColor, mDarkModeFillColor);
+ }
+
+ private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
+ return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
+ }
+
+ @Override
+ public void draw(Canvas c) {
+ final int level = mLevel;
+
+ if (level == -1) return;
+
+ float drawFrac = (float) level / 100f;
+ final int height = mHeight;
+ final int width = (int) (ASPECT_RATIO * mHeight);
+ int px = (mWidth - width) / 2;
+
+ final int buttonHeight = (int) (height * mButtonHeightFraction);
+
+ mFrame.set(0, 0, width, height);
+ mFrame.offset(px, 0);
+
+ // button-frame: area above the battery body
+ mButtonFrame.set(
+ mFrame.left + Math.round(width * 0.25f),
+ mFrame.top,
+ mFrame.right - Math.round(width * 0.25f),
+ mFrame.top + buttonHeight);
+
+ mButtonFrame.top += mSubpixelSmoothingLeft;
+ mButtonFrame.left += mSubpixelSmoothingLeft;
+ mButtonFrame.right -= mSubpixelSmoothingRight;
+
+ // frame: battery body area
+ mFrame.top += buttonHeight;
+ mFrame.left += mSubpixelSmoothingLeft;
+ mFrame.top += mSubpixelSmoothingLeft;
+ mFrame.right -= mSubpixelSmoothingRight;
+ mFrame.bottom -= mSubpixelSmoothingRight;
+
+ // set the battery charging color
+ mBatteryPaint.setColor(mPluggedIn ? mChargeColor : getColorForLevel(level));
+
+ if (level >= FULL) {
+ drawFrac = 1f;
+ } else if (level <= mCriticalLevel) {
+ drawFrac = 0f;
+ }
+
+ final float levelTop = drawFrac == 1f ? mButtonFrame.top
+ : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
+
+ // define the battery shape
+ mShapePath.reset();
+ mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
+ mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
+ mShapePath.lineTo(mButtonFrame.right, mFrame.top);
+ mShapePath.lineTo(mFrame.right, mFrame.top);
+ mShapePath.lineTo(mFrame.right, mFrame.bottom);
+ mShapePath.lineTo(mFrame.left, mFrame.bottom);
+ mShapePath.lineTo(mFrame.left, mFrame.top);
+ mShapePath.lineTo(mButtonFrame.left, mFrame.top);
+ mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
+
+ if (mPluggedIn) {
+ // define the bolt shape
+ final float bl = mFrame.left + mFrame.width() / 4.5f;
+ final float bt = mFrame.top + mFrame.height() / 6f;
+ final float br = mFrame.right - mFrame.width() / 7f;
+ final float bb = mFrame.bottom - mFrame.height() / 10f;
+ if (mBoltFrame.left != bl || mBoltFrame.top != bt
+ || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
+ mBoltFrame.set(bl, bt, br, bb);
+ mBoltPath.reset();
+ mBoltPath.moveTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ for (int i = 2; i < mBoltPoints.length; i += 2) {
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+ }
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ }
+
+ float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
+ boltPct = Math.min(Math.max(boltPct, 0), 1);
+ if (boltPct <= BOLT_LEVEL_THRESHOLD) {
+ // draw the bolt if opaque
+ c.drawPath(mBoltPath, mBoltPaint);
+ } else {
+ // otherwise cut the bolt out of the overall shape
+ mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
+ }
+ }
+
+ // compute percentage text
+ boolean pctOpaque = false;
+ float pctX = 0, pctY = 0;
+ String pctText = null;
+ if (!mPluggedIn && level > mCriticalLevel && mShowPercent) {
+ mTextPaint.setColor(getColorForLevel(level));
+ mTextPaint.setTextSize(height *
+ (SINGLE_DIGIT_PERCENT ? 0.75f
+ : (mLevel == 100 ? 0.38f : 0.5f)));
+ mTextHeight = -mTextPaint.getFontMetrics().ascent;
+ pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
+ pctX = mWidth * 0.5f;
+ pctY = (mHeight + mTextHeight) * 0.47f;
+ pctOpaque = levelTop > pctY;
+ if (!pctOpaque) {
+ mTextPath.reset();
+ mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
+ // cut the percentage text out of the overall shape
+ mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
+ }
+ }
+
+ // draw the battery shape background
+ c.drawPath(mShapePath, mFramePaint);
+
+ // draw the battery shape, clipped to charging level
+ mFrame.top = levelTop;
+ mClipPath.reset();
+ mClipPath.addRect(mFrame, Path.Direction.CCW);
+ mShapePath.op(mClipPath, Path.Op.INTERSECT);
+ c.drawPath(mShapePath, mBatteryPaint);
+
+ if (!mPluggedIn) {
+ if (level <= mCriticalLevel) {
+ // draw the warning text
+ final float x = mWidth * 0.5f;
+ final float y = (mHeight + mWarningTextHeight) * 0.48f;
+ c.drawText(mWarningString, x, y, mWarningTextPaint);
+ } else if (pctOpaque) {
+ // draw the percentage text
+ c.drawText(pctText, pctX, pctY, mTextPaint);
+ }
+ }
+ }
+
+ // Some stuff required by Drawable.
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+
+ private boolean mDemoMode;
+
+ @Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+ if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+ mBatteryController.removeStateChangedCallback(this);
+ mDemoMode = true;
+ if (mListening) {
+ mBatteryController.removeStateChangedCallback(this);
+ }
+ } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+ mDemoMode = false;
+ postInvalidate();
+ if (mListening) {
+ mBatteryController.addStateChangedCallback(this);
+ }
+ } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
+ String level = args.getString("level");
+ String plugged = args.getString("plugged");
+ if (level != null) {
+ mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100);
+ }
+ if (plugged != null) {
+ mPluggedIn = Boolean.parseBoolean(plugged);
+ }
+ postInvalidate();
+ }
+ }
+
+ private final class SettingObserver extends ContentObserver {
+ public SettingObserver() {
+ super(new Handler());
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ updateShowPercent();
+ postInvalidate();
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 95b58e5e527f..6cb8da4a1016 100755..100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -13,82 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.android.systemui;
-import android.animation.ArgbEvaluator;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.database.ContentObserver;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.graphics.Typeface;
-import android.net.Uri;
-import android.os.BatteryManager;
-import android.os.Bundle;
import android.os.Handler;
-import android.provider.Settings;
import android.util.AttributeSet;
-import android.view.View;
-
+import android.widget.ImageView;
import com.android.systemui.statusbar.policy.BatteryController;
-public class BatteryMeterView extends View implements DemoMode,
- BatteryController.BatteryStateChangeCallback {
- public static final String TAG = BatteryMeterView.class.getSimpleName();
- public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
- public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
-
- private static final boolean SINGLE_DIGIT_PERCENT = false;
-
- private static final int FULL = 96;
-
- private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction
-
- private final int[] mColors;
-
- private boolean mShowPercent;
- private float mButtonHeightFraction;
- private float mSubpixelSmoothingLeft;
- private float mSubpixelSmoothingRight;
- private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
- private float mTextHeight, mWarningTextHeight;
- private int mIconTint = Color.WHITE;
-
- private int mHeight;
- private int mWidth;
- private String mWarningString;
- private final int mCriticalLevel;
- private int mChargeColor;
- private final float[] mBoltPoints;
- private final Path mBoltPath = new Path();
-
- private final RectF mFrame = new RectF();
- private final RectF mButtonFrame = new RectF();
- private final RectF mBoltFrame = new RectF();
-
- private final Path mShapePath = new Path();
- private final Path mClipPath = new Path();
- private final Path mTextPath = new Path();
+public class BatteryMeterView extends ImageView implements BatteryController.BatteryStateChangeCallback {
+ private final BatteryMeterDrawable mDrawable;
private BatteryController mBatteryController;
- private boolean mPowerSaveEnabled;
-
- private int mDarkModeBackgroundColor;
- private int mDarkModeFillColor;
-
- private int mLightModeBackgroundColor;
- private int mLightModeFillColor;
-
- private BatteryTracker mTracker = new BatteryTracker();
- private final SettingObserver mSettingObserver = new SettingObserver();
public BatteryMeterView(Context context) {
this(context, null, 0);
@@ -101,443 +38,52 @@ public class BatteryMeterView extends View implements DemoMode,
public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- final Resources res = context.getResources();
TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
defStyle, 0);
final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
context.getColor(R.color.batterymeter_frame_color));
- TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
- TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
-
- final int N = levels.length();
- mColors = new int[2*N];
- for (int i=0; i<N; i++) {
- mColors[2*i] = levels.getInt(i, 0);
- mColors[2*i+1] = colors.getColor(i, 0);
- }
- levels.recycle();
- colors.recycle();
+ mDrawable = new BatteryMeterDrawable(context, new Handler(), frameColor);
atts.recycle();
- updateShowPercent();
- mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
- mCriticalLevel = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_criticalBatteryWarningLevel);
- mButtonHeightFraction = context.getResources().getFraction(
- R.fraction.battery_button_height_fraction, 1, 1);
- mSubpixelSmoothingLeft = context.getResources().getFraction(
- R.fraction.battery_subpixel_smoothing_left, 1, 1);
- mSubpixelSmoothingRight = context.getResources().getFraction(
- R.fraction.battery_subpixel_smoothing_right, 1, 1);
-
- mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mFramePaint.setColor(frameColor);
- mFramePaint.setDither(true);
- mFramePaint.setStrokeWidth(0);
- mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
- mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBatteryPaint.setDither(true);
- mBatteryPaint.setStrokeWidth(0);
- mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
- mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
- mTextPaint.setTypeface(font);
- mTextPaint.setTextAlign(Paint.Align.CENTER);
-
- mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mWarningTextPaint.setColor(mColors[1]);
- font = Typeface.create("sans-serif", Typeface.BOLD);
- mWarningTextPaint.setTypeface(font);
- mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
-
- mChargeColor = context.getColor(R.color.batterymeter_charge_color);
-
- mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
- mBoltPoints = loadBoltPoints(res);
+ setImageDrawable(mDrawable);
+ }
- mDarkModeBackgroundColor =
- context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
- mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
- mLightModeBackgroundColor =
- context.getColor(R.color.light_mode_icon_color_dual_tone_background);
- mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- filter.addAction(ACTION_LEVEL_TEST);
- final Intent sticky = getContext().registerReceiver(mTracker, filter);
- if (sticky != null) {
- // preload the battery level
- mTracker.onReceive(getContext(), sticky);
- }
mBatteryController.addStateChangedCallback(this);
- getContext().getContentResolver().registerContentObserver(
- Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
+ mDrawable.startListening();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
-
- getContext().unregisterReceiver(mTracker);
mBatteryController.removeStateChangedCallback(this);
- getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
- }
-
- public void setBatteryController(BatteryController batteryController) {
- mBatteryController = batteryController;
- mPowerSaveEnabled = mBatteryController.isPowerSave();
+ mDrawable.stopListening();
}
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- // TODO: Use this callback instead of own broadcast receiver.
+ setContentDescription(
+ getContext().getString(R.string.accessibility_battery_level, level));
}
@Override
public void onPowerSaveChanged() {
- mPowerSaveEnabled = mBatteryController.isPowerSave();
- invalidate();
- }
- private static float[] loadBoltPoints(Resources res) {
- final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
- int maxX = 0, maxY = 0;
- for (int i = 0; i < pts.length; i += 2) {
- maxX = Math.max(maxX, pts[i]);
- maxY = Math.max(maxY, pts[i + 1]);
- }
- final float[] ptsF = new float[pts.length];
- for (int i = 0; i < pts.length; i += 2) {
- ptsF[i] = (float)pts[i] / maxX;
- ptsF[i + 1] = (float)pts[i + 1] / maxY;
- }
- return ptsF;
}
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- mHeight = h;
- mWidth = w;
- mWarningTextPaint.setTextSize(h * 0.75f);
- mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
+ public void setBatteryController(BatteryController mBatteryController) {
+ this.mBatteryController = mBatteryController;
+ mDrawable.setBatteryController(mBatteryController);
}
- private void updateShowPercent() {
- mShowPercent = 0 != Settings.System.getInt(getContext().getContentResolver(),
- SHOW_PERCENT_SETTING, 0);
+ public void setDarkIntensity(float f) {
+ mDrawable.setDarkIntensity(f);
}
-
- private int getColorForLevel(int percent) {
-
- // If we are in power save mode, always use the normal color.
- if (mPowerSaveEnabled) {
- return mColors[mColors.length-1];
- }
- int thresh, color = 0;
- for (int i=0; i<mColors.length; i+=2) {
- thresh = mColors[i];
- color = mColors[i+1];
- if (percent <= thresh) {
-
- // Respect tinting for "normal" level
- if (i == mColors.length-2) {
- return mIconTint;
- } else {
- return color;
- }
- }
- }
- return color;
- }
-
- public void setDarkIntensity(float darkIntensity) {
- int backgroundColor = getBackgroundColor(darkIntensity);
- int fillColor = getFillColor(darkIntensity);
- mIconTint = fillColor;
- mFramePaint.setColor(backgroundColor);
- mBoltPaint.setColor(fillColor);
- mChargeColor = fillColor;
- invalidate();
- }
-
- private int getBackgroundColor(float darkIntensity) {
- return getColorForDarkIntensity(
- darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
- }
-
- private int getFillColor(float darkIntensity) {
- return getColorForDarkIntensity(
- darkIntensity, mLightModeFillColor, mDarkModeFillColor);
- }
-
- private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
- return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
- }
-
- @Override
- public void draw(Canvas c) {
- BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
- final int level = tracker.level;
-
- if (level == BatteryTracker.UNKNOWN_LEVEL) return;
-
- float drawFrac = (float) level / 100f;
- final int pt = getPaddingTop();
- final int pl = getPaddingLeft();
- final int pr = getPaddingRight();
- final int pb = getPaddingBottom();
- final int height = mHeight - pt - pb;
- final int width = mWidth - pl - pr;
-
- final int buttonHeight = (int) (height * mButtonHeightFraction);
-
- mFrame.set(0, 0, width, height);
- mFrame.offset(pl, pt);
-
- // button-frame: area above the battery body
- mButtonFrame.set(
- mFrame.left + Math.round(width * 0.25f),
- mFrame.top,
- mFrame.right - Math.round(width * 0.25f),
- mFrame.top + buttonHeight);
-
- mButtonFrame.top += mSubpixelSmoothingLeft;
- mButtonFrame.left += mSubpixelSmoothingLeft;
- mButtonFrame.right -= mSubpixelSmoothingRight;
-
- // frame: battery body area
- mFrame.top += buttonHeight;
- mFrame.left += mSubpixelSmoothingLeft;
- mFrame.top += mSubpixelSmoothingLeft;
- mFrame.right -= mSubpixelSmoothingRight;
- mFrame.bottom -= mSubpixelSmoothingRight;
-
- // set the battery charging color
- mBatteryPaint.setColor(tracker.plugged ? mChargeColor : getColorForLevel(level));
-
- if (level >= FULL) {
- drawFrac = 1f;
- } else if (level <= mCriticalLevel) {
- drawFrac = 0f;
- }
-
- final float levelTop = drawFrac == 1f ? mButtonFrame.top
- : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
-
- // define the battery shape
- mShapePath.reset();
- mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
-
- if (tracker.plugged) {
- // define the bolt shape
- final float bl = mFrame.left + mFrame.width() / 4.5f;
- final float bt = mFrame.top + mFrame.height() / 6f;
- final float br = mFrame.right - mFrame.width() / 7f;
- final float bb = mFrame.bottom - mFrame.height() / 10f;
- if (mBoltFrame.left != bl || mBoltFrame.top != bt
- || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
- mBoltFrame.set(bl, bt, br, bb);
- mBoltPath.reset();
- mBoltPath.moveTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
- for (int i = 2; i < mBoltPoints.length; i += 2) {
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
- }
- mBoltPath.lineTo(
- mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
- mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
- }
-
- float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
- boltPct = Math.min(Math.max(boltPct, 0), 1);
- if (boltPct <= BOLT_LEVEL_THRESHOLD) {
- // draw the bolt if opaque
- c.drawPath(mBoltPath, mBoltPaint);
- } else {
- // otherwise cut the bolt out of the overall shape
- mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
- }
- }
-
- // compute percentage text
- boolean pctOpaque = false;
- float pctX = 0, pctY = 0;
- String pctText = null;
- if (!tracker.plugged && level > mCriticalLevel && mShowPercent) {
- mTextPaint.setColor(getColorForLevel(level));
- mTextPaint.setTextSize(height *
- (SINGLE_DIGIT_PERCENT ? 0.75f
- : (tracker.level == 100 ? 0.38f : 0.5f)));
- mTextHeight = -mTextPaint.getFontMetrics().ascent;
- pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
- pctX = mWidth * 0.5f;
- pctY = (mHeight + mTextHeight) * 0.47f;
- pctOpaque = levelTop > pctY;
- if (!pctOpaque) {
- mTextPath.reset();
- mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
- // cut the percentage text out of the overall shape
- mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
- }
- }
-
- // draw the battery shape background
- c.drawPath(mShapePath, mFramePaint);
-
- // draw the battery shape, clipped to charging level
- mFrame.top = levelTop;
- mClipPath.reset();
- mClipPath.addRect(mFrame, Path.Direction.CCW);
- mShapePath.op(mClipPath, Path.Op.INTERSECT);
- c.drawPath(mShapePath, mBatteryPaint);
-
- if (!tracker.plugged) {
- if (level <= mCriticalLevel) {
- // draw the warning text
- final float x = mWidth * 0.5f;
- final float y = (mHeight + mWarningTextHeight) * 0.48f;
- c.drawText(mWarningString, x, y, mWarningTextPaint);
- } else if (pctOpaque) {
- // draw the percentage text
- c.drawText(pctText, pctX, pctY, mTextPaint);
- }
- }
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-
- private boolean mDemoMode;
- private BatteryTracker mDemoTracker = new BatteryTracker();
-
- @Override
- public void dispatchDemoCommand(String command, Bundle args) {
- if (!mDemoMode && command.equals(COMMAND_ENTER)) {
- mDemoMode = true;
- mDemoTracker.level = mTracker.level;
- mDemoTracker.plugged = mTracker.plugged;
- } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
- mDemoMode = false;
- postInvalidate();
- } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
- String level = args.getString("level");
- String plugged = args.getString("plugged");
- if (level != null) {
- mDemoTracker.level = Math.min(Math.max(Integer.parseInt(level), 0), 100);
- }
- if (plugged != null) {
- mDemoTracker.plugged = Boolean.parseBoolean(plugged);
- }
- postInvalidate();
- }
- }
-
- private final class BatteryTracker extends BroadcastReceiver {
- public static final int UNKNOWN_LEVEL = -1;
-
- // current battery status
- int level = UNKNOWN_LEVEL;
- String percentStr;
- int plugType;
- boolean plugged;
- int health;
- int status;
- String technology;
- int voltage;
- int temperature;
- boolean testmode = false;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
- if (testmode && ! intent.getBooleanExtra("testmode", false)) return;
-
- level = (int)(100f
- * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
- / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
-
- plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
- plugged = plugType != 0;
- health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH,
- BatteryManager.BATTERY_HEALTH_UNKNOWN);
- status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
- BatteryManager.BATTERY_STATUS_UNKNOWN);
- technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
- voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);
- temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
-
- setContentDescription(
- context.getString(R.string.accessibility_battery_level, level));
- postInvalidate();
- } else if (action.equals(ACTION_LEVEL_TEST)) {
- testmode = true;
- post(new Runnable() {
- int curLevel = 0;
- int incr = 1;
- int saveLevel = level;
- int savePlugged = plugType;
- Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
- @Override
- public void run() {
- if (curLevel < 0) {
- testmode = false;
- dummy.putExtra("level", saveLevel);
- dummy.putExtra("plugged", savePlugged);
- dummy.putExtra("testmode", false);
- } else {
- dummy.putExtra("level", curLevel);
- dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
- : 0);
- dummy.putExtra("testmode", true);
- }
- getContext().sendBroadcast(dummy);
-
- if (!testmode) return;
-
- curLevel += incr;
- if (curLevel == 100) {
- incr *= -1;
- }
- postDelayed(this, 200);
- }
- });
- }
- }
- }
-
- private final class SettingObserver extends ContentObserver {
- public SettingObserver() {
- super(new Handler());
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- super.onChange(selfChange, uri);
- updateShowPercent();
- postInvalidate();
- }
- }
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 33f6564b948a..620732442659 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -34,6 +34,8 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
+import com.android.systemui.classifier.FalsingManager;
+
public class SwipeHelper implements Gefingerpoken {
static final String TAG = "com.android.systemui.SwipeHelper";
private static final boolean DEBUG = false;
@@ -67,6 +69,7 @@ public class SwipeHelper implements Gefingerpoken {
private Handler mHandler;
private int mSwipeDirection;
private VelocityTracker mVelocityTracker;
+ private FalsingManager mFalsingManager;
private float mInitialTouchPos;
private boolean mDragging;
@@ -97,6 +100,7 @@ public class SwipeHelper implements Gefingerpoken {
android.R.interpolator.fast_out_linear_in);
mFalsingThreshold = context.getResources().getDimensionPixelSize(
R.dimen.swipe_helper_falsing_threshold);
+ mFalsingManager = FalsingManager.getInstance(context);
}
public void setLongPressListener(LongPressListener listener) {
@@ -449,8 +453,13 @@ public class SwipeHelper implements Gefingerpoken {
boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
(Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
(velocity > 0) == (getTranslation(mCurrAnimView) > 0);
- boolean falsingDetected = mCallback.isAntiFalsingNeeded()
- && !mTouchAboveFalsingThreshold;
+ boolean falsingDetected = mCallback.isAntiFalsingNeeded();
+
+ if (mFalsingManager.isClassiferEnabled()) {
+ falsingDetected = falsingDetected && mFalsingManager.isFalseTouch();
+ } else {
+ falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold;
+ }
boolean dismissChild = mCallback.canChildBeDismissed(mCurrView)
&& !falsingDetected && (childSwipedFastEnough || childSwipedFarEnough)
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
index c74339b9082b..a6ebc0bf0a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -32,17 +32,26 @@ import java.util.List;
* previously calculated angle. Then it calculates the variance of the differences from a stroke.
* To the differences there is artificially added value 0.0 and the difference between the first
* angle and PI (angles are in radians). It helps with strokes which have few points and punishes
- * more strokes which are not smooth. This classifier also tries to split the stroke into two parts
- * int the place in which the biggest angle is. It calculates the angle variance of the two parts
- * and sums them up. The reason the classifier is doing this, is because some human swipes at the
- * beginning go for a moment in one direction and then they rapidly change direction for the rest
- * of the stroke (like a tick). The final result is the minimum of angle variance of the whole
- * stroke and the sum of angle variances of the two parts split up.
+ * more strokes which are not smooth.
+ *
+ * This classifier also tries to split the stroke into two parts in the place in which the biggest
+ * angle is. It calculates the angle variance of the two parts and sums them up. The reason the
+ * classifier is doing this, is because some human swipes at the beginning go for a moment in one
+ * direction and then they rapidly change direction for the rest of the stroke (like a tick). The
+ * final result is the minimum of angle variance of the whole stroke and the sum of angle variances
+ * of the two parts split up. The classifier tries the tick option only if the first part is
+ * shorter than the second part.
+ *
+ * Additionally, the classifier classifies the angles as left angles (those angles which value is
+ * in [0.0, PI - ANGLE_DEVIATION) interval), straight angles
+ * ([PI - ANGLE_DEVIATION, PI + ANGLE_DEVIATION] interval) and right angles
+ * ((PI + ANGLE_DEVIATION, 2 * PI) interval) and then calculates the percentage of angles which are
+ * in the same direction (straight angles can be left angels or right angles)
*/
-public class AnglesVarianceClassifier extends StrokeClassifier {
+public class AnglesClassifier extends StrokeClassifier {
private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
- public AnglesVarianceClassifier(ClassifierData classifierData) {
+ public AnglesClassifier(ClassifierData classifierData) {
mClassifierData = classifierData;
}
@@ -66,10 +75,14 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
@Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
- return AnglesVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance());
+ Data data = mStrokeMap.get(stroke);
+ return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance())
+ + AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage());
}
private static class Data {
+ private final float ANGLE_DEVIATION = (float) Math.PI / 20.0f;
+
private List<Point> mLastThreePoints = new ArrayList<>();
private float mFirstAngleVariance;
private float mPreviousAngle;
@@ -80,6 +93,12 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
private float mSecondSum;
private float mCount;
private float mSecondCount;
+ private float mFirstLength;
+ private float mLength;
+ private float mAnglesCount;
+ private float mLeftAngles;
+ private float mRightAngles;
+ private float mStraightAngles;
public Data() {
mFirstAngleVariance = 0.0f;
@@ -88,6 +107,8 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
mSumSquares = mSecondSumSquares = 0.0f;
mSum = mSecondSum = 0.0f;
mCount = mSecondCount = 1.0f;
+ mLength = mFirstLength = 0.0f;
+ mAnglesCount = mLeftAngles = mRightAngles = mStraightAngles = 0.0f;
}
public void addPoint(Point point) {
@@ -95,6 +116,9 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
// Repetitions are being ignored so that proper angles are calculated.
if (mLastThreePoints.isEmpty()
|| !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(point)) {
+ if (!mLastThreePoints.isEmpty()) {
+ mLength += mLastThreePoints.get(mLastThreePoints.size() - 1).dist(point);
+ }
mLastThreePoints.add(point);
if (mLastThreePoints.size() == 4) {
mLastThreePoints.remove(0);
@@ -102,6 +126,15 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0),
mLastThreePoints.get(2));
+ mAnglesCount++;
+ if (angle < Math.PI - ANGLE_DEVIATION) {
+ mLeftAngles++;
+ } else if (angle <= Math.PI + ANGLE_DEVIATION) {
+ mStraightAngles++;
+ } else {
+ mRightAngles++;
+ }
+
float difference = angle - mPreviousAngle;
// If this is the biggest angle of the stroke so then we save the value of
@@ -109,6 +142,7 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
// variance of the second part.
if (mBiggestAngle < angle) {
mBiggestAngle = angle;
+ mFirstLength = mLength;
mFirstAngleVariance = getAnglesVariance(mSumSquares, mSum, mCount);
mSecondSumSquares = 0.0f;
mSecondSum = 0.0f;
@@ -132,9 +166,19 @@ public class AnglesVarianceClassifier extends StrokeClassifier {
}
public float getAnglesVariance() {
- return Math.min(getAnglesVariance(mSumSquares, mSum, mCount),
- mFirstAngleVariance + getAnglesVariance(mSecondSumSquares, mSecondSum,
- mSecondCount));
+ float anglesVariance = getAnglesVariance(mSumSquares, mSum, mCount);
+ if (mFirstLength < mLength / 2f) {
+ anglesVariance = Math.min(anglesVariance, mFirstAngleVariance
+ + getAnglesVariance(mSecondSumSquares, mSecondSum, mSecondCount));
+ }
+ return anglesVariance;
+ }
+
+ public float getAnglesPercentage() {
+ if (mAnglesCount == 0.0f) {
+ return 1.0f;
+ }
+ return (Math.max(mLeftAngles, mRightAngles) + mStraightAngles) / mAnglesCount;
}
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
new file mode 100644
index 000000000000..a0ceb2958c33
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
@@ -0,0 +1,27 @@
+/*
+ * 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.systemui.classifier;
+
+public class AnglesPercentageEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value < 1.00) evaluation++;
+ if (value < 0.95) evaluation++;
+ if (value < 0.90) evaluation++;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
index 649279dac285..c83c74f69f90 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
@@ -28,12 +28,10 @@ import java.util.ArrayList;
public class ClassifierData {
private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>();
private ArrayList<Stroke> mEndingStrokes = new ArrayList<>();
- private float mXdpi;
- private float mYdpi;
+ private final float mDpi;
- public ClassifierData(float xdpi, float ydpi) {
- mXdpi = xdpi;
- mYdpi = ydpi;
+ public ClassifierData(float dpi) {
+ mDpi = dpi;
}
public void update(MotionEvent event) {
@@ -46,7 +44,7 @@ public class ClassifierData {
for (int i = 0; i < event.getPointerCount(); i++) {
int id = event.getPointerId(i);
if (mCurrentStrokes.get(id) == null) {
- mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano(), mXdpi, mYdpi));
+ mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano(), mDpi));
}
mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i),
event.getEventTimeNano());
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java
new file mode 100644
index 000000000000..299d0e3634b5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java
@@ -0,0 +1,34 @@
+/*
+ * 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.systemui.classifier;
+
+/**
+ * A classifier which looks at the general direction of a stroke and evaluates it depending on
+ * the type of action that takes place.
+ */
+public class DirectionClassifier extends StrokeClassifier {
+ public DirectionClassifier(ClassifierData classifierData) {
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type, Stroke stroke) {
+ Point firstPoint = stroke.getPoints().get(0);
+ Point lastPoint = stroke.getPoints().get(stroke.getPoints().size() - 1);
+ return DirectionEvaluator.evaluate(lastPoint.x - firstPoint.x, lastPoint.y - firstPoint.y,
+ type);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
new file mode 100644
index 000000000000..e20b1ca64580
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
@@ -0,0 +1,54 @@
+/*
+ * 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.systemui.classifier;
+
+public class DirectionEvaluator {
+ public static float evaluate(float xDiff, float yDiff, int type) {
+ float falsingEvaluation = 5.5f;
+ boolean vertical = Math.abs(yDiff) >= Math.abs(xDiff);
+ switch (type) {
+ case Classifier.QUICK_SETTINGS:
+ case Classifier.NOTIFICATION_DRAG_DOWN:
+ if (!vertical || yDiff <= 0.0) {
+ return falsingEvaluation;
+ }
+ break;
+ case Classifier.NOTIFICATION_DISMISS:
+ if (vertical) {
+ return falsingEvaluation;
+ }
+ break;
+ case Classifier.UNLOCK:
+ if (!vertical || yDiff >= 0.0) {
+ return falsingEvaluation;
+ }
+ break;
+ case Classifier.LEFT_AFFORDANCE:
+ if (xDiff < 0.0 && yDiff > 0.0) {
+ return falsingEvaluation;
+ }
+ break;
+ case Classifier.RIGHT_AFFORDANCE:
+ if (xDiff > 0.0 && yDiff > 0.0) {
+ return falsingEvaluation;
+ }
+ default:
+ break;
+ }
+ return 0.0f;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index c68fff837c6f..735a7c4bad4a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -39,7 +39,11 @@ import com.android.systemui.statusbar.StatusBarState;
public class FalsingManager implements SensorEventListener {
private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer";
- private static final int[] SENSORS = new int[] {
+ private static final int[] CLASSIFIER_SENSORS = new int[] {
+ Sensor.TYPE_PROXIMITY,
+ };
+
+ private static final int[] COLLECTOR_SENSORS = new int[] {
Sensor.TYPE_ACCELEROMETER,
Sensor.TYPE_GYROSCOPE,
Sensor.TYPE_PROXIMITY,
@@ -113,7 +117,17 @@ public class FalsingManager implements SensorEventListener {
private void onSessionStart() {
mBouncerOn = false;
mSessionActive = true;
- for (int sensorType : SENSORS) {
+
+ if (mHumanInteractionClassifier.isEnabled()) {
+ registerSensors(CLASSIFIER_SENSORS);
+ }
+ if (mDataCollector.isEnabled()) {
+ registerSensors(COLLECTOR_SENSORS);
+ }
+ }
+
+ private void registerSensors(int [] sensors) {
+ for (int sensorType : sensors) {
Sensor s = mSensorManager.getDefaultSensor(sensorType);
if (s != null) {
mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
@@ -121,6 +135,10 @@ public class FalsingManager implements SensorEventListener {
}
}
+ public boolean isClassiferEnabled() {
+ return mHumanInteractionClassifier.isEnabled();
+ }
+
private boolean isEnabled() {
return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 6ef805c569dd..a7a569419624 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -23,8 +23,10 @@ import android.os.Build;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.DisplayMetrics;
import android.view.MotionEvent;
+import java.util.ArrayDeque;
import java.util.ArrayList;
/**
@@ -32,6 +34,7 @@ import java.util.ArrayList;
*/
public class HumanInteractionClassifier extends Classifier {
private static final String HIC_ENABLE = "HIC_enable";
+ private static final float FINGER_DISTANCE = 0.1f;
private static HumanInteractionClassifier sInstance = null;
private final Handler mHandler = new Handler();
@@ -39,11 +42,13 @@ public class HumanInteractionClassifier extends Classifier {
private ArrayList<StrokeClassifier> mStrokeClassifiers = new ArrayList<>();
private ArrayList<GestureClassifier> mGestureClassifiers = new ArrayList<>();
+ private ArrayDeque<MotionEvent> mBufferedEvents = new ArrayDeque<>();
private final int mStrokeClassifiersSize;
private final int mGestureClassifiersSize;
+ private final float mDpi;
private HistoryEvaluator mHistoryEvaluator;
- private boolean mEnableClassifier = false;
+ private boolean mEnableClassifier = true;
private int mCurrentType = Classifier.GENERIC;
protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@@ -55,18 +60,24 @@ public class HumanInteractionClassifier extends Classifier {
private HumanInteractionClassifier(Context context) {
mContext = context;
- mClassifierData = new ClassifierData(mContext.getResources().getDisplayMetrics().xdpi,
- mContext.getResources().getDisplayMetrics().ydpi);
+ DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+
+ // If the phone is rotated to landscape, the calculations would be wrong if xdpi and ydpi
+ // were to be used separately. Due negligible differences in xdpi and ydpi we can just
+ // take the average.
+ mDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2.0f;
+ mClassifierData = new ClassifierData(mDpi);
mHistoryEvaluator = new HistoryEvaluator();
- mStrokeClassifiers.add(new AnglesVarianceClassifier(mClassifierData));
+ mStrokeClassifiers.add(new AnglesClassifier(mClassifierData));
mStrokeClassifiers.add(new SpeedClassifier(mClassifierData));
mStrokeClassifiers.add(new DurationCountClassifier(mClassifierData));
mStrokeClassifiers.add(new EndPointRatioClassifier(mClassifierData));
mStrokeClassifiers.add(new EndPointLengthClassifier(mClassifierData));
mStrokeClassifiers.add(new AccelerationClassifier(mClassifierData));
- mStrokeClassifiers.add(new SpeedVarianceClassifier(mClassifierData));
+ mStrokeClassifiers.add(new SpeedAnglesClassifier(mClassifierData));
mStrokeClassifiers.add(new LengthCountClassifier(mClassifierData));
+ mStrokeClassifiers.add(new DirectionClassifier(mClassifierData));
mGestureClassifiers.add(new PointerCountClassifier(mClassifierData));
mGestureClassifiers.add(new ProximityClassifier(mClassifierData));
@@ -101,40 +112,71 @@ public class HumanInteractionClassifier extends Classifier {
@Override
public void onTouchEvent(MotionEvent event) {
- if (mEnableClassifier) {
- mClassifierData.update(event);
+ if (!mEnableClassifier) {
+ return;
+ }
- for (int i = 0; i < mStrokeClassifiersSize; i++) {
- mStrokeClassifiers.get(i).onTouchEvent(event);
+ // If the user is dragging down the notification, he might want to drag it down
+ // enough to see the content, read it for a while and then lift the finger to open
+ // the notification. This kind of motion scores very bad in the Classifier so the
+ // MotionEvents which are close to the current position of the finger are not
+ // sent to the classifiers until the finger moves far enough. When the finger if lifted
+ // up, the last MotionEvent which was far enough from the finger is set as the final
+ // MotionEvent and sent to the Classifiers.
+ if (mCurrentType == Classifier.NOTIFICATION_DRAG_DOWN) {
+ mBufferedEvents.add(MotionEvent.obtain(event));
+ Point pointEnd = new Point(event.getX() / mDpi, event.getY() / mDpi);
+
+ while (pointEnd.dist(new Point(mBufferedEvents.getFirst().getX() / mDpi,
+ mBufferedEvents.getFirst().getY() / mDpi)) > FINGER_DISTANCE) {
+ addTouchEvent(mBufferedEvents.getFirst());
+ mBufferedEvents.remove();
}
- for (int i = 0; i < mGestureClassifiersSize; i++) {
- mGestureClassifiers.get(i).onTouchEvent(event);
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_UP) {
+ mBufferedEvents.getFirst().setAction(MotionEvent.ACTION_UP);
+ addTouchEvent(mBufferedEvents.getFirst());
+ mBufferedEvents.clear();
}
+ } else {
+ addTouchEvent(event);
+ }
+ }
- int size = mClassifierData.getEndingStrokes().size();
- for (int i = 0; i < size; i++) {
- Stroke stroke = mClassifierData.getEndingStrokes().get(i);
- float evaluation = 0.0f;
- for (int j = 0; j < mStrokeClassifiersSize; j++) {
- evaluation += mStrokeClassifiers.get(j).getFalseTouchEvaluation(
- mCurrentType, stroke);
- }
- mHistoryEvaluator.addStroke(evaluation);
- }
+ private void addTouchEvent(MotionEvent event) {
+ mClassifierData.update(event);
- int action = event.getActionMasked();
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- float evaluation = 0.0f;
- for (int i = 0; i < mGestureClassifiersSize; i++) {
- evaluation += mGestureClassifiers.get(i).getFalseTouchEvaluation(mCurrentType);
- }
- mHistoryEvaluator.addGesture(evaluation);
- setType(Classifier.GENERIC);
+ for (int i = 0; i < mStrokeClassifiersSize; i++) {
+ mStrokeClassifiers.get(i).onTouchEvent(event);
+ }
+
+ for (int i = 0; i < mGestureClassifiersSize; i++) {
+ mGestureClassifiers.get(i).onTouchEvent(event);
+ }
+
+ int size = mClassifierData.getEndingStrokes().size();
+ for (int i = 0; i < size; i++) {
+ Stroke stroke = mClassifierData.getEndingStrokes().get(i);
+ float evaluation = 0.0f;
+ for (int j = 0; j < mStrokeClassifiersSize; j++) {
+ evaluation += mStrokeClassifiers.get(j).getFalseTouchEvaluation(
+ mCurrentType, stroke);
}
+ mHistoryEvaluator.addStroke(evaluation);
+ }
- mClassifierData.cleanUp(event);
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ float evaluation = 0.0f;
+ for (int i = 0; i < mGestureClassifiersSize; i++) {
+ evaluation += mGestureClassifiers.get(i).getFalseTouchEvaluation(mCurrentType);
+ }
+ mHistoryEvaluator.addGesture(evaluation);
+ setType(Classifier.GENERIC);
}
+
+ mClassifierData.cleanUp(event);
}
@Override
@@ -149,7 +191,10 @@ public class HumanInteractionClassifier extends Classifier {
}
public boolean isFalseTouch() {
- return mHistoryEvaluator.getEvaluation() >= 5.0f;
+ if (mEnableClassifier) {
+ return mHistoryEvaluator.getEvaluation() >= 5.0f;
+ }
+ return false;
}
public boolean isEnabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
index 1ea467bfb857..cedf4676beec 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
@@ -17,8 +17,11 @@
package com.android.systemui.classifier;
/**
- * A classifier which looks at the ratio between the duration of the stroke and its number of
- * points.
+ * A classifier which looks at the ratio between the length of the stroke and its number of
+ * points. The number of points is subtracted by 2 because the UP event comes in with some delay
+ * and it should not influence the ratio and also strokes which are long and have a small number
+ * of points are punished more (these kind of strokes are usually bad ones and they tend to score
+ * well in other classifiers).
*/
public class LengthCountClassifier extends StrokeClassifier {
public LengthCountClassifier(ClassifierData classifierData) {
@@ -26,6 +29,7 @@ public class LengthCountClassifier extends StrokeClassifier {
@Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
- return LengthCountEvaluator.evaluate(stroke.getTotalLength() / stroke.getCount());
+ return LengthCountEvaluator.evaluate(stroke.getTotalLength()
+ / Math.max(1.0f, stroke.getCount() - 2));
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java
index 68f163d1916b..dac7a6f720a7 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java
@@ -23,10 +23,11 @@ package com.android.systemui.classifier;
public class LengthCountEvaluator {
public static float evaluate(float value) {
float evaluation = 0.0f;
- if (value < 0.07) evaluation++;
+ if (value < 0.09) evaluation++;
if (value < 0.05) evaluation++;
if (value < 0.02) evaluation++;
if (value > 0.6) evaluation++;
+ if (value > 0.9) evaluation++;
if (value > 1.2) evaluation++;
return evaluation;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
index 9a30fe1a425c..d544a3d68671 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
@@ -28,14 +28,17 @@ import java.util.List;
* A classifier which for each point from a stroke, it creates a point on plane with coordinates
* (timeOffsetNano, distanceCoveredUpToThisPoint) (scaled by DURATION_SCALE and LENGTH_SCALE)
* and then it calculates the angle variance of these points like the class
- * {@link AnglesVarianceClassifier} (without splitting it into two parts). The classifier ignores
+ * {@link AnglesClassifier} (without splitting it into two parts). The classifier ignores
* the last point of a stroke because the UP event comes in with some delay and this ruins the
- * smoothness of this curve
+ * smoothness of this curve. Additionally, the classifier classifies calculates the percentage of
+ * angles which value is in [PI - ANGLE_DEVIATION, 2* PI) interval. The reason why the classifier
+ * does that is because the speed of a good stroke is most often increases, so most of these angels
+ * should be in this interval.
*/
-public class SpeedVarianceClassifier extends StrokeClassifier {
+public class SpeedAnglesClassifier extends StrokeClassifier {
private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
- public SpeedVarianceClassifier(ClassifierData classifierData) {
+ public SpeedAnglesClassifier(ClassifierData classifierData) {
mClassifierData = classifierData;
}
@@ -64,12 +67,15 @@ public class SpeedVarianceClassifier extends StrokeClassifier {
@Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
- return SpeedVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance());
+ Data data = mStrokeMap.get(stroke);
+ return SpeedVarianceEvaluator.evaluate(data.getAnglesVariance())
+ + SpeedAnglesPercentageEvaluator.evaluate(data.getAnglesPercentage());
}
private static class Data {
private final float DURATION_SCALE = 1e8f;
private final float LENGTH_SCALE = 1.0f;
+ private final float ANGLE_DEVIATION = (float) Math.PI / 10.0f;
private List<Point> mLastThreePoints = new ArrayList<>();
private Point mPreviousPoint;
@@ -78,6 +84,8 @@ public class SpeedVarianceClassifier extends StrokeClassifier {
private float mSum;
private float mCount;
private float mDist;
+ private float mAnglesCount;
+ private float mAcceleratingAngles;
public Data() {
mPreviousPoint = null;
@@ -86,6 +94,7 @@ public class SpeedVarianceClassifier extends StrokeClassifier {
mSum = 0.0f;
mCount = 1.0f;
mDist = 0.0f;
+ mAnglesCount = mAcceleratingAngles = 0.0f;
}
public void addPoint(Point point) {
@@ -108,6 +117,11 @@ public class SpeedVarianceClassifier extends StrokeClassifier {
float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0),
mLastThreePoints.get(2));
+ mAnglesCount++;
+ if (angle >= (float) Math.PI - ANGLE_DEVIATION) {
+ mAcceleratingAngles++;
+ }
+
float difference = angle - mPreviousAngle;
mSum += difference;
mSumSquares += difference * difference;
@@ -120,5 +134,12 @@ public class SpeedVarianceClassifier extends StrokeClassifier {
public float getAnglesVariance() {
return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
}
+
+ public float getAnglesPercentage() {
+ if (mAnglesCount == 0.0f) {
+ return 1.0f;
+ }
+ return (mAcceleratingAngles) / mAnglesCount;
+ }
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java
new file mode 100644
index 000000000000..2a45fa36dbc6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java
@@ -0,0 +1,27 @@
+/*
+ * 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.systemui.classifier;
+
+public class SpeedAnglesPercentageEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value < 1.00) evaluation++;
+ if (value < 0.95) evaluation++;
+ if (value < 0.90) evaluation++;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
index 49e6fb8b62c9..fb04d3e73a2d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
@@ -29,18 +29,16 @@ public class Stroke {
private long mStartTimeNano;
private long mEndTimeNano;
private float mLength;
- private float mXdpi;
- private float mYdpi;
+ private final float mDpi;
- public Stroke(long eventTimeNano, float xdpi, float ydpi) {
- mXdpi = xdpi;
- mYdpi = ydpi;
+ public Stroke(long eventTimeNano, float dpi) {
+ mDpi = dpi;
mStartTimeNano = mEndTimeNano = eventTimeNano;
}
public void addPoint(float x, float y, long eventTimeNano) {
mEndTimeNano = eventTimeNano;
- Point point = new Point(x / mXdpi, y / mYdpi, eventTimeNano - mStartTimeNano);
+ Point point = new Point(x / mDpi, y / mDpi, eventTimeNano - mStartTimeNano);
if (!mPoints.isEmpty()) {
mLength += mPoints.get(mPoints.size() - 1).dist(point);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 3b3593b4c477..e562682551e4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -30,16 +30,7 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.qs.QSTile.State;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.Listenable;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.*;
import java.util.Collection;
import java.util.Objects;
@@ -349,6 +340,9 @@ public abstract class QSTile<TState extends State> implements Listenable {
CastController getCastController();
FlashlightController getFlashlightController();
KeyguardMonitor getKeyguardMonitor();
+ UserSwitcherController getUserSwitcherController();
+ UserInfoController getUserInfoController();
+ BatteryController getBatteryController();
public interface Callback {
void onTilesChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 08cdc1eee65c..e575923fdd09 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -267,7 +267,7 @@ public class QSTileView extends ViewGroup {
final int w = MeasureSpec.getSize(widthMeasureSpec);
final int h = MeasureSpec.getSize(heightMeasureSpec);
final int iconSpec = exactly(mIconSizePx);
- mIcon.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.AT_MOST), iconSpec);
+ mIcon.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), iconSpec);
switch (mType) {
case QS_TYPE_QUICK:
mCircle.measure(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
index 84b05d0055ea..f676ea3499cb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
@@ -44,7 +44,8 @@ public class CustomQSTileHost extends QSTileHost {
host.getRotationLockController(), host.getNetworkController(),
host.getZenModeController(), host.getHotspotController(), host.getCastController(),
host.getFlashlightController(), host.getUserSwitcherController(),
- host.getKeyguardMonitor(), new BlankSecurityController());
+ host.getUserInfoController(), host.getKeyguardMonitor(),
+ new BlankSecurityController(), host.getBatteryController());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
new file mode 100644
index 000000000000..8f9655d65d15
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -0,0 +1,96 @@
+/*
+ * 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.systemui.qs.tiles;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.BatteryMeterDrawable;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.BatteryController;
+
+import java.text.NumberFormat;
+
+public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback {
+
+ private final BatteryMeterDrawable mDrawable;
+ private final BatteryController mBatteryController;
+
+ private int mLevel;
+
+ public BatteryTile(Host host) {
+ super(host);
+ mBatteryController = host.getBatteryController();
+ mDrawable = new BatteryMeterDrawable(host.getContext(), new Handler(),
+ host.getContext().getColor(R.color.batterymeter_frame_color));
+ mDrawable.setBatteryController(mBatteryController);
+ }
+
+ @Override
+ protected State newTileState() {
+ return new QSTile.State();
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_BATTERY_TILE;
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ mDrawable.startListening();
+ mBatteryController.addStateChangedCallback(this);
+ } else {
+ mDrawable.stopListening();
+ mBatteryController.removeStateChangedCallback(this);
+ }
+ }
+
+ @Override
+ protected void handleClick() {
+ mHost.startActivityDismissingKeyguard(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY));
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object arg) {
+ int level = (arg != null) ? (Integer) arg : mLevel;
+ String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
+
+ state.visible = true;
+ state.icon = new Icon() {
+ @Override
+ public Drawable getDrawable(Context context) {
+ return mDrawable;
+ }
+ };
+ state.label = percentage;
+ }
+
+ @Override
+ public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+ mLevel = level;
+ refreshState((Integer) level);
+ }
+
+ @Override
+ public void onPowerSaveChanged() {
+
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java
new file mode 100644
index 000000000000..3675f02b9dee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java
@@ -0,0 +1,81 @@
+/*
+ * 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.systemui.qs.tiles;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileView;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.R;
+
+public class QLockTile extends QSTile<QSTile.State> implements KeyguardMonitor.Callback {
+
+ private final KeyguardMonitor mKeyguard;
+
+ public QLockTile(Host host) {
+ super(host);
+ mKeyguard = host.getKeyguardMonitor();
+ }
+
+ @Override
+ public int getTileType() {
+ return QSTileView.QS_TYPE_QUICK;
+ }
+
+ @Override
+ protected State newTileState() {
+ return new State();
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ mKeyguard.addCallback(this);
+ } else {
+ mKeyguard.removeCallback(this);
+ }
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_LOCK_TILE;
+ }
+
+ @Override
+ public void onKeyguardChanged() {
+ refreshState();
+ }
+
+ @Override
+ protected void handleClick() {
+ if (mKeyguard.isShowing()) {
+ mKeyguard.unlock();
+ } else {
+ mKeyguard.lock();
+ }
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object arg) {
+ // TOD: Content description.
+ state.visible = true;
+ if (mKeyguard.isShowing()) {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_lock);
+ } else {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_lock_open);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
new file mode 100644
index 000000000000..3c5ab8d491b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -0,0 +1,88 @@
+/*
+ * 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.systemui.qs.tiles;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.Pair;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+
+public class UserTile extends QSTile<QSTile.State> implements UserInfoController.OnUserInfoChangedListener {
+
+ private final UserSwitcherController mUserSwitcherController;
+ private final UserInfoController mUserInfoController;
+ private Pair<String, Drawable> mLastUpdate;
+
+ public UserTile(Host host) {
+ super(host);
+ mUserSwitcherController = host.getUserSwitcherController();
+ mUserInfoController = host.getUserInfoController();
+ }
+
+ @Override
+ protected State newTileState() {
+ return new QSTile.State();
+ }
+
+ @Override
+ protected void handleClick() {
+ showDetail(true);
+ }
+
+ @Override
+ public DetailAdapter getDetailAdapter() {
+ return mUserSwitcherController.userDetailAdapter;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_USER_TILE;
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ mUserInfoController.addListener(this);
+ } else {
+ mUserInfoController.remListener(this);
+ }
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object arg) {
+ final Pair<String, Drawable> p = arg != null ? (Pair<String, Drawable>) arg : mLastUpdate;
+ state.visible = p != null;
+ if (!state.visible) return;
+ state.label = p.first;
+ // TODO: Better content description.
+ state.contentDescription = p.first;
+ state.icon = new Icon() {
+ @Override
+ public Drawable getDrawable(Context context) {
+ return p.second;
+ }
+ };
+ }
+
+ @Override
+ public void onUserInfoChanged(String name, Drawable picture) {
+ mLastUpdate = new Pair<>(name, picture);
+ refreshState(mLastUpdate);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index cbccaf887d69..a78351a1ffbc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -38,7 +38,6 @@ import android.util.MutableBoolean;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
-
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
@@ -75,6 +74,8 @@ import java.util.ArrayList;
public class Recents extends SystemUI
implements ActivityOptions.OnAnimationStartedListener, RecentsComponent {
+ public final static int EVENT_BUS_PRIORITY = 1;
+
final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "triggeredFromAltTab";
final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "triggeredFromHomeKey";
final public static String EXTRA_RECENTS_VISIBILITY = "recentsVisibility";
@@ -164,7 +165,6 @@ public class Recents extends SystemUI
static RecentsTaskLoadPlan sInstanceLoadPlan;
static Recents sInstance;
- LayoutInflater mInflater;
SystemServicesProxy mSystemServicesProxy;
Handler mHandler;
TaskStackListenerImpl mTaskStackListener;
@@ -176,12 +176,14 @@ public class Recents extends SystemUI
// Task launching
RecentsConfiguration mConfig;
+ Rect mSearchBarBounds = new Rect();
Rect mTaskStackBounds = new Rect();
- Rect mSystemInsets = new Rect();
+ Rect mLastTaskViewBounds = new Rect();
TaskViewTransform mTmpTransform = new TaskViewTransform();
int mStatusBarHeight;
int mNavBarHeight;
int mNavBarWidth;
+ int mTaskBarHeight;
// Header (for transition)
TaskViewHeader mHeaderBar;
@@ -229,11 +231,11 @@ public class Recents extends SystemUI
if (sInstance == null) {
sInstance = this;
}
+ Resources res = mContext.getResources();
RecentsTaskLoader.initialize(mContext);
- mInflater = LayoutInflater.from(mContext);
+ LayoutInflater inflater = LayoutInflater.from(mContext);
mSystemServicesProxy = new SystemServicesProxy(mContext);
mHandler = new Handler();
- mTaskStackBounds = new Rect();
mAppWidgetHost = new RecentsAppWidgetHost(mContext, Constants.Values.App.AppWidgetHostId);
// Register the task stack listener
@@ -241,7 +243,7 @@ public class Recents extends SystemUI
mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
// Only the owner has the callback to update the SysUI visibility flags, so all non-owner
- // instances of AlternateRecentsComponent needs to notify the owner when the visibility
+ // instances of RecentsComponent needs to notify the owner when the visibility
// changes.
if (mSystemServicesProxy.isForegroundUserSystem()) {
mProxyBroadcastReceiver = new RecentsOwnerEventProxyReceiver();
@@ -254,8 +256,16 @@ public class Recents extends SystemUI
// Initialize some static datastructures
TaskStackViewLayoutAlgorithm.initializeCurve();
- // Load the header bar layout
- reloadHeaderBarLayout();
+ // Initialize the static configuration resources
+ mConfig = RecentsConfiguration.initialize(mContext, mSystemServicesProxy);
+ mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
+ mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
+ mTaskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
+ mDummyStackView = new TaskStackView(mContext, new TaskStack());
+ mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
+ null, false);
+ reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
// When we start, preload the data associated with the previous recent tasks.
// We can use a new plan since the caches will be the same.
@@ -273,6 +283,7 @@ public class Recents extends SystemUI
@Override
public void onBootCompleted() {
mBootCompleted = true;
+ reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
}
/** Shows the Recents. */
@@ -293,7 +304,7 @@ public class Recents extends SystemUI
mTriggeredFromAltTab = triggeredFromAltTab;
try {
- startRecentsActivity();
+ showRecentsActivity();
} catch (ActivityNotFoundException e) {
Console.logRawError("Failed to launch RecentAppsIntent", e);
}
@@ -488,54 +499,52 @@ public class Recents extends SystemUI
void configurationChanged() {
// Don't reuse task stack views if the configuration changes
mCanReuseTaskStackViews = false;
- // Reload the header bar layout
- reloadHeaderBarLayout();
+ mConfig.updateOnConfigurationChange();
}
- /** Prepares the header bar layout. */
- void reloadHeaderBarLayout() {
- Resources res = mContext.getResources();
+ /**
+ * Prepares the header bar layout for the next transition, if the task view bounds has changed
+ * since the last call, it will attempt to re-measure and layout the header bar to the new size.
+ *
+ * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one
+ * is not already bound (can be expensive)
+ */
+ void reloadHeaderBarLayout(boolean tryAndBindSearchWidget) {
Rect windowRect = mSystemServicesProxy.getWindowRect();
- mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
- mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
- mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
- mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
- mConfig.updateOnConfigurationChange();
- Rect searchBarBounds = new Rect();
- // Try and pre-emptively bind the search widget on startup to ensure that we
- // have the right thumbnail bounds to animate to.
- // Note: We have to reload the widget id before we get the task stack bounds below
- if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
- mConfig.getSearchBarBounds(windowRect,
- mStatusBarHeight, searchBarBounds);
+ // Update the configuration for the current state
+ mConfig.update(mContext, mSystemServicesProxy, mSystemServicesProxy.getWindowRect());
+
+ if (tryAndBindSearchWidget) {
+ // Try and pre-emptively bind the search widget on startup to ensure that we
+ // have the right thumbnail bounds to animate to.
+ // Note: We have to reload the widget id before we get the task stack bounds below
+ if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
+ mConfig.getSearchBarBounds(windowRect,
+ mStatusBarHeight, mSearchBarBounds);
+ }
}
mConfig.getAvailableTaskStackBounds(windowRect,
- mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), searchBarBounds,
- mTaskStackBounds);
- if (mConfig.isLandscape && mConfig.hasTransposedNavBar) {
- mSystemInsets.set(0, mStatusBarHeight, mNavBarWidth, 0);
- } else {
- mSystemInsets.set(0, mStatusBarHeight, 0, mNavBarHeight);
- }
+ mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0),
+ mSearchBarBounds, mTaskStackBounds);
+ int systemBarBottomInset = mConfig.hasTransposedNavBar ? 0 : mNavBarHeight;
- // Inflate the header bar layout so that we can rebind and draw it for the transition
- TaskStack stack = new TaskStack();
- mDummyStackView = new TaskStackView(mContext, stack);
+ // Rebind the header bar and draw it for the transition
TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
Rect taskStackBounds = new Rect(mTaskStackBounds);
- taskStackBounds.bottom -= mSystemInsets.bottom;
+ taskStackBounds.bottom -= systemBarBottomInset;
algo.computeRects(windowRect.width(), windowRect.height(), taskStackBounds);
- Rect taskViewSize = algo.getUntransformedTaskViewSize();
- int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
- synchronized (mHeaderBarLock) {
- mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null,
- false);
- mHeaderBar.measure(
- View.MeasureSpec.makeMeasureSpec(taskViewSize.width(), View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY));
- // TODO: may not be needed
- mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight);
+ Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
+ if (!taskViewBounds.equals(mLastTaskViewBounds)) {
+ mLastTaskViewBounds.set(taskViewBounds);
+
+ int taskViewWidth = taskViewBounds.width();
+ synchronized (mHeaderBarLock) {
+ mHeaderBar.measure(
+ View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY));
+ mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight);
+ }
}
}
@@ -560,17 +569,17 @@ public class Recents extends SystemUI
return;
} else {
// Otherwise, start the recents activity
- startRecentsActivity(topTask, isTopTaskHome.value);
+ showRecentsActivity(topTask, isTopTaskHome.value);
}
}
- /** Starts the recents activity if it is not already running */
- void startRecentsActivity() {
+ /** Shows the recents activity if it is not already running */
+ void showRecentsActivity() {
// Check if the top task is in the home stack, and start the recents activity
ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
MutableBoolean isTopTaskHome = new MutableBoolean(true);
if (topTask == null || !mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
- startRecentsActivity(topTask, isTopTaskHome.value);
+ showRecentsActivity(topTask, isTopTaskHome.value);
}
}
@@ -732,30 +741,18 @@ public class Recents extends SystemUI
return mTmpTransform;
}
- /** Starts the recents activity */
- void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) {
+ /** Shows the recents activity */
+ void showRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) {
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
- RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
+
+ // Update the header bar if necessary
+ reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
if (sInstanceLoadPlan == null) {
// Create a new load plan if onPreloadRecents() was never triggered
sInstanceLoadPlan = loader.createLoadPlan(mContext);
}
- // Temporarily skip the transition (use a dummy fade) if multi stack is enabled.
- // For multi-stack we need to figure out where each of the tasks are going.
- if (mConfig.multiWindowEnabled) {
- loader.preloadTasks(sInstanceLoadPlan, true);
- TaskStack stack = sInstanceLoadPlan.getTaskStack();
- mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, true);
- TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
- mDummyStackView.computeStackVisibilityReport();
- ActivityOptions opts = getUnknownTransitionActivityOptions();
- startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
- false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
- return;
- }
-
if (!sInstanceLoadPlan.hasTasks()) {
loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
}
@@ -774,7 +771,7 @@ public class Recents extends SystemUI
ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
mDummyStackView);
if (opts != null) {
- startAlternateRecentsActivity(topTask, opts, false /* fromHome */,
+ startRecentsActivity(topTask, opts, false /* fromHome */,
false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
} else {
// Fall through below to the non-thumbnail transition
@@ -794,12 +791,12 @@ public class Recents extends SystemUI
boolean fromSearchHome = (homeActivityPackage != null) &&
homeActivityPackage.equals(searchWidgetPackage);
ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
- startAlternateRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
+ startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
false /* fromThumbnail */, stackVr);
} else {
// Otherwise we do the normal fade from an unknown source
ActivityOptions opts = getUnknownTransitionActivityOptions();
- startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
+ startRecentsActivity(topTask, opts, true /* fromHome */,
false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
}
}
@@ -807,19 +804,20 @@ public class Recents extends SystemUI
}
/** Starts the recents activity */
- void startAlternateRecentsActivity(ActivityManager.RunningTaskInfo topTask,
- ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
- TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
+ void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
+ ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
+ TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
// Update the configuration based on the launch options
- mConfig.launchedFromHome = fromSearchHome || fromHome;
- mConfig.launchedFromSearchHome = fromSearchHome;
- mConfig.launchedFromAppWithThumbnail = fromThumbnail;
- mConfig.launchedToTaskId = (topTask != null) ? topTask.id : -1;
- mConfig.launchedWithAltTab = mTriggeredFromAltTab;
- mConfig.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
- mConfig.launchedNumVisibleTasks = vr.numVisibleTasks;
- mConfig.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
- mConfig.launchedHasConfigurationChanged = false;
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+ launchState.launchedFromHome = fromSearchHome || fromHome;
+ launchState.launchedFromSearchHome = fromSearchHome;
+ launchState.launchedFromAppWithThumbnail = fromThumbnail;
+ launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+ launchState.launchedWithAltTab = mTriggeredFromAltTab;
+ launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
+ launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
+ launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
+ launchState.launchedHasConfigurationChanged = false;
Intent intent = new Intent(sToggleRecentsAction);
intent.setClassName(sRecentsPackage, sRecentsActivity);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index c53e57325c3d..1a0eb24e1fb5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -25,21 +25,20 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Configuration;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.UserHandle;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewStub;
-import android.widget.Toast;
-
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
import com.android.systemui.recents.misc.Console;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsPackageMonitor;
import com.android.systemui.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
@@ -48,16 +47,17 @@ import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.recents.views.ViewAnimation;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
* The main Recents activity that is started from AlternateRecentsComponent.
*/
-public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
- RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
+public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks {
+
+ public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
RecentsConfiguration mConfig;
+ RecentsPackageMonitor mPackageMonitor;
long mLastTabKeyEventTime;
// Top level views
@@ -182,18 +182,19 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
}
// Start loading tasks according to the load plan
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
if (!plan.hasTasks()) {
- loader.preloadTasks(plan, mConfig.launchedFromHome);
+ loader.preloadTasks(plan, launchState.launchedFromHome);
}
RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
- loadOpts.runningTaskId = mConfig.launchedToTaskId;
- loadOpts.numVisibleTasks = mConfig.launchedNumVisibleTasks;
- loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
+ loadOpts.runningTaskId = launchState.launchedToTaskId;
+ loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+ loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
loader.loadTasks(this, plan, loadOpts);
TaskStack stack = plan.getTaskStack();
- mConfig.launchedWithNoRecentTasks = !plan.hasTasks();
- if (!mConfig.launchedWithNoRecentTasks) {
+ launchState.launchedWithNoRecentTasks = !plan.hasTasks();
+ if (!launchState.launchedWithNoRecentTasks) {
mRecentsView.setTaskStack(stack);
}
@@ -204,19 +205,19 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent,
ActivityOptions.makeCustomAnimation(this,
- mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :
+ launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :
R.anim.recents_to_launcher_enter,
- mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :
+ launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :
R.anim.recents_to_launcher_exit));
// Mark the task that is the launch target
int launchTaskIndexInStack = 0;
- if (mConfig.launchedToTaskId != -1) {
+ if (launchState.launchedToTaskId != -1) {
ArrayList<Task> tasks = stack.getTasks();
int taskCount = tasks.size();
for (int j = 0; j < taskCount; j++) {
Task t = tasks.get(j);
- if (t.key.id == mConfig.launchedToTaskId) {
+ if (t.key.id == launchState.launchedToTaskId) {
t.isLaunchTarget = true;
launchTaskIndexInStack = tasks.size() - j - 1;
break;
@@ -225,7 +226,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
}
// Update the top level view's visibilities
- if (mConfig.launchedWithNoRecentTasks) {
+ if (launchState.launchedWithNoRecentTasks) {
if (mEmptyView == null) {
mEmptyView = mEmptyViewStub.inflate();
}
@@ -246,13 +247,13 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
mScrimViews.prepareEnterRecentsAnimation();
// Keep track of whether we launched from the nav bar button or via alt-tab
- if (mConfig.launchedWithAltTab) {
+ if (launchState.launchedWithAltTab) {
MetricsLogger.count(this, "overview_trigger_alttab", 1);
} else {
MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
}
// Keep track of whether we launched from an app or from home
- if (mConfig.launchedFromAppWithThumbnail) {
+ if (launchState.launchedFromAppWithThumbnail) {
MetricsLogger.count(this, "overview_source_app", 1);
// If from an app, track the stack index of the app in the stack (for affiliated tasks)
MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
@@ -266,6 +267,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
/** Dismisses recents if we are already visible and the intent is to toggle the recents view */
boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) {
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
// If we currently have filtered stacks, then unfilter those first
@@ -274,7 +276,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
// If we have a focused Task, launch that Task now
if (mRecentsView.launchFocusedTask()) return true;
// If we launched from Home, then return to Home
- if (mConfig.launchedFromHome) {
+ if (launchState.launchedFromHome) {
dismissRecentsToHomeRaw(true);
return true;
}
@@ -320,11 +322,17 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ // Register this activity with the event bus
+ EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
+
// For the non-primary user, ensure that the SystemServicesProxy and configuration is
// initialized
RecentsTaskLoader.initialize(this);
SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
- mConfig = RecentsConfiguration.reinitialize(this, ssp);
+ mConfig = RecentsConfiguration.initialize(this, ssp);
+ mConfig.update(this, ssp, ssp.getWindowRect());
+ mPackageMonitor = new RecentsPackageMonitor();
// Initialize the widget host (the host id is static and does not change)
mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId);
@@ -337,7 +345,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
- mScrimViews = new SystemBarScrimViews(this, mConfig);
+ mScrimViews = new SystemBarScrimViews(this);
// Bind the search app widget when we first start up
mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
@@ -358,6 +366,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
@Override
protected void onStart() {
super.onStart();
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
SystemServicesProxy ssp = loader.getSystemServicesProxy();
@@ -371,7 +380,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
registerReceiver(mServiceBroadcastReceiver, filter);
// Register any broadcast receivers for the task loader
- loader.registerReceivers(this, mRecentsView);
+ mPackageMonitor.register(this);
// Update the recent tasks
updateRecentsTasks();
@@ -379,12 +388,13 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
// If this is a new instance from a configuration change, then we have to manually trigger
// the enter animation state, or if recents was relaunched by AM, without going through
// the normal mechanisms
- boolean wasLaunchedByAm = !mConfig.launchedFromHome && !mConfig.launchedFromAppWithThumbnail;
- if (mConfig.launchedHasConfigurationChanged || wasLaunchedByAm) {
+ boolean wasLaunchedByAm = !launchState.launchedFromHome &&
+ !launchState.launchedFromAppWithThumbnail;
+ if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
onEnterAnimationTriggered();
}
- if (!mConfig.launchedHasConfigurationChanged) {
+ if (!launchState.launchedHasConfigurationChanged) {
mRecentsView.disableLayersForOneFrame();
}
}
@@ -402,6 +412,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
protected void onStop() {
super.onStop();
MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY);
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
SystemServicesProxy ssp = loader.getSystemServicesProxy();
Recents.notifyVisibilityChanged(this, ssp, false);
@@ -413,17 +424,17 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
unregisterReceiver(mServiceBroadcastReceiver);
// Unregister any broadcast receivers for the task loader
- loader.unregisterReceivers();
+ mPackageMonitor.unregister();
// Workaround for b/22542869, if the RecentsActivity is started again, but without going
// through SystemUI, we need to reset the config launch flags to ensure that we do not
// wait on the system to send a signal that was never queued.
- mConfig.launchedFromHome = false;
- mConfig.launchedFromSearchHome = false;
- mConfig.launchedFromAppWithThumbnail = false;
- mConfig.launchedToTaskId = -1;
- mConfig.launchedWithAltTab = false;
- mConfig.launchedHasConfigurationChanged = false;
+ launchState.launchedFromHome = false;
+ launchState.launchedFromSearchHome = false;
+ launchState.launchedFromAppWithThumbnail = false;
+ launchState.launchedToTaskId = -1;
+ launchState.launchedWithAltTab = false;
+ launchState.launchedHasConfigurationChanged = false;
}
@Override
@@ -435,6 +446,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
// Stop listening for widget package changes if there was one bound
mAppWidgetHost.stopListening();
+ EventBus.getDefault().unregister(this);
}
public void onEnterAnimationTriggered() {
@@ -444,16 +456,12 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
mRecentsView.startEnterRecentsAnimation(ctx);
if (mSearchWidgetInfo != null) {
- final WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks> cbRef =
- new WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks>(
- RecentsActivity.this);
ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
@Override
public void run() {
// Start listening for widget package changes if there is one bound
- RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks cb = cbRef.get();
- if (cb != null) {
- mAppWidgetHost.startListening(cb);
+ if (mAppWidgetHost != null) {
+ mAppWidgetHost.startListening();
}
}
});
@@ -475,8 +483,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_TAB: {
+ int altTabKeyDelay = getResources().getInteger(R.integer.recents_alt_tab_key_delay);
boolean hasRepKeyTimeElapsed = (SystemClock.elapsedRealtime() -
- mLastTabKeyEventTime) > mConfig.altTabKeyDelay;
+ mLastTabKeyEventTime) > altTabKeyDelay;
if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) {
// Focus the next task in the stack
final boolean backward = event.isShiftPressed();
@@ -514,9 +523,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
@Override
public void onBackPressed() {
- // Test mode where back does not do anything
- if (mConfig.debugModeEnabled) return;
-
// Dismiss Recents to the focused Task or Home
dismissRecentsToFocusedTaskOrHome(true);
}
@@ -572,10 +578,13 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
mAfterPauseRunnable = r;
}
- /**** RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks Implementation ****/
+ /**** EventBus events ****/
- @Override
- public void refreshSearchWidgetView() {
+ public final void onBusEvent(AppWidgetProviderChangedEvent event) {
+ refreshSearchWidgetView();
+ }
+
+ private void refreshSearchWidgetView() {
if (mSearchWidgetInfo != null) {
SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
int searchWidgetId = ssp.getSearchAppWidgetId(this);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
new file mode 100644
index 000000000000..e2e0e918ab51
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 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.systemui.recents;
+
+/**
+ * The launch state of the RecentsActivity.
+ *
+ * TODO: We will be refactoring this out RecentsConfiguration.
+ * Current Constraints:
+ * - needed in onStart() before onNewIntent()
+ * - needs to be reset when Recents is hidden
+ * - needs to be computed in Recents component
+ * - needs to be accessible by views
+ */
+public class RecentsActivityLaunchState {
+
+ public RecentsConfiguration mConfig;
+
+ public boolean launchedWithAltTab;
+ public boolean launchedWithNoRecentTasks;
+ public boolean launchedFromAppWithThumbnail;
+ public boolean launchedFromHome;
+ public boolean launchedFromSearchHome;
+ public boolean launchedReuseTaskStackViews;
+ public boolean launchedHasConfigurationChanged;
+ public int launchedToTaskId;
+ public int launchedNumVisibleTasks;
+ public int launchedNumVisibleThumbnails;
+
+ RecentsActivityLaunchState(RecentsConfiguration config) {
+ mConfig = config;
+ }
+
+ /** Called when the configuration has changed, and we want to reset any configuration specific
+ * members. */
+ public void updateOnConfigurationChange() {
+ // Reset this flag on configuration change to ensure that we recreate new task views
+ launchedReuseTaskStackViews = false;
+ // Set this flag to indicate that the configuration has changed since Recents last launched
+ launchedHasConfigurationChanged = true;
+ }
+
+ /** Returns whether the status bar scrim should be animated when shown for the first time. */
+ public boolean shouldAnimateStatusBarScrim() {
+ return launchedFromHome;
+ }
+
+ /** Returns whether the status bar scrim should be visible. */
+ public boolean hasStatusBarScrim() {
+ return !launchedWithNoRecentTasks;
+ }
+
+ /** Returns whether the nav bar scrim should be animated when shown for the first time. */
+ public boolean shouldAnimateNavBarScrim() {
+ return true;
+ }
+
+ /** Returns whether the nav bar scrim should be visible. */
+ public boolean hasNavBarScrim() {
+ // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
+ return !launchedWithNoRecentTasks && mConfig.hasTransposedNavBar;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
index 0102332b17cb..fc96c11e4124 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
@@ -20,24 +20,19 @@ import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
/** Our special app widget host for the Search widget */
public class RecentsAppWidgetHost extends AppWidgetHost {
- /* Callbacks to notify when an app package changes */
- interface RecentsAppWidgetHostCallbacks {
- void refreshSearchWidgetView();
- }
-
- RecentsAppWidgetHostCallbacks mCb;
boolean mIsListening;
public RecentsAppWidgetHost(Context context, int hostId) {
super(context, hostId);
}
- public void startListening(RecentsAppWidgetHostCallbacks cb) {
- mCb = cb;
+ public void startListening() {
if (!mIsListening) {
mIsListening = true;
super.startListening();
@@ -47,11 +42,9 @@ public class RecentsAppWidgetHost extends AppWidgetHost {
@Override
public void stopListening() {
if (mIsListening) {
+ mIsListening = false;
super.stopListening();
}
- // Ensure that we release any references to the callbacks
- mCb = null;
- mIsListening = false;
}
@Override
@@ -66,8 +59,8 @@ public class RecentsAppWidgetHost extends AppWidgetHost {
@Override
protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
super.onProviderChanged(appWidgetId, appWidgetInfo);
- if (mIsListening && mCb != null) {
- mCb.refreshSearchWidgetView();
+ if (mIsListening) {
+ EventBus.getDefault().send(new AppWidgetProviderChangedEvent());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index b41b5e75e0f6..52b9521b9952 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -16,27 +16,29 @@
package com.android.systemui.recents;
-import android.app.ActivityManager;
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.recents.misc.Console;
import com.android.systemui.recents.misc.SystemServicesProxy;
-
-/** A static Recents configuration for the current context
- * NOTE: We should not hold any references to a Context from a static instance */
+/**
+ * Application resources that can be retrieved from the application context and are not specifically
+ * tied to the current activity.
+ */
public class RecentsConfiguration {
static RecentsConfiguration sInstance;
- static int sPrevConfigurationHashCode;
+
+ private static final int LARGE_SCREEN_MIN_DP = 600;
+ private static final int XLARGE_SCREEN_MIN_DP = 720;
+
+ // Variables that are used for global calculations
+ private static final float STACK_SIDE_PADDING_PHONES_PCT = 0.03333f;
+ private static final float STACK_SIZE_PADDING_TABLETS_PCT = 0.075f;
+ private static final float STACK_SIZE_PADDING_LARGE_TABLETS_PCT = 0.15f;
+ private static final int SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS = 64;
+ private static final int SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS = 72;
/** Levels of svelte in increasing severity/austerity. */
// No svelting.
@@ -50,123 +52,81 @@ public class RecentsConfiguration {
// Disable all thumbnail loading.
public static final int SVELTE_DISABLE_LOADING = 3;
- /** Interpolators */
- public Interpolator fastOutSlowInInterpolator;
- public Interpolator fastOutLinearInInterpolator;
- public Interpolator linearOutSlowInInterpolator;
- public Interpolator quintOutInterpolator;
+ // Launch states
+ public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState(this);
- /** Filtering */
- public int filteringCurrentViewsAnimDuration;
- public int filteringNewViewsAnimDuration;
-
- /** Insets */
- public Rect systemInsets = new Rect();
- public Rect displayRect = new Rect();
-
- /** Layout */
- boolean isLandscape;
+ // TODO: Values determined by the current context, needs to be refactored into something that is
+ // agnostic of the activity context, but still calculable from the Recents component for
+ // the transition into recents
boolean hasTransposedSearchBar;
boolean hasTransposedNavBar;
-
- /** Loading */
- public int maxNumTasksToLoad;
-
- /** Search bar */
- public int searchBarSpaceHeightPx;
-
- /** Task stack */
- public int taskStackScrollDuration;
- public int taskStackMaxDim;
- public int taskStackTopPaddingPx;
- public int dismissAllButtonSizePx;
public float taskStackWidthPaddingPct;
- public float taskStackOverscrollPct;
-
- /** Transitions */
- public int transitionEnterFromAppDelay;
- public int transitionEnterFromHomeDelay;
-
- /** Task view animation and styles */
- public int taskViewEnterFromAppDuration;
- public int taskViewEnterFromHomeDuration;
- public int taskViewEnterFromHomeStaggerDelay;
- public int taskViewExitToAppDuration;
- public int taskViewExitToHomeDuration;
- public int taskViewRemoveAnimDuration;
- public int taskViewRemoveAnimTranslationXPx;
- public int taskViewTranslationZMinPx;
- public int taskViewTranslationZMaxPx;
- public int taskViewRoundedCornerRadiusPx;
- public int taskViewHighlightPx;
- public int taskViewAffiliateGroupEnterOffsetPx;
- public float taskViewThumbnailAlpha;
-
- /** Task bar colors */
- public int taskBarViewDefaultBackgroundColor;
- public int taskBarViewLightTextColor;
- public int taskBarViewDarkTextColor;
- public int taskBarViewHighlightColor;
- public float taskBarViewAffiliationColorMinAlpha;
- /** Task bar size & animations */
- public int taskBarHeight;
- public int taskBarDismissDozeDelaySeconds;
-
- /** Nav bar scrim */
- public int navBarScrimEnterDuration;
-
- /** Launch states */
- public boolean launchedWithAltTab;
- public boolean launchedWithNoRecentTasks;
- public boolean launchedFromAppWithThumbnail;
- public boolean launchedFromHome;
- public boolean launchedFromSearchHome;
- public boolean launchedReuseTaskStackViews;
- public boolean launchedHasConfigurationChanged;
- public int launchedToTaskId;
- public int launchedNumVisibleTasks;
- public int launchedNumVisibleThumbnails;
+ // Since the positions in Recents has to be calculated globally (before the RecentsActivity
+ // starts), we need to calculate some resource values ourselves, instead of relying on framework
+ // resources.
+ public final boolean isLargeScreen;
+ public final boolean isXLargeScreen;
+ public final int smallestWidth;
/** Misc **/
public boolean useHardwareLayers;
- public int altTabKeyDelay;
public boolean fakeShadows;
+ public int svelteLevel;
+ public int searchBarSpaceHeightPx;
/** Dev options and global settings */
public boolean multiWindowEnabled;
public boolean lockToAppEnabled;
- public boolean developerOptionsEnabled;
- public boolean debugModeEnabled;
- public int svelteLevel;
/** Private constructor */
- private RecentsConfiguration(Context context) {
- // Properties that don't have to be reloaded with each configuration change can be loaded
- // here.
+ private RecentsConfiguration(Context context, SystemServicesProxy ssp) {
+ // Load only resources that can not change after the first load either through developer
+ // settings or via multi window
+ Context appContext = context.getApplicationContext();
+ Resources res = appContext.getResources();
+ useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
+ fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
+ svelteLevel = res.getInteger(R.integer.recents_svelte_level);
+
+ float density = context.getResources().getDisplayMetrics().density;
+ smallestWidth = ssp.getDeviceSmallestWidth();
+ isLargeScreen = smallestWidth >= (int) (density * LARGE_SCREEN_MIN_DP);
+ isXLargeScreen = smallestWidth >= (int) (density * XLARGE_SCREEN_MIN_DP);
+ searchBarSpaceHeightPx = isLargeScreen ?
+ (int) (density * SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS) :
+ (int) (density * SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS);
+ if (isLargeScreen) {
+ taskStackWidthPaddingPct = STACK_SIZE_PADDING_TABLETS_PCT;
+ } else if (isXLargeScreen) {
+ taskStackWidthPaddingPct = STACK_SIZE_PADDING_LARGE_TABLETS_PCT;
+ } else {
+ taskStackWidthPaddingPct = STACK_SIDE_PADDING_PHONES_PCT;
+ }
+ }
+
+ /**
+ * Updates the configuration based on the current state of the system
+ */
+ void update(Context context, SystemServicesProxy ssp, Rect windowRect) {
+ // Only update resources that can change after the first load, either through developer
+ // settings or via multi window
+ lockToAppEnabled = ssp.getSystemSetting(context,
+ Settings.System.LOCK_TO_APP_ENABLED) != 0;
+ multiWindowEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window"));
- // Interpolators
- fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
- linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.linear_out_slow_in);
- quintOutInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.decelerate_quint);
+ // Recompute some values based on the given state, since we can not rely on the resource
+ // system to get certain values.
+ boolean isLandscape = windowRect.width() > windowRect.height();
+ hasTransposedNavBar = isLandscape && isLargeScreen && !isXLargeScreen;
+ hasTransposedSearchBar = isLandscape && isLargeScreen && !isXLargeScreen;
}
/** Updates the configuration to the current context */
- public static RecentsConfiguration reinitialize(Context context, SystemServicesProxy ssp) {
+ public static RecentsConfiguration initialize(Context context, SystemServicesProxy ssp) {
if (sInstance == null) {
- sInstance = new RecentsConfiguration(context);
+ sInstance = new RecentsConfiguration(context, ssp);
}
- int configHashCode = context.getResources().getConfiguration().hashCode();
- if (sPrevConfigurationHashCode != configHashCode) {
- sInstance.update(context);
- sPrevConfigurationHashCode = configHashCode;
- }
- sInstance.updateOnReinitialize(context, ssp);
return sInstance;
}
@@ -175,145 +135,18 @@ public class RecentsConfiguration {
return sInstance;
}
- /** Updates the state, given the specified context */
- void update(Context context) {
- Resources res = context.getResources();
- DisplayMetrics dm = res.getDisplayMetrics();
-
- // Debug mode
- debugModeEnabled = Prefs.getBoolean(context, Prefs.Key.DEBUG_MODE_ENABLED,
- false /* defaultValue */);
- if (debugModeEnabled) {
- Console.Enabled = true;
- }
-
- // Layout
- isLandscape = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
- hasTransposedSearchBar = res.getBoolean(R.bool.recents_has_transposed_search_bar);
- hasTransposedNavBar = res.getBoolean(R.bool.recents_has_transposed_nav_bar);
-
- // Insets
- displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
-
- // Filtering
- filteringCurrentViewsAnimDuration =
- res.getInteger(R.integer.recents_filter_animate_current_views_duration);
- filteringNewViewsAnimDuration =
- res.getInteger(R.integer.recents_filter_animate_new_views_duration);
-
- // Loading
- maxNumTasksToLoad = ActivityManager.getMaxRecentTasksStatic();
-
- // Search Bar
- searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
-
- // Task stack
- taskStackScrollDuration =
- res.getInteger(R.integer.recents_animate_task_stack_scroll_duration);
- taskStackWidthPaddingPct = res.getFloat(R.dimen.recents_stack_width_padding_percentage);
- taskStackOverscrollPct = res.getFloat(R.dimen.recents_stack_overscroll_percentage);
- taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
- taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
- dismissAllButtonSizePx = res.getDimensionPixelSize(R.dimen.recents_dismiss_all_button_size);
-
- // Transition
- transitionEnterFromAppDelay =
- res.getInteger(R.integer.recents_enter_from_app_transition_duration);
- transitionEnterFromHomeDelay =
- res.getInteger(R.integer.recents_enter_from_home_transition_duration);
-
- // Task view animation and styles
- taskViewEnterFromAppDuration =
- res.getInteger(R.integer.recents_task_enter_from_app_duration);
- taskViewEnterFromHomeDuration =
- res.getInteger(R.integer.recents_task_enter_from_home_duration);
- taskViewEnterFromHomeStaggerDelay =
- res.getInteger(R.integer.recents_task_enter_from_home_stagger_delay);
- taskViewExitToAppDuration =
- res.getInteger(R.integer.recents_task_exit_to_app_duration);
- taskViewExitToHomeDuration =
- res.getInteger(R.integer.recents_task_exit_to_home_duration);
- taskViewRemoveAnimDuration =
- res.getInteger(R.integer.recents_animate_task_view_remove_duration);
- taskViewRemoveAnimTranslationXPx =
- res.getDimensionPixelSize(R.dimen.recents_task_view_remove_anim_translation_x);
- taskViewRoundedCornerRadiusPx =
- res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
- taskViewHighlightPx = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight);
- taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
- taskViewTranslationZMaxPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
- taskViewAffiliateGroupEnterOffsetPx =
- res.getDimensionPixelSize(R.dimen.recents_task_view_affiliate_group_enter_offset);
- taskViewThumbnailAlpha = res.getFloat(R.dimen.recents_task_view_thumbnail_alpha);
-
- // Task bar colors
- taskBarViewDefaultBackgroundColor = context.getColor(
- R.color.recents_task_bar_default_background_color);
- taskBarViewLightTextColor = context.getColor(R.color.recents_task_bar_light_text_color);
- taskBarViewDarkTextColor = context.getColor(R.color.recents_task_bar_dark_text_color);
- taskBarViewHighlightColor = context.getColor(R.color.recents_task_bar_highlight_color);
- taskBarViewAffiliationColorMinAlpha = res.getFloat(
- R.dimen.recents_task_affiliation_color_min_alpha_percentage);
-
- // Task bar size & animations
- taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
- taskBarDismissDozeDelaySeconds =
- res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds);
-
- // Nav bar scrim
- navBarScrimEnterDuration =
- res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration);
-
- // Misc
- useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
- altTabKeyDelay = res.getInteger(R.integer.recents_alt_tab_key_delay);
- fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
- svelteLevel = res.getInteger(R.integer.recents_svelte_level);
- }
-
- /** Updates the system insets */
- public void updateSystemInsets(Rect insets) {
- systemInsets.set(insets);
- }
-
- /** Updates the states that need to be re-read whenever we re-initialize. */
- void updateOnReinitialize(Context context, SystemServicesProxy ssp) {
- // Check if the developer options are enabled
- developerOptionsEnabled = ssp.getGlobalSetting(context,
- Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) != 0;
- lockToAppEnabled = ssp.getSystemSetting(context,
- Settings.System.LOCK_TO_APP_ENABLED) != 0;
- multiWindowEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window"));
+ /**
+ * Returns the activity launch state.
+ * TODO: This will be refactored out of RecentsConfiguration.
+ */
+ public RecentsActivityLaunchState getLaunchState() {
+ return mLaunchState;
}
/** Called when the configuration has changed, and we want to reset any configuration specific
* members. */
public void updateOnConfigurationChange() {
- // Reset this flag on configuration change to ensure that we recreate new task views
- launchedReuseTaskStackViews = false;
- // Set this flag to indicate that the configuration has changed since Recents last launched
- launchedHasConfigurationChanged = true;
- }
-
- /** Returns whether the status bar scrim should be animated when shown for the first time. */
- public boolean shouldAnimateStatusBarScrim() {
- return launchedFromHome;
- }
-
- /** Returns whether the status bar scrim should be visible. */
- public boolean hasStatusBarScrim() {
- return !launchedWithNoRecentTasks;
- }
-
- /** Returns whether the nav bar scrim should be animated when shown for the first time. */
- public boolean shouldAnimateNavBarScrim() {
- return true;
- }
-
- /** Returns whether the nav bar scrim should be visible. */
- public boolean hasNavBarScrim() {
- // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
- return !launchedWithNoRecentTasks && (!hasTransposedNavBar || !isLandscape);
+ mLaunchState.updateOnConfigurationChange();
}
/**
@@ -322,14 +155,17 @@ public class RecentsConfiguration {
*/
public void getAvailableTaskStackBounds(Rect windowBounds, int topInset,
int rightInset, Rect searchBarBounds, Rect taskStackBounds) {
- if (isLandscape && hasTransposedSearchBar) {
- // In landscape, the search bar appears on the left, but we overlay it on top
- taskStackBounds.set(windowBounds.left, windowBounds.top + topInset,
- windowBounds.right - rightInset, windowBounds.bottom);
+ if (hasTransposedNavBar) {
+ // In landscape phones, the search bar appears on the left, but we overlay it on top
+ int swInset = getInsetToSmallestWidth(windowBounds.right - rightInset -
+ windowBounds.left);
+ taskStackBounds.set(windowBounds.left + swInset, windowBounds.top + topInset,
+ windowBounds.right - swInset - rightInset, windowBounds.bottom);
} else {
// In portrait, the search bar appears on the top (which already has the inset)
- taskStackBounds.set(windowBounds.left, searchBarBounds.bottom,
- windowBounds.right, windowBounds.bottom);
+ int swInset = getInsetToSmallestWidth(windowBounds.right - windowBounds.left);
+ taskStackBounds.set(windowBounds.left + swInset, searchBarBounds.bottom,
+ windowBounds.right - swInset, windowBounds.bottom);
}
}
@@ -340,8 +176,8 @@ public class RecentsConfiguration {
public void getSearchBarBounds(Rect windowBounds, int topInset, Rect searchBarSpaceBounds) {
// Return empty rects if search is not enabled
int searchBarSize = searchBarSpaceHeightPx;
- if (isLandscape && hasTransposedSearchBar) {
- // In landscape, the search bar appears on the left
+ if (hasTransposedSearchBar) {
+ // In landscape phones, the search bar appears on the left
searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset,
windowBounds.left + searchBarSize, windowBounds.bottom);
} else {
@@ -350,4 +186,14 @@ public class RecentsConfiguration {
windowBounds.right, windowBounds.top + topInset + searchBarSize);
}
}
+
+ /**
+ * Constrain the width of the landscape stack to the smallest width of the device.
+ */
+ private int getInsetToSmallestWidth(int availableWidth) {
+ if (availableWidth > smallestWidth) {
+ return (availableWidth - smallestWidth) / 2;
+ }
+ return 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index 703c7d27312f..59df293f71d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -16,17 +16,18 @@
package com.android.systemui.recents;
+import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
-import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
+import android.widget.Toast;
import com.android.systemui.R;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoader;
@@ -50,10 +51,18 @@ public class RecentsResizeTaskDialog extends DialogFragment {
private static final int PLACE_BOTTOM_LEFT = 7;
private static final int PLACE_BOTTOM_RIGHT = 8;
private static final int PLACE_FULL = 9;
+ private static final int PLACE_DOCK_LEFT = 10;
+ private static final int PLACE_DOCK_RIGHT = 11;
+ private static final int PLACE_DOCK_TOP = 12;
+ private static final int PLACE_DOCK_BOTTOM = 13;
// The button resource ID combined with the arrangement command.
private static final int[][] BUTTON_DEFINITIONS =
- {{R.id.place_left, PLACE_LEFT},
+ {{R.id.place_dock_left, PLACE_DOCK_LEFT},
+ {R.id.place_dock_right, PLACE_DOCK_RIGHT},
+ {R.id.place_dock_top, PLACE_DOCK_TOP},
+ {R.id.place_dock_bottom, PLACE_DOCK_BOTTOM},
+ {R.id.place_left, PLACE_LEFT},
{R.id.place_right, PLACE_RIGHT},
{R.id.place_top, PLACE_TOP},
{R.id.place_bottom, PLACE_BOTTOM},
@@ -72,6 +81,12 @@ public class RecentsResizeTaskDialog extends DialogFragment {
private Rect[] mBounds = {new Rect(), new Rect(), new Rect(), new Rect()};
private Task[] mTasks = {null, null, null, null};
+ /**
+ * Called by FragmentManager
+ */
+ public RecentsResizeTaskDialog() {
+ }
+
public RecentsResizeTaskDialog(FragmentManager mgr, RecentsActivity activity) {
mFragmentManager = mgr;
mRecentsActivity = activity;
@@ -82,13 +97,11 @@ public class RecentsResizeTaskDialog extends DialogFragment {
void showResizeTaskDialog(Task mainTask, RecentsView rv) {
mTasks[0] = mainTask;
mRecentsView = rv;
-
- show(mFragmentManager, TAG);
+ showAllowingStateLoss(mFragmentManager, TAG);
}
/** Creates a new resize-task dialog. */
- private void createResizeTaskDialog(final Context context, LayoutInflater inflater,
- AlertDialog.Builder builder) {
+ private void createResizeTaskDialog(LayoutInflater inflater, AlertDialog.Builder builder) {
builder.setTitle(R.string.recents_caption_resize);
mResizeTaskDialogContent =
inflater.inflate(R.layout.recents_task_resize_dialog, null, false);
@@ -100,7 +113,17 @@ public class RecentsResizeTaskDialog extends DialogFragment {
b.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
- placeTasks(action);
+ switch (action) {
+ case PLACE_DOCK_LEFT:
+ case PLACE_DOCK_RIGHT:
+ case PLACE_DOCK_TOP:
+ case PLACE_DOCK_BOTTOM:
+ placeDockTasks(action);
+ break;
+ default:
+ placeTasks(action);
+ break;
+ }
}
});
}
@@ -109,7 +132,7 @@ public class RecentsResizeTaskDialog extends DialogFragment {
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- dismiss();
+ dismissAllowingStateLoss();
}
});
@@ -118,7 +141,7 @@ public class RecentsResizeTaskDialog extends DialogFragment {
/** Helper function to place window(s) on the display according to an arrangement request. */
private void placeTasks(int arrangement) {
- Rect rect = mSsp.getWindowRect();
+ Rect rect = mSsp.getDisplayRect();
for (int i = 0; i < mBounds.length; ++i) {
mBounds[i].set(rect);
if (i != 0) {
@@ -193,7 +216,7 @@ public class RecentsResizeTaskDialog extends DialogFragment {
break;
case PLACE_FULL:
// Nothing to change.
- mBounds[0] = null;
+ mBounds[0] = new Rect();
break;
}
@@ -207,7 +230,7 @@ public class RecentsResizeTaskDialog extends DialogFragment {
}
// Get rid of the dialog.
- dismiss();
+ dismissAllowingStateLoss();
mRecentsActivity.dismissRecentsToHomeWithoutTransitionAnimation();
// In debug mode, we force all task to be resizeable regardless of the
@@ -229,12 +252,44 @@ public class RecentsResizeTaskDialog extends DialogFragment {
}
}
+ /**
+ * Helper function to place docked window(s) on the display according to an arrangement request.
+ */
+ private void placeDockTasks(int arrangement) {
+ int createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+ switch (arrangement) {
+ case PLACE_DOCK_LEFT:
+ createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+ break;
+ case PLACE_DOCK_TOP:
+ createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+ break;
+ case PLACE_DOCK_RIGHT:
+ createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+ break;
+ case PLACE_DOCK_BOTTOM:
+ createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+ break;
+ }
+
+ // Dismiss the dialog before trying to launch the task
+ dismissAllowingStateLoss();
+
+ if (mTasks[0].key.stackId != ActivityManager.DOCKED_STACK_ID) {
+ int taskId = mTasks[0].key.id;
+ mSsp.setTaskResizeable(taskId);
+ mSsp.dockTask(taskId, createMode);
+ mRecentsView.launchTask(mTasks[0], null);
+ } else {
+ Toast.makeText(getContext(), "Already docked", Toast.LENGTH_SHORT);
+ }
+ }
+
@Override
public Dialog onCreateDialog(Bundle args) {
- final Context context = this.getActivity();
LayoutInflater inflater = getActivity().getLayoutInflater();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- createResizeTaskDialog(context, inflater, builder);
+ createResizeTaskDialog(inflater, builder);
return builder.create();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index cbf5c058d102..231843ea2690 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -39,7 +39,6 @@ import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
-
import com.android.systemui.R;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
new file mode 100644
index 000000000000..4addfa57e900
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -0,0 +1,844 @@
+/*
+ * Copyright (C) 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.systemui.recents.events;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.MutableBoolean;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Represents a subscriber, which implements various event bus handler methods.
+ */
+class Subscriber {
+ private WeakReference<Object> mSubscriber;
+
+ long registrationTime;
+
+ Subscriber(Object subscriber, long registrationTime) {
+ mSubscriber = new WeakReference<>(subscriber);
+ this.registrationTime = registrationTime;
+ }
+
+ public String toString(int priority) {
+ Object sub = mSubscriber.get();
+ String id = Integer.toHexString(System.identityHashCode(sub));
+ return sub.getClass().getSimpleName() + " [0x" + id + ", P" + priority + "]";
+ }
+
+ public Object getReference() {
+ return mSubscriber.get();
+ }
+}
+
+/**
+ * Represents an event handler with a priority.
+ */
+class EventHandler {
+ int priority;
+ Subscriber subscriber;
+ EventHandlerMethod method;
+
+ EventHandler(Subscriber subscriber, EventHandlerMethod method, int priority) {
+ this.subscriber = subscriber;
+ this.method = method;
+ this.priority = priority;
+ }
+
+ @Override
+ public String toString() {
+ return subscriber.toString(priority) + " " + method.toString();
+ }
+}
+
+/**
+ * Represents the low level method handling a particular event.
+ */
+class EventHandlerMethod {
+ private Method mMethod;
+ Class<? extends EventBus.Event> eventType;
+
+ EventHandlerMethod(Method method, Class<? extends EventBus.Event> eventType) {
+ mMethod = method;
+ mMethod.setAccessible(true);
+ this.eventType = eventType;
+ }
+
+ public void invoke(Object target, EventBus.Event event)
+ throws InvocationTargetException, IllegalAccessException {
+ mMethod.invoke(target, event);
+ }
+
+ @Override
+ public String toString() {
+ return mMethod.getName() + "(" + eventType.getSimpleName() + ")";
+ }
+}
+
+/**
+ * A simple in-process event bus. It is simple because we can make assumptions about the state of
+ * SystemUI and Recent's lifecycle.
+ *
+ * <p>
+ * Currently, there is a single EventBus that handles {@link EventBus.Event}s for each subscriber
+ * on the main application thread. Publishers can send() events to synchronously call subscribers
+ * of that event, or post() events to be processed in the next run of the {@link Looper}. In
+ * addition, the EventBus supports sending and handling {@link EventBus.InterprocessEvent}s
+ * (within the same package) implemented using standard {@link BroadcastReceiver} mechanism.
+ * Interprocess events must be posted using postInterprocess() to ensure that it is dispatched
+ * correctly across processes.
+ *
+ * <p>
+ * Subscribers must be registered with a particular EventBus before they will receive events, and
+ * handler methods must match a specific signature.
+ *
+ * <p>
+ * Event method signature:<ul>
+ * <li>Methods must be public final
+ * <li>Methods must return void
+ * <li>Methods must be called "onBusEvent"
+ * <li>Methods must take one parameter, of class type deriving from {@link EventBus.Event}
+ * </ul>
+ *
+ * <p>
+ * Interprocess-Event method signature:<ul>
+ * <li>Methods must be public final
+ * <li>Methods must return void
+ * <li>Methods must be called "onInterprocessBusEvent"
+ * <li>Methods must take one parameter, of class type deriving from {@link EventBus.InterprocessEvent}
+ * </ul>
+ * </p>
+ *
+ * </p>
+ * Each subscriber can be registered with a given priority (default 1), and events will be dispatch
+ * in decreasing order of priority. For subscribers with the same priority, events will be
+ * dispatched by latest registration time to earliest.
+ *
+ * <p>
+ * Interprocess events must extend {@link EventBus.InterprocessEvent}, have a constructor which
+ * takes a {@link Bundle} and implement toBundle(). This allows us to serialize events to be sent
+ * across processes.
+ *
+ * <p>
+ * Caveats:<ul>
+ * <li>The EventBus keeps a {@link WeakReference} to the publisher to prevent memory leaks, so
+ * there must be another strong reference to the publisher for it to not get garbage-collected and
+ * continue receiving events.
+ * <li>Because the event handlers are called back using reflection, the EventBus is not intended
+ * for use in tight, performance criticial loops. For most user input/system callback events, this
+ * is generally of low enough frequency to use the EventBus.
+ * <li>Because the event handlers are called back using reflection, there will often be no
+ * references to them from actual code. The proguard configuration will be need to be updated to
+ * keep these extra methods:
+ *
+ * -keepclassmembers class ** {
+ * public void onBusEvent(**);
+ * public void onInterprocessBusEvent(**);
+ * }
+ * -keepclassmembers class ** extends **.EventBus$InterprocessEvent {
+ * public <init>(android.os.Bundle);
+ * }
+ *
+ * <li>Subscriber registration can be expensive depending on the subscriber's {@link Class}. This
+ * is only done once per class type, but if possible, it is best to pre-register an instance of
+ * that class beforehand or when idle.
+ * <li>Each event should be sent once. Events may hold internal information about the current
+ * dispatch, or may be queued to be dispatched on another thread (if posted from a non-main thread),
+ * so it may be unsafe to edit, change, or re-send the event again.
+ * <li>Events should follow a pattern of public-final POD (plain old data) objects, where they are
+ * initialized by the constructor and read by each subscriber of that event. Subscribers should
+ * never alter events as they are processed, and this enforces that pattern.
+ * </ul>
+ *
+ * <p>
+ * Future optimizations:
+ * <li>throw exception/log when a subscriber loses the reference
+ * <li>trace cost per registration & invocation
+ * <li>trace cross-process invocation
+ * <li>register(subscriber, Class&lt;?&gt;...) -- pass in exact class types you want registered
+ * <li>setSubscriberEventHandlerPriority(subscriber, Class<Event>, priority)
+ * <li>allow subscribers to implement interface, ie. EventBus.Subscriber, which lets then test a
+ * message before invocation (ie. check if task id == this task id)
+ * <li>add postOnce() which automatically debounces
+ * <li>add postDelayed() which delays / postDelayedOnce() which delays and bounces
+ * <li>consolidate register() and registerInterprocess()
+ * <li>sendForResult&lt;ReturnType&gt;(Event) to send and get a result, but who will send the
+ * result?
+ * </p>
+ */
+public class EventBus extends BroadcastReceiver {
+
+ public static final String TAG = "EventBus";
+
+ /**
+ * An event super class that allows us to track internal event state across subscriber
+ * invocations.
+ *
+ * Events should not be edited by subscribers.
+ */
+ public static class Event {
+ // Indicates that this event's dispatch should be traced and logged to logcat
+ boolean trace;
+ // Indicates that this event must be posted on the EventBus's looper thread before invocation
+ boolean requiresPost;
+ // Not currently exposed, allows a subscriber to cancel further dispatch of this event
+ boolean cancelled;
+
+ // Only accessible from derived events
+ protected Event() {}
+ }
+
+ /**
+ * An inter-process event super class that allows us to track user state across subscriber
+ * invocations.
+ */
+ public static class InterprocessEvent extends Event {
+ private static final String EXTRA_USER = "_user";
+
+ // The user which this event originated from
+ public final int user;
+
+ // Only accessible from derived events
+ protected InterprocessEvent(int user) {
+ this.user = user;
+ }
+
+ /**
+ * Called from the event bus
+ */
+ protected InterprocessEvent(Bundle b) {
+ user = b.getInt(EXTRA_USER);
+ }
+
+ protected Bundle toBundle() {
+ Bundle b = new Bundle();
+ b.putInt(EXTRA_USER, user);
+ return b;
+ }
+ }
+
+ /**
+ * Proguard must also know, and keep, all methods matching this signature.
+ *
+ * -keepclassmembers class ** {
+ * public void onBusEvent(**);
+ * public void onInterprocessBusEvent(**);
+ * }
+ */
+ private static final String METHOD_PREFIX = "onBusEvent";
+ private static final String INTERPROCESS_METHOD_PREFIX = "onInterprocessBusEvent";
+
+ // Ensures that interprocess events can only be sent from a process holding this permission. */
+ private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+
+ // Used for passing event data across process boundaries
+ private static final String EXTRA_INTERPROCESS_EVENT_BUNDLE = "interprocess_event_bundle";
+
+ // The default priority of all subscribers
+ private static final int DEFAULT_SUBSCRIBER_PRIORITY = 1;
+
+ // Used for debugging everything
+ private static final boolean DEBUG_TRACE_ALL = false;
+
+ // Orders the handlers by priority and registration time
+ private static final Comparator<EventHandler> EVENT_HANDLER_COMPARATOR = new Comparator<EventHandler>() {
+ @Override
+ public int compare(EventHandler h1, EventHandler h2) {
+ // Rank the handlers by priority descending, followed by registration time descending.
+ // aka. the later registered
+ if (h1.priority != h2.priority) {
+ return h2.priority - h1.priority;
+ } else {
+ return Long.compare(h2.subscriber.registrationTime, h1.subscriber.registrationTime);
+ }
+ }
+ };
+
+ // Used for initializing the default bus
+ private static final Object sLock = new Object();
+ private static EventBus sDefaultBus;
+
+ // The handler to post all events
+ private Handler mHandler;
+
+ // Keep track of whether we have registered a broadcast receiver already, so that we can
+ // unregister ourselves before re-registering again with a new IntentFilter.
+ private boolean mHasRegisteredReceiver;
+
+ /**
+ * Map from event class -> event handler list. Keeps track of the actual mapping from event
+ * to subscriber method.
+ */
+ private HashMap<Class<? extends Event>, ArrayList<EventHandler>> mEventTypeMap = new HashMap<>();
+
+ /**
+ * Map from subscriber class -> event handler method lists. Used to determine upon registration
+ * of a new subscriber whether we need to read all the subscriber's methods again using
+ * reflection or whether we can just add the subscriber to the event type map.
+ */
+ private HashMap<Class<? extends Object>, ArrayList<EventHandlerMethod>> mSubscriberTypeMap = new HashMap<>();
+
+ /**
+ * Map from interprocess event name -> interprocess event class. Used for mapping the event
+ * name after receiving the broadcast, to the event type. After which a new instance is created
+ * and posted in the local process.
+ */
+ private HashMap<String, Class<? extends InterprocessEvent>> mInterprocessEventNameMap = new HashMap<>();
+
+ /**
+ * Set of all currently registered subscribers
+ */
+ private ArrayList<Subscriber> mSubscribers = new ArrayList<>();
+
+ // For tracing
+ private int mCallCount;
+ private long mCallDurationMicros;
+
+ /**
+ * Private constructor to create an event bus for a given looper.
+ */
+ private EventBus(Looper looper) {
+ mHandler = new Handler(looper);
+ }
+
+ /**
+ * @return the default event bus for the application's main thread.
+ */
+ public static EventBus getDefault() {
+ if (sDefaultBus == null)
+ synchronized (sLock) {
+ if (sDefaultBus == null) {
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("New EventBus");
+ }
+ sDefaultBus = new EventBus(Looper.getMainLooper());
+ }
+ }
+ return sDefaultBus;
+ }
+
+ /**
+ * Registers a subscriber to receive events with the default priority.
+ *
+ * @param subscriber the subscriber to handle events. If this is the first instance of the
+ * subscriber's class type that has been registered, the class's methods will
+ * be scanned for appropriate event handler methods.
+ */
+ public void register(Object subscriber) {
+ registerSubscriber(subscriber, DEFAULT_SUBSCRIBER_PRIORITY, null);
+ }
+
+ /**
+ * Registers a subscriber to receive events with the given priority.
+ *
+ * @param subscriber the subscriber to handle events. If this is the first instance of the
+ * subscriber's class type that has been registered, the class's methods will
+ * be scanned for appropriate event handler methods.
+ * @param priority the priority that this subscriber will receive events relative to other
+ * subscribers
+ */
+ public void register(Object subscriber, int priority) {
+ registerSubscriber(subscriber, priority, null);
+ }
+
+ /**
+ * Explicitly registers a subscriber to receive interprocess events with the default priority.
+ *
+ * @param subscriber the subscriber to handle events. If this is the first instance of the
+ * subscriber's class type that has been registered, the class's methods will
+ * be scanned for appropriate event handler methods.
+ */
+ public void registerInterprocessAsCurrentUser(Context context, Object subscriber) {
+ registerInterprocessAsCurrentUser(context, subscriber, DEFAULT_SUBSCRIBER_PRIORITY);
+ }
+
+ /**
+ * Registers a subscriber to receive interprocess events with the given priority.
+ *
+ * @param subscriber the subscriber to handle events. If this is the first instance of the
+ * subscriber's class type that has been registered, the class's methods will
+ * be scanned for appropriate event handler methods.
+ * @param priority the priority that this subscriber will receive events relative to other
+ * subscribers
+ */
+ public void registerInterprocessAsCurrentUser(Context context, Object subscriber, int priority) {
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("registerInterprocessAsCurrentUser(" + subscriber.getClass().getSimpleName() + ")");
+ }
+
+ // Register the subscriber normally, and update the broadcast receiver filter if this is
+ // a new subscriber type with interprocess events
+ MutableBoolean hasInterprocessEventsChanged = new MutableBoolean(false);
+ registerSubscriber(subscriber, priority, hasInterprocessEventsChanged);
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("hasInterprocessEventsChanged: " + hasInterprocessEventsChanged.value);
+ }
+ if (hasInterprocessEventsChanged.value) {
+ registerReceiverForInterprocessEvents(context);
+ }
+ }
+
+ /**
+ * Remove all EventHandlers pointing to the specified subscriber. This does not remove the
+ * mapping of subscriber type to event handler method, in case new instances of this subscriber
+ * are registered.
+ */
+ public void unregister(Object subscriber) {
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("unregister()");
+ }
+
+ // Fail immediately if we are being called from the non-main thread
+ long callingThreadId = Thread.currentThread().getId();
+ if (callingThreadId != mHandler.getLooper().getThread().getId()) {
+ throw new RuntimeException("Can not unregister() a subscriber from a non-main thread.");
+ }
+
+ // Return early if this is not a registered subscriber
+ if (!findRegisteredSubscriber(subscriber, true /* removeFoundSubscriber */)) {
+ return;
+ }
+
+ Class<?> subscriberType = subscriber.getClass();
+ ArrayList<EventHandlerMethod> subscriberMethods = mSubscriberTypeMap.get(subscriberType);
+ if (subscriberMethods != null) {
+ // For each of the event handlers the subscriber handles, remove all references of that
+ // handler
+ for (EventHandlerMethod method : subscriberMethods) {
+ ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(method.eventType);
+ for (int i = eventHandlers.size() - 1; i >= 0; i--) {
+ if (eventHandlers.get(i).subscriber.getReference() == subscriber) {
+ eventHandlers.remove(i);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Explicit unregistration for interprocess event subscribers. This actually behaves exactly
+ * the same as unregister() since we also do not want to stop listening for specific
+ * inter-process messages in case new instances of that subscriber is registered.
+ */
+ public void unregisterInterprocess(Context context, Object subscriber) {
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("unregisterInterprocess()");
+ }
+ unregister(subscriber);
+ }
+
+ /**
+ * Sends an event to the subscribers of the given event type immediately. This can only be
+ * called from the same thread as the EventBus's looper thread (for the default EventBus, this
+ * is the main application thread).
+ */
+ public void send(Event event) {
+ // Fail immediately if we are being called from the non-main thread
+ long callingThreadId = Thread.currentThread().getId();
+ if (callingThreadId != mHandler.getLooper().getThread().getId()) {
+ throw new RuntimeException("Can not send() a message from a non-main thread.");
+ }
+
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("send(" + event.getClass().getSimpleName() + ")");
+ }
+
+ // Reset the event's cancelled state
+ event.requiresPost = false;
+ event.cancelled = false;
+ queueEvent(event);
+ }
+
+ /**
+ * Post a message to the subscribers of the given event type. The messages will be posted on
+ * the EventBus's looper thread (for the default EventBus, this is the main application thread).
+ */
+ public void post(Event event) {
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("post(" + event.getClass().getSimpleName() + ")");
+ }
+
+ // Reset the event's cancelled state
+ event.requiresPost = true;
+ event.cancelled = false;
+ queueEvent(event);
+ }
+
+ /** Prevent post()ing an InterprocessEvent */
+ @Deprecated
+ public void post(InterprocessEvent event) {
+ throw new RuntimeException("Not supported, use postInterprocess");
+ }
+
+ /** Prevent send()ing an InterprocessEvent */
+ @Deprecated
+ public void send(InterprocessEvent event) {
+ throw new RuntimeException("Not supported, use postInterprocess");
+ }
+
+ /**
+ * Posts an interprocess event.
+ */
+ public void postInterprocess(Context context, final InterprocessEvent event) {
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("postInterprocess(" + event.getClass().getSimpleName() + ")");
+ }
+ String eventType = event.getClass().getName();
+ Bundle eventBundle = event.toBundle();
+ Intent intent = new Intent(eventType);
+ intent.setPackage(context.getPackageName());
+ intent.putExtra(EXTRA_INTERPROCESS_EVENT_BUNDLE, eventBundle);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+ Intent.FLAG_RECEIVER_FOREGROUND);
+ context.sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
+ /**
+ * Receiver for interprocess events.
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("onReceive(" + intent.getAction() + ", user " + UserHandle.myUserId() + ")");
+ }
+
+ Bundle eventBundle = intent.getBundleExtra(EXTRA_INTERPROCESS_EVENT_BUNDLE);
+ Class<? extends InterprocessEvent> eventType = mInterprocessEventNameMap.get(intent.getAction());
+ try {
+ Constructor<? extends InterprocessEvent> ctor = eventType.getConstructor(Bundle.class);
+ send((Event) ctor.newInstance(eventBundle));
+ } catch (NoSuchMethodException|
+ InvocationTargetException|
+ InstantiationException|
+ IllegalAccessException e) {
+ Log.e(TAG, "Failed to create InterprocessEvent", e);
+ }
+ }
+
+ /**
+ * @return a dump of the current state of the EventBus
+ */
+ public String dump() {
+ StringBuilder output = new StringBuilder();
+ output.append("Registered class types:");
+ output.append("\n");
+ for (Class<?> clz : mSubscriberTypeMap.keySet()) {
+ output.append("\t");
+ output.append(clz.getSimpleName());
+ output.append("\n");
+ }
+ output.append("Event map:");
+ output.append("\n");
+ for (Class<?> clz : mEventTypeMap.keySet()) {
+ output.append("\t");
+ output.append(clz.getSimpleName());
+ output.append(" -> ");
+ output.append("\n");
+ ArrayList<EventHandler> handlers = mEventTypeMap.get(clz);
+ for (EventHandler handler : handlers) {
+ Object subscriber = handler.subscriber.getReference();
+ if (subscriber != null) {
+ String id = Integer.toHexString(System.identityHashCode(subscriber));
+ output.append("\t\t");
+ output.append(subscriber.getClass().getSimpleName());
+ output.append(" [0x" + id + ", #" + handler.priority + "]");
+ output.append("\n");
+ }
+ }
+ }
+ return output.toString();
+ }
+
+ /**
+ * Registers a new subscriber.
+ *
+ * @return return whether or not this
+ */
+ private void registerSubscriber(Object subscriber, int priority,
+ MutableBoolean hasInterprocessEventsChangedOut) {
+ // Fail immediately if we are being called from the non-main thread
+ long callingThreadId = Thread.currentThread().getId();
+ if (callingThreadId != mHandler.getLooper().getThread().getId()) {
+ throw new RuntimeException("Can not register() a subscriber from a non-main thread.");
+ }
+
+ // Return immediately if this exact subscriber is already registered
+ if (findRegisteredSubscriber(subscriber, false /* removeFoundSubscriber */)) {
+ return;
+ }
+
+ long t1 = 0;
+ if (DEBUG_TRACE_ALL) {
+ t1 = SystemClock.currentTimeMicro();
+ logWithPid("registerSubscriber(" + subscriber.getClass().getSimpleName() + ")");
+ }
+ Subscriber sub = new Subscriber(subscriber, SystemClock.uptimeMillis());
+ Class<?> subscriberType = subscriber.getClass();
+ ArrayList<EventHandlerMethod> subscriberMethods = mSubscriberTypeMap.get(subscriberType);
+ if (subscriberMethods != null) {
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("Subscriber class type already registered");
+ }
+
+ // If we've parsed this subscriber type before, just add to the set for all the known
+ // events
+ for (EventHandlerMethod method : subscriberMethods) {
+ ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(method.eventType);
+ eventTypeHandlers.add(new EventHandler(sub, method, priority));
+ sortEventHandlersByPriority(eventTypeHandlers);
+ }
+ mSubscribers.add(sub);
+ return;
+ } else {
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("Subscriber class type requires registration");
+ }
+
+ // If we are parsing this type from scratch, ensure we add it to the subscriber type
+ // map, and pull out he handler methods below
+ subscriberMethods = new ArrayList<>();
+ mSubscriberTypeMap.put(subscriberType, subscriberMethods);
+ mSubscribers.add(sub);
+ }
+
+ // Find all the valid event bus handler methods of the subscriber
+ MutableBoolean isInterprocessEvent = new MutableBoolean(false);
+ Method[] methods = subscriberType.getMethods();
+ for (Method m : methods) {
+ Class<?>[] parameterTypes = m.getParameterTypes();
+ isInterprocessEvent.value = false;
+ if (isValidEventBusHandlerMethod(m, parameterTypes, isInterprocessEvent)) {
+ Class<? extends Event> eventType = (Class<? extends Event>) parameterTypes[0];
+ ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(eventType);
+ if (eventTypeHandlers == null) {
+ eventTypeHandlers = new ArrayList<>();
+ mEventTypeMap.put(eventType, eventTypeHandlers);
+ }
+ if (isInterprocessEvent.value) {
+ try {
+ // Enforce that the event must have a Bundle constructor
+ eventType.getConstructor(Bundle.class);
+
+ mInterprocessEventNameMap.put(eventType.getName(),
+ (Class<? extends InterprocessEvent>) eventType);
+ if (hasInterprocessEventsChangedOut != null) {
+ hasInterprocessEventsChangedOut.value = true;
+ }
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Expected InterprocessEvent to have a Bundle constructor");
+ }
+ }
+ EventHandlerMethod method = new EventHandlerMethod(m, eventType);
+ EventHandler handler = new EventHandler(sub, method, priority);
+ eventTypeHandlers.add(handler);
+ subscriberMethods.add(method);
+ sortEventHandlersByPriority(eventTypeHandlers);
+
+ if (DEBUG_TRACE_ALL) {
+ logWithPid(" * Method: " + m.getName() +
+ " event: " + parameterTypes[0].getSimpleName() +
+ " interprocess? " + isInterprocessEvent.value);
+ }
+ }
+ }
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("Registered " + subscriber.getClass().getSimpleName() + " in " +
+ (SystemClock.currentTimeMicro() - t1) + " microseconds");
+ }
+ }
+
+ /**
+ * Adds a new message.
+ */
+ private void queueEvent(final Event event) {
+ ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(event.getClass());
+ if (eventHandlers == null) {
+ return;
+ }
+ // We need to clone the list in case a subscriber unregisters itself during traversal
+ eventHandlers = (ArrayList<EventHandler>) eventHandlers.clone();
+ for (final EventHandler eventHandler : eventHandlers) {
+ if (eventHandler.subscriber.getReference() != null) {
+ if (event.requiresPost) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ processEvent(eventHandler, event);
+ }
+ });
+ } else {
+ processEvent(eventHandler, event);
+ }
+ }
+ }
+ }
+
+ /**
+ * Processes and dispatches the given event to the given event handler, on the thread of whoever
+ * calls this method.
+ */
+ private void processEvent(final EventHandler eventHandler, final Event event) {
+ // Skip if the event was already cancelled
+ if (event.cancelled) {
+ if (event.trace || DEBUG_TRACE_ALL) {
+ logWithPid("Event dispatch cancelled");
+ }
+ return;
+ }
+
+ try {
+ if (event.trace || DEBUG_TRACE_ALL) {
+ logWithPid(" -> " + eventHandler.toString());
+ }
+ Object sub = eventHandler.subscriber.getReference();
+ if (sub != null) {
+ long t1 = 0;
+ if (DEBUG_TRACE_ALL) {
+ t1 = SystemClock.currentTimeMicro();
+ }
+ eventHandler.method.invoke(sub, event);
+ if (DEBUG_TRACE_ALL) {
+ long duration = (SystemClock.currentTimeMicro() - t1);
+ mCallDurationMicros += duration;
+ mCallCount++;
+ logWithPid(eventHandler.method.toString() + " duration: " + duration +
+ " microseconds, avg: " + (mCallDurationMicros / mCallCount));
+ }
+ } else {
+ Log.e(TAG, "Failed to deliver event to null subscriber");
+ }
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "Failed to invoke method", e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e.getCause());
+ }
+ }
+
+ /**
+ * Re-registers the broadcast receiver for any new messages that we want to listen for.
+ */
+ private void registerReceiverForInterprocessEvents(Context context) {
+ if (DEBUG_TRACE_ALL) {
+ logWithPid("registerReceiverForInterprocessEvents()");
+ }
+ // Rebuild the receiver filter with the new interprocess events
+ IntentFilter filter = new IntentFilter();
+ for (String eventName : mInterprocessEventNameMap.keySet()) {
+ filter.addAction(eventName);
+ if (DEBUG_TRACE_ALL) {
+ logWithPid(" filter: " + eventName);
+ }
+ }
+ // Re-register the receiver with the new filter
+ if (mHasRegisteredReceiver) {
+ context.unregisterReceiver(this);
+ }
+ context.registerReceiverAsUser(this, UserHandle.ALL, filter, PERMISSION_SELF, mHandler);
+ mHasRegisteredReceiver = true;
+ }
+
+ /**
+ * Returns whether this subscriber is currently registered. If {@param removeFoundSubscriber}
+ * is true, then remove the subscriber before returning.
+ */
+ private boolean findRegisteredSubscriber(Object subscriber, boolean removeFoundSubscriber) {
+ for (int i = mSubscribers.size() - 1; i >= 0; i--) {
+ Subscriber sub = mSubscribers.get(i);
+ if (sub.getReference() == subscriber) {
+ if (removeFoundSubscriber) {
+ mSubscribers.remove(i);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return whether {@param method} is a valid (normal or interprocess) event bus handler method
+ */
+ private boolean isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes,
+ MutableBoolean isInterprocessEventOut) {
+ int modifiers = method.getModifiers();
+ if (Modifier.isPublic(modifiers) &&
+ Modifier.isFinal(modifiers) &&
+ method.getReturnType().equals(Void.TYPE) &&
+ parameterTypes.length == 1) {
+ if (EventBus.InterprocessEvent.class.isAssignableFrom(parameterTypes[0]) &&
+ method.getName().startsWith(INTERPROCESS_METHOD_PREFIX)) {
+ isInterprocessEventOut.value = true;
+ return true;
+ } else if (EventBus.Event.class.isAssignableFrom(parameterTypes[0]) &&
+ method.getName().startsWith(METHOD_PREFIX)) {
+ isInterprocessEventOut.value = false;
+ return true;
+ } else {
+ if (DEBUG_TRACE_ALL) {
+ if (!EventBus.Event.class.isAssignableFrom(parameterTypes[0])) {
+ logWithPid(" Expected method take an Event-based parameter: " + method.getName());
+ } else if (!method.getName().startsWith(INTERPROCESS_METHOD_PREFIX) &&
+ !method.getName().startsWith(METHOD_PREFIX)) {
+ logWithPid(" Expected method start with method prefix: " + method.getName());
+ }
+ }
+ }
+ } else {
+ if (DEBUG_TRACE_ALL) {
+ if (!Modifier.isPublic(modifiers)) {
+ logWithPid(" Expected method to be public: " + method.getName());
+ } else if (!Modifier.isFinal(modifiers)) {
+ logWithPid(" Expected method to be final: " + method.getName());
+ } else if (!method.getReturnType().equals(Void.TYPE)) {
+ logWithPid(" Expected method to return null: " + method.getName());
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Sorts the event handlers by priority and registration time.
+ */
+ private void sortEventHandlersByPriority(List<EventHandler> eventHandlers) {
+ Collections.sort(eventHandlers, EVENT_HANDLER_COMPARATOR);
+ }
+
+ /**
+ * Helper method to log the given {@param text} with the current process and user id.
+ */
+ private static void logWithPid(String text) {
+ Log.d(TAG, "[" + android.os.Process.myPid() + ", u" + UserHandle.myUserId() + "] " + text);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java
new file mode 100644
index 000000000000..52cfe18a9e26
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java
@@ -0,0 +1,28 @@
+/*
+ * 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.systemui.recents.events.activity;
+
+import com.android.systemui.recents.RecentsAppWidgetHost;
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent by the {@link RecentsAppWidgetHost} whenever the search provider widget changes, and
+ * subscribers can update accordingly.
+ */
+public class AppWidgetProviderChangedEvent extends EventBus.Event {
+ // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java
new file mode 100644
index 000000000000..3b68574c2830
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java
@@ -0,0 +1,39 @@
+/*
+ * 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.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.RecentsPackageMonitor;
+import com.android.systemui.recents.views.TaskStackView;
+
+/**
+ * This event is sent by {@link RecentsPackageMonitor} when a package on the the system changes.
+ * {@link TaskStackView}s listen for this event, and remove the tasks associated with the removed
+ * packages.
+ */
+public class PackagesChangedEvent extends EventBus.Event {
+
+ public final RecentsPackageMonitor monitor;
+ public final String packageName;
+ public final int userId;
+
+ public PackagesChangedEvent(RecentsPackageMonitor monitor, String packageName, int userId) {
+ this.monitor = monitor;
+ this.packageName = packageName;
+ this.userId = userId;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 5790ca63e4f2..b6d25f507cb9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -55,18 +55,18 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.util.MutableBoolean;
+import android.util.MutableFloat;
+import android.util.MutableInt;
import android.util.Pair;
-import android.util.SparseArray;
+import android.util.Size;
import android.view.Display;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
-
import com.android.internal.app.AssistUtils;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
import java.io.IOException;
import java.util.ArrayList;
@@ -282,6 +282,30 @@ public class SystemServicesProxy {
}
}
+ /**
+ * Resizes the given task to the new bounds.
+ */
+ public void resizeTask(int taskId, Rect bounds) {
+ if (mIam == null) return;
+
+ try {
+ mIam.resizeTask(taskId, bounds, ActivityManager.RESIZE_MODE_FORCED);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /** Docks a task to the side of the screen. */
+ public void dockTask(int taskId, int createMode) {
+ if (mIam == null) return;
+
+ try {
+ mIam.moveTaskToDockedStack(taskId, createMode, true);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
/** Returns the focused stack id. */
public int getFocusedStack() {
if (mIam == null) return -1;
@@ -637,7 +661,32 @@ public class SystemServicesProxy {
}
/**
- * Returns the window rect.
+ * Returns the smallest width/height.
+ */
+ public int getDeviceSmallestWidth() {
+ if (mWm == null) return 0;
+
+ Point smallestSizeRange = new Point();
+ Point largestSizeRange = new Point();
+ mWm.getDefaultDisplay().getCurrentSizeRange(smallestSizeRange, largestSizeRange);
+ return smallestSizeRange.x;
+ }
+
+ /**
+ * Returns the display rect.
+ */
+ public Rect getDisplayRect() {
+ Rect displayRect = new Rect();
+ if (mWm == null) return displayRect;
+
+ Point p = new Point();
+ mWm.getDefaultDisplay().getRealSize(p);
+ displayRect.set(0, 0, p.x, p.y);
+ return displayRect;
+ }
+
+ /**
+ * Returns the window rect for the RecentsActivity, based on the dimensions of the home stack.
*/
public Rect getWindowRect() {
Rect windowRect = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
index e48e5f053f5f..8f9a2935c3a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
@@ -21,6 +21,8 @@ import android.content.Context;
import android.os.Looper;
import android.os.UserHandle;
import com.android.internal.content.PackageMonitor;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.PackagesChangedEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import java.util.HashSet;
@@ -31,18 +33,9 @@ import java.util.List;
* Recents list.
*/
public class RecentsPackageMonitor extends PackageMonitor {
- public interface PackageCallbacks {
- public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName,
- int userId);
- }
-
- PackageCallbacks mCb;
- SystemServicesProxy mSystemServicesProxy;
/** Registers the broadcast receivers with the specified callbacks. */
- public void register(Context context, PackageCallbacks cb) {
- mSystemServicesProxy = new SystemServicesProxy(context);
- mCb = cb;
+ public void register(Context context) {
try {
// We register for events from all users, but will cross-reference them with
// packages for the current user and any profiles they have
@@ -60,17 +53,13 @@ public class RecentsPackageMonitor extends PackageMonitor {
} catch (IllegalStateException e) {
e.printStackTrace();
}
- mSystemServicesProxy = null;
- mCb = null;
}
@Override
public void onPackageRemoved(String packageName, int uid) {
- if (mCb == null) return;
-
// Notify callbacks that a package has changed
final int eventUserId = getChangingUserId();
- mCb.onPackagesChanged(this, packageName, eventUserId);
+ EventBus.getDefault().send(new PackagesChangedEvent(this, packageName, eventUserId));
}
@Override
@@ -81,11 +70,9 @@ public class RecentsPackageMonitor extends PackageMonitor {
@Override
public void onPackageModified(String packageName) {
- if (mCb == null) return;
-
// Notify callbacks that a package has changed
final int eventUserId = getChangingUserId();
- mCb.onPackagesChanged(this, packageName, eventUserId);
+ EventBus.getDefault().send(new PackagesChangedEvent(this, packageName, eventUserId));
}
/**
@@ -108,7 +95,8 @@ public class RecentsPackageMonitor extends PackageMonitor {
// If we know that the component still exists in the package, then skip
continue;
}
- if (mSystemServicesProxy.getActivityInfo(cn, userId) != null) {
+ SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+ if (ssp.getActivityInfo(cn, userId) != null) {
existingComponents.add(cn);
} else {
removedComponents.add(cn);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 649cb4db0fb1..6ef725306815 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -23,7 +23,6 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.util.Log;
-import android.util.SparseArray;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -76,7 +75,7 @@ public class RecentsTaskLoadPlan {
* An optimization to preload the raw list of tasks.
*/
public synchronized void preloadRawTasks(boolean isTopTaskHome) {
- mRawTasks = mSystemServicesProxy.getRecentTasks(mConfig.maxNumTasksToLoad,
+ mRawTasks = mSystemServicesProxy.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
UserHandle.CURRENT.getIdentifier(), isTopTaskHome);
Collections.reverse(mRawTasks);
@@ -125,7 +124,7 @@ public class RecentsTaskLoadPlan {
activityLabel, mSystemServicesProxy, res);
Drawable activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
mSystemServicesProxy, res, infoHandle, false);
- int activityColor = loader.getActivityPrimaryColor(t.taskDescription, mConfig);
+ int activityColor = loader.getActivityPrimaryColor(t.taskDescription, res);
// Update the activity info cache
if (!hadCachedActivityInfo && infoHandle.info != null) {
@@ -153,7 +152,7 @@ public class RecentsTaskLoadPlan {
// Initialize the stacks
mStack = new TaskStack();
mStack.setTasks(stackTasks);
- mStack.createAffiliatedGroupings(mConfig);
+ mStack.createAffiliatedGroupings(mContext);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index ad25c85860ed..39bef81386b4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -27,7 +27,6 @@ import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
-
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
@@ -248,7 +247,7 @@ class TaskResourceLoader implements Runnable {
}
/* Recents task loader
- * NOTE: We should not hold any references to a Context from a static instance */
+ * NOTE: We should not hold any references to non-application Context from a static instance */
public class RecentsTaskLoader {
private static final String TAG = "RecentsTaskLoader";
@@ -263,8 +262,6 @@ public class RecentsTaskLoader {
TaskResourceLoadQueue mLoadQueue;
TaskResourceLoader mLoader;
- RecentsPackageMonitor mPackageMonitor;
-
int mMaxThumbnailCacheSize;
int mMaxIconCacheSize;
int mNumVisibleTasksLoaded;
@@ -294,7 +291,6 @@ public class RecentsTaskLoader {
// Initialize the proxy, cache and loaders
mSystemServicesProxy = new SystemServicesProxy(context);
- mPackageMonitor = new RecentsPackageMonitor();
mLoadQueue = new TaskResourceLoadQueue();
mApplicationIconCache = new DrawableLruCache(iconCacheSize);
mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
@@ -438,12 +434,11 @@ public class RecentsTaskLoader {
}
/** Returns the activity's primary color. */
- public int getActivityPrimaryColor(ActivityManager.TaskDescription td,
- RecentsConfiguration config) {
+ public int getActivityPrimaryColor(ActivityManager.TaskDescription td, Resources res) {
if (td != null && td.getPrimaryColor() != 0) {
return td.getPrimaryColor();
}
- return config.taskBarViewDefaultBackgroundColor;
+ return res.getColor(R.color.recents_task_bar_default_background_color);
}
/** Returns the size of the app icon cache. */
@@ -521,17 +516,6 @@ public class RecentsTaskLoader {
mLoadQueue.clearTasks();
}
- /** Registers any broadcast receivers. */
- public void registerReceivers(Context context, RecentsPackageMonitor.PackageCallbacks cb) {
- // Register the broadcast receiver to handle messages related to packages being added/removed
- mPackageMonitor.register(context, cb);
- }
-
- /** Unregisters any broadcast receivers. */
- public void unregisterReceivers() {
- mPackageMonitor.unregister();
- }
-
/**
* Handles signals from the system, trimming memory when requested to prevent us from running
* out of memory.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 515e5784412a..20d9203ef71f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -16,11 +16,12 @@
package com.android.systemui.recents.model;
+import android.content.Context;
import android.graphics.Color;
import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.NamedCounter;
import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.R;
import java.util.ArrayList;
import java.util.Collections;
@@ -367,7 +368,7 @@ public class TaskStack {
/**
* Temporary: This method will simulate affiliation groups by
*/
- public void createAffiliatedGroupings(RecentsConfiguration config) {
+ public void createAffiliatedGroupings(Context context) {
if (Constants.DebugFlags.App.EnableSimulatedTaskGroups) {
HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>();
// Sort all tasks by increasing firstActiveTime of the task
@@ -452,7 +453,8 @@ public class TaskStack {
tasksMap.put(t.key, t);
}
// Update the task colors for each of the groups
- float minAlpha = config.taskBarViewAffiliationColorMinAlpha;
+ float minAlpha = context.getResources().getFloat(
+ R.dimen.recents_task_affiliation_color_min_alpha_percentage);
int taskGroupCount = mGroups.size();
for (int i = 0; i < taskGroupCount; i++) {
TaskGrouping group = mGroups.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
index 41adbed8fd3d..682fd8fe1724 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -89,7 +89,8 @@ class FakeShadowDrawable extends Drawable {
mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mCornerShadowPaint.setStyle(Paint.Style.FILL);
mCornerShadowPaint.setDither(true);
- mCornerRadius = config.taskViewRoundedCornerRadiusPx;
+ mCornerRadius = resources.getDimensionPixelSize(
+ R.dimen.recents_task_view_rounded_corners_radius);
mCardBounds = new RectF();
mEdgeShadowPaint = new Paint(mCornerShadowPaint);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index fab8b3a16bef..68faccc93c14 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -38,8 +38,9 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManagerGlobal;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.FrameLayout;
-
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
@@ -58,8 +59,7 @@ import java.util.List;
* This view is the the top level layout that contains TaskStacks (which are laid out according
* to their SpaceNode bounds.
*/
-public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks,
- RecentsPackageMonitor.PackageCallbacks {
+public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks {
private static final String TAG = "RecentsView";
@@ -83,6 +83,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
TaskStackView mTaskStackView;
RecentsAppWidgetHostView mSearchBar;
RecentsViewCallbacks mCb;
+ Interpolator mFastOutSlowInInterpolator;
+
+ Rect mSystemInsets = new Rect();
public RecentsView(Context context) {
super(context);
@@ -100,6 +103,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
super(context, attrs, defStyleAttr, defStyleRes);
mConfig = RecentsConfiguration.getInstance();
mInflater = LayoutInflater.from(context);
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
}
/** Sets the callbacks */
@@ -109,7 +114,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
/** Set/get the bsp root node */
public void setTaskStack(TaskStack stack) {
- if (mConfig.launchedReuseTaskStackViews) {
+ if (mConfig.getLaunchState().launchedReuseTaskStackViews) {
if (mTaskStackView != null) {
// If onRecentsHidden is not triggered, we need to the stack view again here
mTaskStackView.reset();
@@ -184,7 +189,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
for (int j = 0; j < taskViewCount; j++) {
TaskView tv = taskViews.get(j);
if (tv.getTask() == task) {
- onTaskViewClicked(mTaskStackView, tv, stack, task, false, true, taskBounds);
+ onTaskViewClicked(mTaskStackView, tv, stack, task, false, taskBounds != null,
+ taskBounds);
return true;
}
}
@@ -277,7 +283,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
// Get the search bar bounds and measure the search bar layout
Rect searchBarSpaceBounds = new Rect();
if (mSearchBar != null) {
- mConfig.getSearchBarBounds(new Rect(0, 0, width, height), mConfig.systemInsets.top,
+ mConfig.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top,
searchBarSpaceBounds);
mSearchBar.measure(
MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
@@ -285,8 +291,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
}
Rect taskStackBounds = new Rect();
- mConfig.getAvailableTaskStackBounds(new Rect(0, 0, width, height), mConfig.systemInsets.top,
- mConfig.systemInsets.right, searchBarSpaceBounds, taskStackBounds);
+ mConfig.getAvailableTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top,
+ mSystemInsets.right, searchBarSpaceBounds, taskStackBounds);
if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
mTaskStackView.setTaskStackBounds(taskStackBounds);
mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
@@ -305,7 +311,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
Rect searchBarSpaceBounds = new Rect();
if (mSearchBar != null) {
mConfig.getSearchBarBounds(measuredRect,
- mConfig.systemInsets.top, searchBarSpaceBounds);
+ mSystemInsets.top, searchBarSpaceBounds);
mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top,
searchBarSpaceBounds.right, searchBarSpaceBounds.bottom);
}
@@ -317,8 +323,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- // Update the configuration with the latest system insets and trigger a relayout
- mConfig.updateSystemInsets(insets.getSystemWindowInsets());
+ mSystemInsets.set(insets.getSystemWindowInsets());
requestLayout();
return insets.consumeSystemWindowInsets();
}
@@ -547,7 +552,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
// outside the display rect (to ensure we don't animate from too far away)
sourceView = stackView;
offsetX = transform.rect.left;
- offsetY = mConfig.displayRect.height();
+ offsetY = getMeasuredHeight();
} else {
sourceView = tv.mThumbnailView;
}
@@ -578,22 +583,15 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
}
postDrawHeaderThumbnailTransitionRunnable(stackView, tv, offsetX, offsetY, stackScroll,
animStartedListener);
- if (mConfig.multiWindowEnabled) {
- opts = ActivityOptions.makeCustomAnimation(sourceView.getContext(),
- R.anim.recents_from_unknown_enter,
- R.anim.recents_from_unknown_exit,
- sourceView.getHandler(), animStartedListener);
- } else {
- opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
- Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
- offsetX, offsetY, transform.rect.width(), transform.rect.height(),
- sourceView.getHandler(), animStartedListener);
- }
+ opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
+ Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
+ offsetX, offsetY, transform.rect.width(), transform.rect.height(),
+ sourceView.getHandler(), animStartedListener);
} else {
opts = ActivityOptions.makeBasic();
}
if (boundsValid) {
- opts.setBounds(bounds);
+ opts.setBounds(bounds.isEmpty() ? null : bounds);
}
final ActivityOptions launchOpts = opts;
final boolean screenPinningRequested = (animStartedListener == null) && lockToTask;
@@ -699,11 +697,13 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
public void onTaskStackFilterTriggered() {
// Hide the search bar
if (mSearchBar != null) {
+ int filterDuration = getResources().getInteger(
+ R.integer.recents_filter_animate_current_views_duration);
mSearchBar.animate()
.alpha(0f)
.setStartDelay(0)
- .setInterpolator(mConfig.fastOutSlowInInterpolator)
- .setDuration(mConfig.filteringCurrentViewsAnimDuration)
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .setDuration(filterDuration)
.withLayer()
.start();
}
@@ -713,11 +713,13 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
public void onTaskStackUnfilterTriggered() {
// Show the search bar
if (mSearchBar != null) {
+ int filterDuration = getResources().getInteger(
+ R.integer.recents_filter_animate_new_views_duration);
mSearchBar.animate()
.alpha(1f)
.setStartDelay(0)
- .setInterpolator(mConfig.fastOutSlowInInterpolator)
- .setDuration(mConfig.filteringNewViewsAnimDuration)
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .setDuration(filterDuration)
.withLayer()
.start();
}
@@ -729,14 +731,4 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
mCb.onTaskResize(t);
}
}
-
- /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
-
- @Override
- public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) {
- // Propagate this event down to each task stack view
- if (mTaskStackView != null) {
- mTaskStackView.onPackagesChanged(monitor, packageName, userId);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index 0428b48490d6..e04699c10fdd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -22,13 +22,15 @@ import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.TargetApi;
+import android.content.Context;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
-import com.android.systemui.recents.RecentsConfiguration;
/**
* This class facilitates swipe to dismiss. It defines an interface to be implemented by the
@@ -46,6 +48,7 @@ public class SwipeHelper {
public static final int Y = 1;
private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
+ private Interpolator mLinearOutSlowInInterpolator;
private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
private int DEFAULT_ESCAPE_ANIMATION_DURATION = 75; // ms
@@ -74,13 +77,15 @@ public class SwipeHelper {
public boolean mAllowSwipeTowardsEnd = true;
private boolean mRtl;
- public SwipeHelper(int swipeDirection, Callback callback, float densityScale,
+ public SwipeHelper(Context context, int swipeDirection, Callback callback, float densityScale,
float pagingTouchSlop) {
mCallback = callback;
mSwipeDirection = swipeDirection;
mVelocityTracker = VelocityTracker.obtain();
mDensityScale = densityScale;
mPagingTouchSlop = pagingTouchSlop;
+ mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.linear_out_slow_in);
}
public void setDensityScale(float densityScale) {
@@ -265,7 +270,7 @@ public class SwipeHelper {
ValueAnimator anim = createTranslationAnimation(view, 0);
int duration = SNAP_ANIM_LEN;
anim.setDuration(duration);
- anim.setInterpolator(RecentsConfiguration.getInstance().linearOutSlowInInterpolator);
+ anim.setInterpolator(mLinearOutSlowInInterpolator);
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 1086160e07e7..7ce50d803ee2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -17,13 +17,19 @@
package com.android.systemui.recents.views;
import android.app.Activity;
+import android.content.Context;
import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.systemui.R;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
/** Manages the scrims for the various system bars. */
public class SystemBarScrimViews {
+ Context mContext;
RecentsConfiguration mConfig;
View mStatusBarScrimView;
@@ -34,10 +40,22 @@ public class SystemBarScrimViews {
boolean mHasStatusBarScrim;
boolean mShouldAnimateNavBarScrim;
- public SystemBarScrimViews(Activity activity, RecentsConfiguration config) {
- mConfig = config;
+ int mNavBarScrimEnterDuration;
+
+ Interpolator mFastOutSlowInInterpolator;
+ Interpolator mQuintOutInterpolator;
+
+ public SystemBarScrimViews(Activity activity) {
+ mContext = activity;
+ mConfig = RecentsConfiguration.getInstance();
mStatusBarScrimView = activity.findViewById(R.id.status_bar_scrim);
mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
+ mNavBarScrimEnterDuration = activity.getResources().getInteger(
+ R.integer.recents_nav_bar_scrim_enter_duration);
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(activity,
+ com.android.internal.R.interpolator.fast_out_slow_in);
+ mQuintOutInterpolator = AnimationUtils.loadInterpolator(activity,
+ com.android.internal.R.interpolator.decelerate_quint);
}
/**
@@ -45,10 +63,11 @@ public class SystemBarScrimViews {
* the first draw.
*/
public void prepareEnterRecentsAnimation() {
- mHasNavBarScrim = mConfig.hasNavBarScrim();
- mShouldAnimateNavBarScrim = mConfig.shouldAnimateNavBarScrim();
- mHasStatusBarScrim = mConfig.hasStatusBarScrim();
- mShouldAnimateStatusBarScrim = mConfig.shouldAnimateStatusBarScrim();
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+ mHasNavBarScrim = launchState.hasNavBarScrim();
+ mShouldAnimateNavBarScrim = launchState.shouldAnimateNavBarScrim();
+ mHasStatusBarScrim = launchState.hasStatusBarScrim();
+ mShouldAnimateStatusBarScrim = launchState.shouldAnimateStatusBarScrim();
mNavBarScrimView.setVisibility(mHasNavBarScrim && !mShouldAnimateNavBarScrim ?
View.VISIBLE : View.INVISIBLE);
@@ -60,15 +79,21 @@ public class SystemBarScrimViews {
* Starts animating the scrim views when entering Recents.
*/
public void startEnterRecentsAnimation() {
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+ int transitionEnterFromAppDelay = mContext.getResources().getInteger(
+ R.integer.recents_enter_from_app_transition_duration);
+ int transitionEnterFromHomeDelay = mContext.getResources().getInteger(
+ R.integer.recents_enter_from_home_transition_duration);
+
if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight());
mStatusBarScrimView.animate()
.translationY(0)
- .setStartDelay(mConfig.launchedFromHome ?
- mConfig.transitionEnterFromHomeDelay :
- mConfig.transitionEnterFromAppDelay)
- .setDuration(mConfig.navBarScrimEnterDuration)
- .setInterpolator(mConfig.quintOutInterpolator)
+ .setStartDelay(launchState.launchedFromHome ?
+ transitionEnterFromHomeDelay :
+ transitionEnterFromAppDelay)
+ .setDuration(mNavBarScrimEnterDuration)
+ .setInterpolator(mQuintOutInterpolator)
.withStartAction(new Runnable() {
@Override
public void run() {
@@ -81,11 +106,11 @@ public class SystemBarScrimViews {
mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
mNavBarScrimView.animate()
.translationY(0)
- .setStartDelay(mConfig.launchedFromHome ?
- mConfig.transitionEnterFromHomeDelay :
- mConfig.transitionEnterFromAppDelay)
- .setDuration(mConfig.navBarScrimEnterDuration)
- .setInterpolator(mConfig.quintOutInterpolator)
+ .setStartDelay(launchState.launchedFromHome ?
+ transitionEnterFromHomeDelay :
+ transitionEnterFromAppDelay)
+ .setDuration(mNavBarScrimEnterDuration)
+ .setInterpolator(mQuintOutInterpolator)
.withStartAction(new Runnable() {
@Override
public void run() {
@@ -101,20 +126,22 @@ public class SystemBarScrimViews {
* going home).
*/
public void startExitRecentsAnimation() {
+ int taskViewExitToAppDuration = mContext.getResources().getInteger(
+ R.integer.recents_task_exit_to_app_duration);
if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
mStatusBarScrimView.animate()
.translationY(-mStatusBarScrimView.getMeasuredHeight())
.setStartDelay(0)
- .setDuration(mConfig.taskViewExitToAppDuration)
- .setInterpolator(mConfig.fastOutSlowInInterpolator)
+ .setDuration(taskViewExitToAppDuration)
+ .setInterpolator(mFastOutSlowInInterpolator)
.start();
}
if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
mNavBarScrimView.animate()
.translationY(mNavBarScrimView.getMeasuredHeight())
.setStartDelay(0)
- .setDuration(mConfig.taskViewExitToAppDuration)
- .setInterpolator(mConfig.fastOutSlowInInterpolator)
+ .setDuration(taskViewExitToAppDuration)
+ .setInterpolator(mFastOutSlowInInterpolator)
.start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 4db8b3708bf3..76b091cfc28b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -29,15 +29,17 @@ import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
-
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.PackagesChangedEvent;
import com.android.systemui.recents.misc.DozeTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.RecentsPackageMonitor;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
@@ -54,7 +56,7 @@ import java.util.List;
/* The visual representation of a task stack view */
public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks,
TaskView.TaskViewCallbacks, TaskStackViewScroller.TaskStackViewScrollerCallbacks,
- ViewPool.ViewPoolConsumer<TaskView, Task>, RecentsPackageMonitor.PackageCallbacks {
+ ViewPool.ViewPoolConsumer<TaskView, Task> {
/** The TaskView callbacks */
interface TaskStackViewCallbacks {
@@ -77,7 +79,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
TaskStackViewTouchHandler mTouchHandler;
TaskStackViewCallbacks mCb;
ViewPool<TaskView, Task> mViewPool;
- ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<TaskViewTransform>();
+ ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
DozeTrigger mUIDozeTrigger;
DismissView mDismissAllButton;
boolean mDismissAllButtonAnimating;
@@ -97,9 +99,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
Matrix mTmpMatrix = new Matrix();
Rect mTmpRect = new Rect();
TaskViewTransform mTmpTransform = new TaskViewTransform();
- HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<Task, TaskView>();
- ArrayList<TaskView> mTaskViews = new ArrayList<TaskView>();
- List<TaskView> mImmutableTaskViews = new ArrayList<TaskView>();
+ HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<>();
+ ArrayList<TaskView> mTaskViews = new ArrayList<>();
+ List<TaskView> mImmutableTaskViews = new ArrayList<>();
LayoutInflater mInflater;
boolean mLayersDisabled;
@@ -117,14 +119,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Set the stack first
setStack(stack);
mConfig = RecentsConfiguration.getInstance();
- mViewPool = new ViewPool<TaskView, Task>(context, this);
+ mViewPool = new ViewPool<>(context, this);
mInflater = LayoutInflater.from(context);
- mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(mConfig);
- mFilterAlgorithm = new TaskStackViewFilterAlgorithm(mConfig, this, mViewPool);
- mStackScroller = new TaskStackViewScroller(context, mConfig, mLayoutAlgorithm);
+ mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(context, mConfig);
+ mFilterAlgorithm = new TaskStackViewFilterAlgorithm(this, mViewPool);
+ mStackScroller = new TaskStackViewScroller(context, mLayoutAlgorithm);
mStackScroller.setCallbacks(this);
- mTouchHandler = new TaskStackViewTouchHandler(context, this, mConfig, mStackScroller);
- mUIDozeTrigger = new DozeTrigger(mConfig.taskBarDismissDozeDelaySeconds, new Runnable() {
+ mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
+
+ int taskBarDismissDozeDelaySeconds = getResources().getInteger(
+ R.integer.recents_task_bar_dismiss_delay_seconds);
+ mUIDozeTrigger = new DozeTrigger(taskBarDismissDozeDelaySeconds, new Runnable() {
@Override
public void run() {
// Show the task bar dismiss buttons
@@ -144,6 +149,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mCb = cb;
}
+ @Override
+ protected void onAttachedToWindow() {
+ EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ EventBus.getDefault().unregister(this);
+ }
+
/** Sets the task stack */
void setStack(TaskStack stack) {
// Set the new stack
@@ -731,8 +748,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
int height = MeasureSpec.getSize(heightMeasureSpec);
// Compute our stack/task rects
- computeRects(width, height, mTaskStackBounds, mConfig.launchedWithAltTab,
- mConfig.launchedFromHome);
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+ computeRects(width, height, mTaskStackBounds, launchState.launchedWithAltTab,
+ launchState.launchedFromHome);
// If this is the first layout, then scroll to the front of the stack and synchronize the
// stack views immediately to load all the views
@@ -764,9 +782,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Measure the dismiss button
if (mDismissAllButton != null) {
int taskRectWidth = mLayoutAlgorithm.mTaskRect.width();
+ int dismissAllButtonHeight = getResources().getDimensionPixelSize(
+ R.dimen.recents_dismiss_all_button_size);
mDismissAllButton.measure(
MeasureSpec.makeMeasureSpec(taskRectWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(mConfig.dismissAllButtonSizePx, MeasureSpec.EXACTLY));
+ MeasureSpec.makeMeasureSpec(dismissAllButtonHeight, MeasureSpec.EXACTLY));
}
setMeasuredDimension(width, height);
@@ -847,20 +867,19 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// When Alt-Tabbing, focus the previous task (but leave the animation until we finish the
// enter animation).
- if (mConfig.launchedWithAltTab) {
- if (mConfig.launchedFromAppWithThumbnail) {
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+ if (launchState.launchedWithAltTab) {
+ if (launchState.launchedFromAppWithThumbnail) {
focusTask(Math.max(0, mStack.getTaskCount() - 2), false,
- mConfig.launchedHasConfigurationChanged);
+ launchState.launchedHasConfigurationChanged);
} else {
focusTask(Math.max(0, mStack.getTaskCount() - 1), false,
- mConfig.launchedHasConfigurationChanged);
+ launchState.launchedHasConfigurationChanged);
}
}
// Start dozing
- if (!mConfig.multiWindowEnabled) {
- mUIDozeTrigger.startDozing();
- }
+ mUIDozeTrigger.startDozing();
}
/** Requests this task stacks to start it's enter-recents animation */
@@ -924,7 +943,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Start the focus animation when alt-tabbing
ArrayList<Task> tasks = mStack.getTasks();
- if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged &&
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+ if (launchState.launchedWithAltTab &&
+ !launchState.launchedHasConfigurationChanged &&
0 <= mFocusedTaskIndex && mFocusedTaskIndex < tasks.size()) {
TaskView tv = getChildViewForTask(tasks.get(mFocusedTaskIndex));
if (tv != null) {
@@ -1115,7 +1136,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
// Update the min/max scroll and animate other task views into their new positions
- updateMinMaxScroll(true, mConfig.launchedWithAltTab, mConfig.launchedFromHome);
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+ updateMinMaxScroll(true, launchState.launchedWithAltTab, launchState.launchedFromHome);
// Offset the stack by as much as the anchor task would otherwise move back
if (pullStackForward) {
@@ -1133,7 +1155,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
TaskView frontTv = getChildViewForTask(newFrontMostTask);
if (frontTv != null) {
frontTv.onTaskBound(newFrontMostTask);
- frontTv.fadeInActionButton(0, mConfig.taskViewEnterFromAppDuration);
+ frontTv.fadeInActionButton(0, getResources().getInteger(
+ R.integer.recents_task_enter_from_app_duration));
}
}
@@ -1282,7 +1305,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
RecentsTaskLoader.getInstance().loadTaskData(task);
// If the doze trigger has already fired, then update the state for this task view
- if (mConfig.multiWindowEnabled || mUIDozeTrigger.hasTriggered()) {
+ if (mUIDozeTrigger.hasTriggered()) {
tv.setNoUserInteractionState();
}
@@ -1384,7 +1407,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
if (nextTv != null) {
// Focus the next task, and only animate the visible state if we are launched
// from Alt-Tab
- nextTv.setFocusedTask(mConfig.launchedWithAltTab);
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+ nextTv.setFocusedTask(launchState.launchedWithAltTab);
}
}
}
@@ -1420,13 +1444,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
postInvalidateOnAnimation();
}
- /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
+ /**** EventBus Events ****/
- @Override
- public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) {
+ public final void onBusEvent(PackagesChangedEvent event) {
// Compute which components need to be removed
- HashSet<ComponentName> removedComponents = monitor.computeComponentsRemoved(
- mStack.getTaskKeys(), packageName, userId);
+ HashSet<ComponentName> removedComponents = event.monitor.computeComponentsRemoved(
+ mStack.getTaskKeys(), event.packageName, event.userId);
// For other tasks, just remove them directly if they no longer exist
ArrayList<Task> tasks = mStack.getTasks();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
index 614ca53983ed..e9f6a46c9707 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
@@ -17,8 +17,8 @@
package com.android.systemui.recents.views;
import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.model.Task;
+import com.android.systemui.R;
import java.util.ArrayList;
import java.util.HashMap;
@@ -27,13 +27,10 @@ import java.util.List;
/* The layout logic for a TaskStackView */
public class TaskStackViewFilterAlgorithm {
- RecentsConfiguration mConfig;
TaskStackView mStackView;
ViewPool<TaskView, Task> mViewPool;
- public TaskStackViewFilterAlgorithm(RecentsConfiguration config, TaskStackView stackView,
- ViewPool<TaskView, Task> viewPool) {
- mConfig = config;
+ public TaskStackViewFilterAlgorithm(TaskStackView stackView, ViewPool<TaskView, Task> viewPool) {
mStackView = stackView;
mViewPool = viewPool;
}
@@ -126,7 +123,8 @@ public class TaskStackViewFilterAlgorithm {
}
}
}
- return mConfig.filteringNewViewsAnimDuration;
+ return mStackView.getResources().getInteger(
+ R.integer.recents_filter_animate_new_views_duration);
}
/**
@@ -172,7 +170,8 @@ public class TaskStackViewFilterAlgorithm {
childViewTransformsOut.put(tv, toTransform);
offset++;
}
- return mConfig.filteringCurrentViewsAnimDuration;
+ return mStackView.getResources().getInteger(
+ R.integer.recents_filter_animate_current_views_duration);
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index f6df881121d7..7f4c0a5f7cb4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -16,11 +16,13 @@
package com.android.systemui.recents.views;
+import android.content.Context;
import android.graphics.Rect;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
+import com.android.systemui.R;
import java.util.ArrayList;
import java.util.HashMap;
@@ -48,6 +50,7 @@ public class TaskStackViewLayoutAlgorithm {
}
}
+ Context mContext;
RecentsConfiguration mConfig;
// The various rects that define the stack view
@@ -71,7 +74,8 @@ public class TaskStackViewLayoutAlgorithm {
static float[] xp;
static float[] px;
- public TaskStackViewLayoutAlgorithm(RecentsConfiguration config) {
+ public TaskStackViewLayoutAlgorithm(Context context, RecentsConfiguration config) {
+ mContext = context;
mConfig = config;
// Precompute the path
@@ -87,7 +91,8 @@ public class TaskStackViewLayoutAlgorithm {
mStackVisibleRect.bottom = mViewRect.bottom;
int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * mStackRect.width());
- int heightPadding = mConfig.taskStackTopPaddingPx;
+ int heightPadding = mContext.getResources().getDimensionPixelSize(
+ R.dimen.recents_stack_top_padding);
mStackRect.inset(widthPadding, heightPadding);
// Compute the task rect
@@ -98,7 +103,8 @@ public class TaskStackViewLayoutAlgorithm {
// Update the affiliation offsets
float visibleTaskPct = 0.5f;
- mWithinAffiliationOffset = mConfig.taskBarHeight;
+ mWithinAffiliationOffset = mContext.getResources().getDimensionPixelSize(
+ R.dimen.recents_task_bar_height);
mBetweenAffiliationOffset = (int) (visibleTaskPct * mTaskRect.height());
}
@@ -134,8 +140,10 @@ public class TaskStackViewLayoutAlgorithm {
mStackRect.bottom));
float pDismissAllButtonOffset = 0f;
if (Constants.DebugFlags.App.EnableDismissAll) {
+ int dismissAllButtonHeight = mContext.getResources().getDimensionPixelSize(
+ R.dimen.recents_dismiss_all_button_size);
pDismissAllButtonOffset = pAtBottomOfStackRect -
- screenYToCurveProgress(mStackVisibleRect.bottom - mConfig.dismissAllButtonSizePx);
+ screenYToCurveProgress(mStackVisibleRect.bottom - dismissAllButtonHeight);
}
// Update the task offsets
@@ -177,6 +185,8 @@ public class TaskStackViewLayoutAlgorithm {
// Walk backwards in the task stack and count the number of tasks and visible thumbnails
int taskHeight = mTaskRect.height();
+ int taskBarHeight = mContext.getResources().getDimensionPixelSize(
+ R.dimen.recents_task_bar_height);
int numVisibleTasks = 1;
int numVisibleThumbnails = 1;
float progress = mTaskProgressMap.get(tasks.get(tasks.size() - 1).key) - mInitialScrollP;
@@ -192,7 +202,7 @@ public class TaskStackViewLayoutAlgorithm {
float scaleAtP = curveProgressToScale(progress);
int scaleYOffsetAtP = (int) (((1f - scaleAtP) * taskHeight) / 2);
int screenY = curveProgressToScreenY(progress) + scaleYOffsetAtP;
- boolean hasVisibleThumbnail = (prevScreenY - screenY) > mConfig.taskBarHeight;
+ boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
if (hasVisibleThumbnail) {
numVisibleThumbnails++;
numVisibleTasks++;
@@ -251,8 +261,8 @@ public class TaskStackViewLayoutAlgorithm {
}
float scale = curveProgressToScale(pBounded);
int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2);
- int minZ = mConfig.taskViewTranslationZMinPx;
- int maxZ = mConfig.taskViewTranslationZMaxPx;
+ int minZ = mContext.getResources().getDimensionPixelSize(R.dimen.recents_task_view_z_min);
+ int maxZ = mContext.getResources().getDimensionPixelSize(R.dimen.recents_task_view_z_max);
transformOut.scale = scale;
transformOut.translationY = curveProgressToScreenY(pBounded) - mStackVisibleRect.top -
scaleYOffset;
@@ -265,11 +275,9 @@ public class TaskStackViewLayoutAlgorithm {
return transformOut;
}
- /** Returns the untransformed task view size. */
- public Rect getUntransformedTaskViewSize() {
- Rect tvSize = new Rect(mTaskRect);
- tvSize.offsetTo(0, 0);
- return tvSize;
+ /** Returns the untransformed task view bounds. */
+ public Rect getUntransformedTaskViewBounds() {
+ return new Rect(mTaskRect);
}
/** Returns the scroll to such task top = 1f; */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index fabc86d7e53a..f0ae87f6f9ae 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -21,9 +21,11 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.OverScroller;
-import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.R;
/* The scrolling logic for a TaskStackView */
public class TaskStackViewScroller {
@@ -31,7 +33,7 @@ public class TaskStackViewScroller {
public void onScrollChanged(float p);
}
- RecentsConfiguration mConfig;
+ Context mContext;
TaskStackViewLayoutAlgorithm mLayoutAlgorithm;
TaskStackViewScrollerCallbacks mCb;
@@ -41,10 +43,14 @@ public class TaskStackViewScroller {
ObjectAnimator mScrollAnimator;
float mFinalAnimatedScroll;
- public TaskStackViewScroller(Context context, RecentsConfiguration config, TaskStackViewLayoutAlgorithm layoutAlgorithm) {
- mConfig = config;
+ Interpolator mLinearOutSlowInInterpolator;
+
+ public TaskStackViewScroller(Context context, TaskStackViewLayoutAlgorithm layoutAlgorithm) {
+ mContext = context;
mScroller = new OverScroller(context);
mLayoutAlgorithm = layoutAlgorithm;
+ mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.linear_out_slow_in);
setStackScroll(getStackScroll());
}
@@ -140,8 +146,9 @@ public class TaskStackViewScroller {
mFinalAnimatedScroll = newScroll;
mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll);
- mScrollAnimator.setDuration(mConfig.taskStackScrollDuration);
- mScrollAnimator.setInterpolator(mConfig.linearOutSlowInInterpolator);
+ mScrollAnimator.setDuration(mContext.getResources().getInteger(
+ R.integer.recents_animate_task_stack_scroll_duration));
+ mScrollAnimator.setInterpolator(mLinearOutSlowInInterpolator);
mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 7d079d90fee5..86eced8a763d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -26,7 +26,7 @@ import android.view.ViewParent;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.R;
import java.util.List;
@@ -34,7 +34,7 @@ import java.util.List;
class TaskStackViewTouchHandler implements SwipeHelper.Callback {
static int INACTIVE_POINTER_ID = -1;
- RecentsConfiguration mConfig;
+ Context mContext;
TaskStackView mSv;
TaskStackViewScroller mScroller;
VelocityTracker mVelocityTracker;
@@ -62,7 +62,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
boolean mInterceptedBySwipeHelper;
public TaskStackViewTouchHandler(Context context, TaskStackView sv,
- RecentsConfiguration config, TaskStackViewScroller scroller) {
+ TaskStackViewScroller scroller) {
+ mContext = context;
ViewConfiguration configuration = ViewConfiguration.get(context);
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
@@ -71,10 +72,9 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
mSv = sv;
mScroller = scroller;
- mConfig = config;
float densityScale = context.getResources().getDisplayMetrics().density;
- mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, mPagingTouchSlop);
+ mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale, mPagingTouchSlop);
mSwipeHelper.setMinAlpha(1f);
}
@@ -268,7 +268,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
if (Float.compare(overScrollAmount, 0f) != 0) {
// Bound the overscroll to a fixed amount, and inversely scale the y-movement
// relative to how close we are to the max overscroll
- float maxOverScroll = mConfig.taskStackOverscrollPct;
+ float maxOverScroll = mContext.getResources().getFloat(
+ R.dimen.recents_stack_overscroll_percentage);
deltaP *= (1f - (Math.min(maxOverScroll, overScrollAmount)
/ maxOverScroll));
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 373fe7b60fd6..bbbaccf3fa5f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -20,16 +20,25 @@ import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.*;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityManager;
import android.view.View;
import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
@@ -75,6 +84,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
View mActionButtonView;
TaskViewCallbacks mCb;
+ Interpolator mFastOutSlowInInterpolator;
+ Interpolator mFastOutLinearInInterpolator;
+ Interpolator mQuintOutInterpolator;
+
// Optimizations
ValueAnimator.AnimatorUpdateListener mUpdateDimListener =
new ValueAnimator.AnimatorUpdateListener() {
@@ -99,14 +112,22 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ Resources res = context.getResources();
mConfig = RecentsConfiguration.getInstance();
- mMaxDimScale = mConfig.taskStackMaxDim / 255f;
+ mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
mClipViewInStack = true;
- mViewBounds = new AnimateableViewBounds(this, mConfig.taskViewRoundedCornerRadiusPx);
+ mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
+ R.dimen.recents_task_view_rounded_corners_radius));
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
+ mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_linear_in);
+ mQuintOutInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.decelerate_quint);
setTaskProgress(getTaskProgress());
setDim(getDim());
if (mConfig.fakeShadows) {
- setBackground(new FakeShadowDrawable(context.getResources(), mConfig));
+ setBackground(new FakeShadowDrawable(res, mConfig));
}
setOutlineProvider(mViewBounds);
}
@@ -159,6 +180,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
int widthWithoutPadding = width - mPaddingLeft - mPaddingRight;
int heightWithoutPadding = height - mPaddingTop - mPaddingBottom;
+ int taskBarHeight = getResources().getDimensionPixelSize(R.dimen.recents_task_bar_height);
// Measure the content
mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
@@ -166,7 +188,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
// Measure the bar view, and action button
mHeaderView.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(mConfig.taskBarHeight, MeasureSpec.EXACTLY));
+ MeasureSpec.makeMeasureSpec(taskBarHeight, MeasureSpec.EXACTLY));
mActionButtonView.measure(
MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.AT_MOST));
@@ -186,7 +208,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration,
ValueAnimator.AnimatorUpdateListener updateCallback) {
// Apply the transform
- toTransform.applyToTaskView(this, duration, mConfig.fastOutSlowInInterpolator, false,
+ toTransform.applyToTaskView(this, duration, mFastOutSlowInInterpolator, false,
!mConfig.fakeShadows, updateCallback);
// Update the task progress
@@ -238,10 +260,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
* first layout because the actual animation into recents may take a long time. */
void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask,
boolean occludesLaunchTarget, int offscreenY) {
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
int initialDim = getDim();
- if (mConfig.launchedHasConfigurationChanged) {
+ if (launchState.launchedHasConfigurationChanged) {
// Just load the views as-is
- } else if (mConfig.launchedFromAppWithThumbnail) {
+ } else if (launchState.launchedFromAppWithThumbnail) {
if (isTaskViewLaunchTargetTask) {
// Set the dim to 0 so we can animate it in
initialDim = 0;
@@ -252,7 +275,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
setTranslationY(offscreenY);
}
- } else if (mConfig.launchedFromHome) {
+ } else if (launchState.launchedFromHome) {
// Move the task view off screen (below) so we can animate it in
setTranslationY(offscreenY);
setTranslationZ(0);
@@ -267,45 +290,59 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
/** Animates this task view as it enters recents */
void startEnterRecentsAnimation(final ViewAnimation.TaskViewEnterContext ctx) {
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+ Resources res = mContext.getResources();
final TaskViewTransform transform = ctx.currentTaskTransform;
+ final int transitionEnterFromAppDelay = res.getInteger(
+ R.integer.recents_enter_from_app_transition_duration);
+ final int transitionEnterFromHomeDelay = res.getInteger(
+ R.integer.recents_enter_from_home_transition_duration);
+ final int taskViewEnterFromAppDuration = res.getInteger(
+ R.integer.recents_task_enter_from_app_duration);
+ final int taskViewEnterFromHomeDuration = res.getInteger(
+ R.integer.recents_task_enter_from_home_duration);
+ final int taskViewEnterFromHomeStaggerDelay = res.getInteger(
+ R.integer.recents_task_enter_from_home_stagger_delay);
+ final int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
+ R.dimen.recents_task_view_affiliate_group_enter_offset);
int startDelay = 0;
- if (mConfig.launchedFromAppWithThumbnail) {
+ if (launchState.launchedFromAppWithThumbnail) {
if (mTask.isLaunchTarget) {
// Animate the dim/overlay
if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) {
// Animate the thumbnail alpha before the dim animation (to prevent updating the
// hardware layer)
- mThumbnailView.startEnterRecentsAnimation(mConfig.transitionEnterFromAppDelay,
+ mThumbnailView.startEnterRecentsAnimation(transitionEnterFromAppDelay,
new Runnable() {
@Override
public void run() {
- animateDimToProgress(0, mConfig.taskViewEnterFromAppDuration,
+ animateDimToProgress(0, taskViewEnterFromAppDuration,
ctx.postAnimationTrigger.decrementOnAnimationEnd());
}
});
} else {
// Immediately start the dim animation
- animateDimToProgress(mConfig.transitionEnterFromAppDelay,
- mConfig.taskViewEnterFromAppDuration,
+ animateDimToProgress(transitionEnterFromAppDelay,
+ taskViewEnterFromAppDuration,
ctx.postAnimationTrigger.decrementOnAnimationEnd());
}
ctx.postAnimationTrigger.increment();
// Animate the action button in
- fadeInActionButton(mConfig.transitionEnterFromAppDelay,
- mConfig.taskViewEnterFromAppDuration);
+ fadeInActionButton(transitionEnterFromAppDelay,
+ taskViewEnterFromAppDuration);
} else {
// Animate the task up if it was occluding the launch target
if (ctx.currentTaskOccludesLaunchTarget) {
- setTranslationY(transform.translationY + mConfig.taskViewAffiliateGroupEnterOffsetPx);
+ setTranslationY(transform.translationY + taskViewAffiliateGroupEnterOffset);
setAlpha(0f);
animate().alpha(1f)
.translationY(transform.translationY)
- .setStartDelay(mConfig.transitionEnterFromAppDelay)
+ .setStartDelay(transitionEnterFromAppDelay)
.setUpdateListener(null)
- .setInterpolator(mConfig.fastOutSlowInInterpolator)
- .setDuration(mConfig.taskViewEnterFromHomeDuration)
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .setDuration(taskViewEnterFromHomeDuration)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -317,13 +354,13 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
ctx.postAnimationTrigger.increment();
}
}
- startDelay = mConfig.transitionEnterFromAppDelay;
+ startDelay = transitionEnterFromAppDelay;
- } else if (mConfig.launchedFromHome) {
+ } else if (launchState.launchedFromHome) {
// Animate the tasks up
int frontIndex = (ctx.currentStackViewCount - ctx.currentStackViewIndex - 1);
- int delay = mConfig.transitionEnterFromHomeDelay +
- frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay;
+ int delay = transitionEnterFromHomeDelay +
+ frontIndex * taskViewEnterFromHomeStaggerDelay;
setScaleX(transform.scale);
setScaleY(transform.scale);
@@ -334,9 +371,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
.translationY(transform.translationY)
.setStartDelay(delay)
.setUpdateListener(ctx.updateListener)
- .setInterpolator(mConfig.quintOutInterpolator)
- .setDuration(mConfig.taskViewEnterFromHomeDuration +
- frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay)
+ .setInterpolator(mQuintOutInterpolator)
+ .setDuration(taskViewEnterFromHomeDuration +
+ frontIndex * taskViewEnterFromHomeStaggerDelay)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -373,12 +410,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
/** Animates this task view as it leaves recents by pressing home. */
void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
+ int taskViewExitToHomeDuration = getResources().getInteger(
+ R.integer.recents_task_exit_to_home_duration);
animate()
.translationY(ctx.offscreenTranslationY)
.setStartDelay(0)
.setUpdateListener(null)
- .setInterpolator(mConfig.fastOutLinearInInterpolator)
- .setDuration(mConfig.taskViewExitToHomeDuration)
+ .setInterpolator(mFastOutLinearInInterpolator)
+ .setDuration(taskViewExitToHomeDuration)
.withEndAction(ctx.postAnimationTrigger.decrementAsRunnable())
.start();
ctx.postAnimationTrigger.increment();
@@ -392,6 +431,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
/** Animates this task view as it exits recents */
void startLaunchTaskAnimation(final Runnable postAnimRunnable, boolean isLaunchingTask,
boolean occludesLaunchTarget, boolean lockToTask) {
+ final int taskViewExitToAppDuration = mContext.getResources().getInteger(
+ R.integer.recents_task_exit_to_app_duration);
+ final int taskViewAffiliateGroupEnterOffset = mContext.getResources().getDimensionPixelSize(
+ R.dimen.recents_task_view_affiliate_group_enter_offset);
+
if (isLaunchingTask) {
// Animate the thumbnail alpha back into full opacity for the window animation out
mThumbnailView.startLaunchTaskAnimation(postAnimRunnable);
@@ -399,8 +443,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
// Animate the dim
if (mDimAlpha > 0) {
ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
- anim.setDuration(mConfig.taskViewExitToAppDuration);
- anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
+ anim.setDuration(taskViewExitToAppDuration);
+ anim.setInterpolator(mFastOutLinearInInterpolator);
anim.start();
}
@@ -414,8 +458,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
mActionButtonView.animate()
.alpha(0f)
.setStartDelay(0)
- .setDuration(mConfig.taskViewExitToAppDuration)
- .setInterpolator(mConfig.fastOutLinearInInterpolator)
+ .setDuration(taskViewExitToAppDuration)
+ .setInterpolator(mFastOutLinearInInterpolator)
.start();
} else {
// Hide the dismiss button
@@ -424,11 +468,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
// animate it away first
if (occludesLaunchTarget) {
animate().alpha(0f)
- .translationY(getTranslationY() + mConfig.taskViewAffiliateGroupEnterOffsetPx)
+ .translationY(getTranslationY() + taskViewAffiliateGroupEnterOffset)
.setStartDelay(0)
.setUpdateListener(null)
- .setInterpolator(mConfig.fastOutLinearInInterpolator)
- .setDuration(mConfig.taskViewExitToAppDuration)
+ .setInterpolator(mFastOutLinearInInterpolator)
+ .setDuration(taskViewExitToAppDuration)
.start();
}
}
@@ -436,15 +480,20 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
/** Animates the deletion of this task view */
void startDeleteTaskAnimation(final Runnable r, int delay) {
+ int taskViewRemoveAnimDuration = getResources().getInteger(
+ R.integer.recents_animate_task_view_remove_duration);
+ int taskViewRemoveAnimTranslationXPx = getResources().getDimensionPixelSize(
+ R.dimen.recents_task_view_remove_anim_translation_x);
+
// Disabling clipping with the stack while the view is animating away
setClipViewInStack(false);
- animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx)
+ animate().translationX(taskViewRemoveAnimTranslationXPx)
.alpha(0f)
.setStartDelay(delay)
.setUpdateListener(null)
- .setInterpolator(mConfig.fastOutSlowInInterpolator)
- .setDuration(mConfig.taskViewRemoveAnimDuration)
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .setDuration(taskViewRemoveAnimDuration)
.withEndAction(new Runnable() {
@Override
public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 3e9410e1348a..f68dd64b0bf2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -26,19 +26,21 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.RippleDrawable;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@@ -67,6 +69,8 @@ public class TaskViewHeader extends FrameLayout {
boolean mCurrentPrimaryColorIsDark;
int mCurrentPrimaryColor;
int mBackgroundColor;
+ int mCornerRadius;
+ int mHighlightHeight;
Drawable mLightDismissDrawable;
Drawable mDarkDismissDrawable;
RippleDrawable mBackground;
@@ -81,6 +85,9 @@ public class TaskViewHeader extends FrameLayout {
Paint mDimLayerPaint = new Paint();
PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
+ Interpolator mFastOutSlowInInterpolator;
+ Interpolator mFastOutLinearInInterpolator;
+
boolean mLayersDisabled;
public TaskViewHeader(Context context) {
@@ -113,13 +120,21 @@ public class TaskViewHeader extends FrameLayout {
mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark);
mDismissContentDescription =
context.getString(R.string.accessibility_recents_item_will_be_dismissed);
+ mCornerRadius = getResources().getDimensionPixelSize(
+ R.dimen.recents_task_view_rounded_corners_radius);
+ mHighlightHeight = getResources().getDimensionPixelSize(
+ R.dimen.recents_task_view_highlight);
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
+ mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_linear_in);
// Configure the highlight paint
if (sHighlightPaint == null) {
sHighlightPaint = new Paint();
sHighlightPaint.setStyle(Paint.Style.STROKE);
- sHighlightPaint.setStrokeWidth(mConfig.taskViewHighlightPx);
- sHighlightPaint.setColor(mConfig.taskBarViewHighlightColor);
+ sHighlightPaint.setStrokeWidth(mHighlightHeight);
+ sHighlightPaint.setColor(context.getColor(R.color.recents_task_bar_highlight_color));
sHighlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
sHighlightPaint.setAntiAlias(true);
}
@@ -154,8 +169,8 @@ public class TaskViewHeader extends FrameLayout {
@Override
protected void onDraw(Canvas canvas) {
// Draw the highlight at the top edge (but put the bottom edge just out of view)
- float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f);
- float radius = mConfig.taskViewRoundedCornerRadiusPx;
+ float offset = (float) Math.ceil(mHighlightHeight / 2f);
+ float radius = mCornerRadius;
int count = canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset,
@@ -207,10 +222,15 @@ public class TaskViewHeader extends FrameLayout {
mBackgroundColorDrawable.setColor(t.colorPrimary);
mBackgroundColor = t.colorPrimary;
}
+
+ int taskBarViewLightTextColor = getResources().getColor(
+ R.color.recents_task_bar_light_text_color);
+ int taskBarViewDarkTextColor = getResources().getColor(
+ R.color.recents_task_bar_dark_text_color);
mCurrentPrimaryColor = t.colorPrimary;
mCurrentPrimaryColorIsDark = t.useLightOnPrimaryColor;
mActivityDescription.setTextColor(t.useLightOnPrimaryColor ?
- mConfig.taskBarViewLightTextColor : mConfig.taskBarViewDarkTextColor);
+ taskBarViewLightTextColor : taskBarViewDarkTextColor);
mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
mLightDismissDrawable : mDarkDismissDrawable);
mDismissButton.setContentDescription(String.format(mDismissContentDescription,
@@ -262,12 +282,14 @@ public class TaskViewHeader extends FrameLayout {
/** Animates this task bar dismiss button when launching a task. */
void startLaunchTaskDismissAnimation() {
if (mDismissButton.getVisibility() == View.VISIBLE) {
+ int taskViewExitToAppDuration = mContext.getResources().getInteger(
+ R.integer.recents_task_exit_to_app_duration);
mDismissButton.animate().cancel();
mDismissButton.animate()
.alpha(0f)
.setStartDelay(0)
- .setInterpolator(mConfig.fastOutSlowInInterpolator)
- .setDuration(mConfig.taskViewExitToAppDuration)
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .setDuration(taskViewExitToAppDuration)
.start();
}
}
@@ -280,8 +302,9 @@ public class TaskViewHeader extends FrameLayout {
mDismissButton.animate()
.alpha(1f)
.setStartDelay(0)
- .setInterpolator(mConfig.fastOutLinearInInterpolator)
- .setDuration(mConfig.taskViewEnterFromAppDuration)
+ .setInterpolator(mFastOutLinearInInterpolator)
+ .setDuration(getResources().getInteger(
+ R.integer.recents_task_enter_from_app_duration))
.start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 117a7d328692..6c83beeff1da 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -32,9 +32,11 @@ import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
-import com.android.systemui.recents.RecentsConfiguration;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
+import com.android.systemui.R;
/**
@@ -43,9 +45,8 @@ import com.android.systemui.recents.model.Task;
*/
public class TaskViewThumbnail extends View {
- RecentsConfiguration mConfig;
-
// Drawing
+ int mCornerRadius;
float mDimAlpha;
Matrix mScaleMatrix = new Matrix();
Paint mDrawPaint = new Paint();
@@ -54,6 +55,8 @@ public class TaskViewThumbnail extends View {
BitmapShader mBitmapShader;
LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
+ Interpolator mFastOutSlowInInterpolator;
+
// Thumbnail alpha
float mThumbnailAlpha;
ValueAnimator mThumbnailAlphaAnimator;
@@ -89,15 +92,18 @@ public class TaskViewThumbnail extends View {
public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mConfig = RecentsConfiguration.getInstance();
mDrawPaint.setColorFilter(mLightingColorFilter);
mDrawPaint.setFilterBitmap(true);
mDrawPaint.setAntiAlias(true);
+ mCornerRadius = getResources().getDimensionPixelSize(
+ R.dimen.recents_task_view_rounded_corners_radius);
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
}
@Override
protected void onFinishInflate() {
- mThumbnailAlpha = mConfig.taskViewThumbnailAlpha;
+ mThumbnailAlpha = getResources().getFloat(R.dimen.recents_task_view_thumbnail_alpha);
updateThumbnailPaintFilter();
}
@@ -117,8 +123,8 @@ public class TaskViewThumbnail extends View {
}
// Draw the thumbnail with the rounded corners
canvas.drawRoundRect(0, 0, getWidth(), getHeight(),
- mConfig.taskViewRoundedCornerRadiusPx,
- mConfig.taskViewRoundedCornerRadiusPx, mDrawPaint);
+ mCornerRadius,
+ mCornerRadius, mDrawPaint);
}
/** Sets the thumbnail to a given bitmap. */
@@ -215,8 +221,10 @@ public class TaskViewThumbnail extends View {
startFadeAnimation(1f, 0, 150, null);
}
} else {
- if (Float.compare(getAlpha(), mConfig.taskViewThumbnailAlpha) != 0) {
- startFadeAnimation(mConfig.taskViewThumbnailAlpha, 0, 150, null);
+ float taskViewThumbnailAlpha = getResources().getFloat(
+ R.dimen.recents_task_view_thumbnail_alpha);
+ if (Float.compare(getAlpha(), taskViewThumbnailAlpha) != 0) {
+ startFadeAnimation(taskViewThumbnailAlpha, 0, 150, null);
}
}
}
@@ -229,20 +237,26 @@ public class TaskViewThumbnail extends View {
if (isTaskViewLaunchTargetTask) {
mThumbnailAlpha = 1f;
} else {
- mThumbnailAlpha = mConfig.taskViewThumbnailAlpha;
+ mThumbnailAlpha = getResources().getFloat(
+ R.dimen.recents_task_view_thumbnail_alpha);
}
updateThumbnailPaintFilter();
}
/** Animates this task thumbnail as it enters Recents. */
void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
- startFadeAnimation(mConfig.taskViewThumbnailAlpha, delay,
- mConfig.taskViewEnterFromAppDuration, postAnimRunnable);
+ float taskViewThumbnailAlpha = getResources().getFloat(
+ R.dimen.recents_task_view_thumbnail_alpha);
+ startFadeAnimation(taskViewThumbnailAlpha, delay,
+ getResources().getInteger(R.integer.recents_task_enter_from_app_duration),
+ postAnimRunnable);
}
/** Animates this task thumbnail as it exits Recents. */
void startLaunchTaskAnimation(Runnable postAnimRunnable) {
- startFadeAnimation(1f, 0, mConfig.taskViewExitToAppDuration, postAnimRunnable);
+ int taskViewExitToAppDuration = mContext.getResources().getInteger(
+ R.integer.recents_task_exit_to_app_duration);
+ startFadeAnimation(1f, 0, taskViewExitToAppDuration, postAnimRunnable);
}
/** Starts a new thumbnail alpha animation. */
@@ -251,7 +265,7 @@ public class TaskViewThumbnail extends View {
mThumbnailAlphaAnimator = ValueAnimator.ofFloat(mThumbnailAlpha, finalAlpha);
mThumbnailAlphaAnimator.setStartDelay(delay);
mThumbnailAlphaAnimator.setDuration(duration);
- mThumbnailAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
+ mThumbnailAlphaAnimator.setInterpolator(mFastOutSlowInInterpolator);
mThumbnailAlphaAnimator.addUpdateListener(mThumbnailAlphaUpdateListener);
if (postAnimRunnable != null) {
mThumbnailAlphaAnimator.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index b01a2a8a2c2f..10d4a965852f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -112,7 +112,7 @@ public class CommandQueue extends IStatusBar.Stub {
public void appTransitionStarting(long startTime, long duration);
public void showAssistDisclosure();
public void startAssist(Bundle args);
- public void onCameraLaunchGestureDetected();
+ public void onCameraLaunchGestureDetected(int source);
}
public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -306,10 +306,10 @@ public class CommandQueue extends IStatusBar.Stub {
}
@Override
- public void onCameraLaunchGestureDetected() {
+ public void onCameraLaunchGestureDetected(int source) {
synchronized (mList) {
mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE);
- mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE).sendToTarget();
+ mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget();
}
}
@@ -415,7 +415,7 @@ public class CommandQueue extends IStatusBar.Stub {
mCallbacks.startAssist((Bundle) msg.obj);
break;
case MSG_CAMERA_LAUNCH_GESTURE:
- mCallbacks.onCameraLaunchGestureDetected();
+ mCallbacks.onCameraLaunchGestureDetected(msg.arg1);
break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index d9127952a329..687f6c1b0922 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -130,7 +130,7 @@ public class DragDownHelper implements Gefingerpoken {
}
return true;
case MotionEvent.ACTION_UP:
- if (mDraggedFarEnough && mDragDownCallback.onDraggedDown(mStartingChild,
+ if (!isFalseTouch() && mDragDownCallback.onDraggedDown(mStartingChild,
(int) (y - mInitialTouchY))) {
if (mStartingChild == null) {
mDragDownCallback.setEmptyDragAmount(0f);
@@ -148,6 +148,13 @@ public class DragDownHelper implements Gefingerpoken {
return false;
}
+ private boolean isFalseTouch() {
+ if (mFalsingManager.isClassiferEnabled()) {
+ return mFalsingManager.isFalseTouch();
+ }
+ return !mDraggedFarEnough;
+ }
+
private void captureStartingChild(float x, float y) {
if (mStartingChild == null) {
mStartingChild = findView(x, y);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index ac4dee28e3e4..5e6fdd05a87a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -187,32 +187,41 @@ public class KeyguardIndicationController {
}
// Try fetching charging time from battery stats.
+ long chargingTimeRemaining = 0;
try {
- long chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
- if (chargingTimeRemaining > 0) {
- String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
- mContext, chargingTimeRemaining);
- return mContext.getResources().getString(
- R.string.keyguard_indication_charging_time, chargingTimeFormatted);
- }
+ chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
+
} catch (RemoteException e) {
Log.e(TAG, "Error calling IBatteryStats: ", e);
}
+ final boolean hasChargingTime = chargingTimeRemaining > 0;
- // Fall back to simple charging label.
int chargingId;
switch (mChargingSpeed) {
case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
- chargingId = R.string.keyguard_plugged_in_charging_fast;
+ chargingId = hasChargingTime
+ ? R.string.keyguard_indication_charging_time_fast_if_translated
+ : R.string.keyguard_plugged_in_charging_fast;
break;
case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
- chargingId = R.string.keyguard_plugged_in_charging_slowly;
+ chargingId = hasChargingTime
+ ? R.string.keyguard_indication_charging_time_slowly_if_translated
+ : R.string.keyguard_plugged_in_charging_slowly;
break;
default:
- chargingId = R.string.keyguard_plugged_in;
+ chargingId = hasChargingTime
+ ? R.string.keyguard_indication_charging_time
+ : R.string.keyguard_plugged_in;
break;
}
- return mContext.getResources().getString(chargingId);
+
+ if (hasChargingTime) {
+ String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+ mContext, chargingTimeRemaining);
+ return mContext.getResources().getString(chargingId, chargingTimeFormatted);
+ } else {
+ return mContext.getResources().getString(chargingId);
+ }
}
KeyguardUpdateMonitorCallback mUpdateMonitor = new KeyguardUpdateMonitorCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 60ebfdf639ef..41adeb587736 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -28,6 +28,7 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -62,6 +63,7 @@ public class KeyguardAffordanceHelper {
private Interpolator mAppearInterpolator;
private Interpolator mDisappearInterpolator;
private Animator mSwipeAnimator;
+ private FalsingManager mFalsingManager;
private int mMinBackgroundRadius;
private boolean mMotionCancelled;
private int mTouchTargetSize;
@@ -109,6 +111,7 @@ public class KeyguardAffordanceHelper {
android.R.interpolator.linear_out_slow_in);
mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
android.R.interpolator.fast_out_linear_in);
+ mFalsingManager = FalsingManager.getInstance(mContext);
}
private void initIcons() {
@@ -322,7 +325,12 @@ public class KeyguardAffordanceHelper {
float vel = getCurrentVelocity(lastX, lastY);
// We snap back if the current translation is not far enough
- boolean snapBack = isBelowFalsingThreshold();
+ boolean snapBack;
+ if (mFalsingManager.isFalseTouch()) {
+ snapBack = mFalsingManager.isFalseTouch();
+ } else {
+ snapBack = isBelowFalsingThreshold();
+ }
// or if the velocity is in the opposite direction.
boolean velIsInWrongDirection = vel * mTranslation < 0;
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 012dc9c53207..14176a6f5b3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -77,6 +77,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
+ public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance";
+ public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture";
+ public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap";
+
+ public static final String EXTRA_CAMERA_LAUNCH_SOURCE
+ = "com.android.systemui.camera_launch_source";
+
private static final Intent SECURE_CAMERA_INTENT =
new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
@@ -170,7 +177,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
return true;
} else if (host == mCameraImageView) {
- launchCamera();
+ launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
return true;
} else if (host == mLeftAffordanceView) {
launchLeftAffordance();
@@ -349,7 +356,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
public void onClick(View v) {
if (v == mCameraImageView) {
- launchCamera();
+ launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
} else if (v == mLeftAffordanceView) {
launchLeftAffordance();
} if (v == mLockIcon) {
@@ -417,8 +424,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
}
- public void launchCamera() {
+ public void launchCamera(String source) {
final Intent intent = getCameraIntent();
+ intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source);
boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
mContext, intent, KeyguardUpdateMonitor.getCurrentUser());
if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
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 e70d146119f4..71267cd7c582 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -81,7 +81,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
}
private void registerListener() {
- if (UserSwitcherController.isUserSwitcherAvailable(mUserManager) && mUserListener == null) {
+ if (mUserManager.isUserSwitcherEnabled() && mUserListener == null) {
final UserSwitcherController controller = mUserSwitcherController;
if (controller != null) {
@@ -103,7 +103,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
@Override
public void onClick(View v) {
- if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)) {
+ if (mUserManager.isUserSwitcherEnabled()) {
if (mKeyguardMode) {
if (mKeyguardUserSwitcher != null) {
mKeyguardUserSwitcher.show(true /* animate */);
@@ -135,14 +135,14 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
private void refreshContentDescription() {
String currentUser = null;
- if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)
+ if (mUserManager.isUserSwitcherEnabled()
&& mUserSwitcherController != null) {
currentUser = mUserSwitcherController.getCurrentUserName(mContext);
}
String text = null;
if (isClickable()) {
- if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)) {
+ if (mUserManager.isUserSwitcherEnabled()) {
if (TextUtils.isEmpty(currentUser)) {
text = mContext.getString(R.string.accessibility_multi_user_switch_switcher);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 980527b82666..08353cbb51c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -22,6 +22,7 @@ import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
+import android.app.StatusBarManager;
import android.content.Context;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
@@ -204,6 +205,7 @@ public class NotificationPanelView extends PanelView implements
private boolean mHeadsUpAnimatingAway;
private boolean mLaunchingAffordance;
private FalsingManager mFalsingManager;
+ private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
@Override
@@ -480,6 +482,7 @@ public class NotificationPanelView extends PanelView implements
mUnlockIconActive = false;
if (!mLaunchingAffordance) {
mAfforanceHelper.reset(false);
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
}
closeQs();
mStatusBar.dismissPopups();
@@ -692,7 +695,7 @@ public class NotificationPanelView extends PanelView implements
}
private boolean flingExpandsQs(float vel) {
- if (isBelowFalsingThreshold()) {
+ if (isFalseTouch()) {
return false;
}
if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
@@ -702,8 +705,14 @@ public class NotificationPanelView extends PanelView implements
}
}
- private boolean isBelowFalsingThreshold() {
- return !mQsTouchAboveFalsingThreshold && mStatusBarState == StatusBarState.KEYGUARD;
+ private boolean isFalseTouch() {
+ if (mStatusBarState != StatusBarState.KEYGUARD) {
+ return false;
+ }
+ if (mFalsingManager.isClassiferEnabled()) {
+ return mFalsingManager.isFalseTouch();
+ }
+ return !mQsTouchAboveFalsingThreshold;
}
private float getQsExpansionFraction() {
@@ -1428,7 +1437,7 @@ public class NotificationPanelView extends PanelView implements
}
return;
}
- boolean belowFalsingThreshold = isBelowFalsingThreshold();
+ boolean belowFalsingThreshold = isFalseTouch();
if (belowFalsingThreshold) {
vel = 0;
}
@@ -1965,20 +1974,23 @@ public class NotificationPanelView extends PanelView implements
mKeyguardBottomArea.launchLeftAffordance();
}
} else {
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp);
-
+ if (KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE.equals(
+ mLastCameraLaunchSource)) {
+ EventLogTags.writeSysuiLockscreenGesture(
+ EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA,
+ lengthDp, velocityDp);
+ }
mFalsingManager.onCameraOn();
if (mFalsingManager.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
@Override
public void run() {
- mKeyguardBottomArea.launchCamera();
+ mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
}
}, null, true /* dismissShade */, false /* afterKeyguardGone */);
}
else {
- mKeyguardBottomArea.launchCamera();
+ mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
}
}
mStatusBar.startLaunchTransitionTimeout();
@@ -2419,7 +2431,17 @@ public class NotificationPanelView extends PanelView implements
return !mDozing;
}
- public void launchCamera(boolean animate) {
+ public void launchCamera(boolean animate, int source) {
+ if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP;
+ } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) {
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE;
+ } else {
+
+ // Default.
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
+ }
+
// If we are launching it when we are occluded already we don't want it to animate,
// nor setting these flags, since the occluded state doesn't change anymore, hence it's
// never reset.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 3feead8f36ad..bd16257e6ece 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -610,8 +610,8 @@ public abstract class PanelView extends FrameLayout {
if (!mStatusBar.isFalsingThresholdNeeded()) {
return false;
}
- if (mFalsingManager.isFalseTouch()) {
- return true;
+ if (mFalsingManager.isClassiferEnabled()) {
+ return mFalsingManager.isFalseTouch();
}
if (!mTouchAboveFalsingThreshold) {
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 151fa3c5a033..37edc28b765d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -492,6 +492,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private ExpandableNotificationRow mDraggedDownRow;
private boolean mLaunchCameraOnScreenTurningOn;
private boolean mLaunchCameraOnFinishedGoingToSleep;
+ private int mLastCameraLaunchSource;
private PowerManager.WakeLock mGestureWakeLock;
private Vibrator mVibrator;
@@ -881,7 +882,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
mNextAlarmController = new NextAlarmController(mContext);
mKeyguardMonitor = new KeyguardMonitor(mContext);
- if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) {
+ if (UserManager.get(mContext).isUserSwitcherEnabled()) {
mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
mHandler);
if (mUserSwitcherController.useFullscreenUserSwitcher()) {
@@ -903,8 +904,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mBluetoothController, mLocationController, mRotationLockController,
mNetworkController, mZenModeController, mHotspotController,
mCastController, mFlashlightController,
- mUserSwitcherController, mKeyguardMonitor,
- mSecurityController);
+ mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
+ mSecurityController, mBatteryController);
mQSPanel.setHost(qsh);
mQSPanel.setTiles(qsh.getTiles());
mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
@@ -3000,6 +3001,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
}
+ public void dismissKeyguard() {
+ mStatusBarKeyguardViewManager.dismiss();
+ }
+
private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
boolean afterKeyguardGone) {
if (mStatusBarKeyguardViewManager.isShowing()) {
@@ -3992,7 +3997,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mHandler.post(new Runnable() {
@Override
public void run() {
- onCameraLaunchGestureDetected();
+ onCameraLaunchGestureDetected(mLastCameraLaunchSource);
}
});
}
@@ -4010,7 +4015,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mFalsingManager.onScreenTurningOn();
mNotificationPanel.onScreenTurningOn();
if (mLaunchCameraOnScreenTurningOn) {
- mNotificationPanel.launchCamera(false);
+ mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
mLaunchCameraOnScreenTurningOn = false;
}
}
@@ -4175,7 +4180,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- public void onCameraLaunchGestureDetected() {
+ public void onCameraLaunchGestureDetected(int source) {
+ mLastCameraLaunchSource = source;
if (mStartedGoingToSleep) {
mLaunchCameraOnFinishedGoingToSleep = true;
return;
@@ -4201,7 +4207,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
}
if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
- mNotificationPanel.launchCamera(mDeviceInteractive /* animate */);
+ mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
} else {
// We need to defer the camera launch until the screen comes on, since otherwise
// we will dismiss us too early since we are waiting on an activity to be drawn and
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 385c5d5bb736..6ec94946d2e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -26,34 +26,8 @@ import android.util.Log;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.tiles.AirplaneModeTile;
-import com.android.systemui.qs.tiles.BluetoothTile;
-import com.android.systemui.qs.tiles.CastTile;
-import com.android.systemui.qs.tiles.CellularTile;
-import com.android.systemui.qs.tiles.ColorInversionTile;
-import com.android.systemui.qs.tiles.DndTile;
-import com.android.systemui.qs.tiles.FlashlightTile;
-import com.android.systemui.qs.tiles.HotspotTile;
-import com.android.systemui.qs.tiles.IntentTile;
-import com.android.systemui.qs.tiles.LocationTile;
-import com.android.systemui.qs.tiles.QAirplaneTile;
-import com.android.systemui.qs.tiles.QBluetoothTile;
-import com.android.systemui.qs.tiles.QFlashlightTile;
-import com.android.systemui.qs.tiles.QRotationLockTile;
-import com.android.systemui.qs.tiles.QWifiTile;
-import com.android.systemui.qs.tiles.RotationLockTile;
-import com.android.systemui.qs.tiles.WifiTile;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.qs.tiles.*;
+import com.android.systemui.statusbar.policy.*;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -85,8 +59,10 @@ public class QSTileHost implements QSTile.Host, Tunable {
private final Looper mLooper;
private final FlashlightController mFlashlight;
private final UserSwitcherController mUserSwitcherController;
+ private final UserInfoController mUserInfoController;
private final KeyguardMonitor mKeyguard;
private final SecurityController mSecurity;
+ private final BatteryController mBattery;
private Callback mCallback;
@@ -95,8 +71,8 @@ public class QSTileHost implements QSTile.Host, Tunable {
RotationLockController rotation, NetworkController network,
ZenModeController zen, HotspotController hotspot,
CastController cast, FlashlightController flashlight,
- UserSwitcherController userSwitcher, KeyguardMonitor keyguard,
- SecurityController security) {
+ UserSwitcherController userSwitcher, UserInfoController userInfo, KeyguardMonitor keyguard,
+ SecurityController security, BatteryController battery) {
mContext = context;
mStatusBar = statusBar;
mBluetooth = bluetooth;
@@ -108,8 +84,10 @@ public class QSTileHost implements QSTile.Host, Tunable {
mCast = cast;
mFlashlight = flashlight;
mUserSwitcherController = userSwitcher;
+ mUserInfoController = userInfo;
mKeyguard = keyguard;
mSecurity = security;
+ mBattery = battery;
final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
Process.THREAD_PRIORITY_BACKGROUND);
@@ -203,10 +181,21 @@ public class QSTileHost implements QSTile.Host, Tunable {
return mKeyguard;
}
+ @Override
public UserSwitcherController getUserSwitcherController() {
return mUserSwitcherController;
}
+ @Override
+ public UserInfoController getUserInfoController() {
+ return mUserInfoController;
+ }
+
+ @Override
+ public BatteryController getBatteryController() {
+ return mBattery;
+ }
+
public SecurityController getSecurityController() {
return mSecurity;
}
@@ -259,6 +248,8 @@ public class QSTileHost implements QSTile.Host, Tunable {
else if (tileSpec.equals("location")) return new LocationTile(this);
else if (tileSpec.equals("cast")) return new CastTile(this);
else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
+ else if (tileSpec.equals("user")) return new UserTile(this);
+ else if (tileSpec.equals("battery")) return new BatteryTile(this);
// Detail only versions of wifi and bluetooth.
else if (tileSpec.equals("dwifi")) return new WifiTile(this, true);
else if (tileSpec.equals("dbt")) return new BluetoothTile(this, true);
@@ -268,6 +259,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
else if (tileSpec.equals("qairplane")) return new QAirplaneTile(this);
else if (tileSpec.equals("qrotation")) return new QRotationLockTile(this);
else if (tileSpec.equals("qflashlight")) return new QFlashlightTile(this);
+ else if (tileSpec.equals("qlock")) return new QLockTile(this);
// Intent tiles.
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index d1b69aba6528..5071df0dee48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
+import android.os.Handler;
import android.os.PowerManager;
import android.util.Log;
@@ -30,24 +31,31 @@ import java.util.ArrayList;
public class BatteryController extends BroadcastReceiver {
private static final String TAG = "BatteryController";
+
+ public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
+
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
private final PowerManager mPowerManager;
+ private final Handler mHandler;
private int mLevel;
private boolean mPluggedIn;
private boolean mCharging;
private boolean mCharged;
private boolean mPowerSave;
+ private boolean mTestmode = false;
public BatteryController(Context context) {
+ mHandler = new Handler();
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
+ filter.addAction(ACTION_LEVEL_TEST);
context.registerReceiver(this, filter);
updatePowerSave();
@@ -71,9 +79,10 @@ public class BatteryController extends BroadcastReceiver {
mChangeCallbacks.remove(cb);
}
- public void onReceive(Context context, Intent intent) {
+ public void onReceive(final Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+ if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
mLevel = (int)(100f
* intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
/ intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
@@ -89,6 +98,38 @@ public class BatteryController extends BroadcastReceiver {
updatePowerSave();
} else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)) {
setPowerSave(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false));
+ } else if (action.equals(ACTION_LEVEL_TEST)) {
+ mTestmode = true;
+ mHandler.post(new Runnable() {
+ int curLevel = 0;
+ int incr = 1;
+ int saveLevel = mLevel;
+ boolean savePlugged = mPluggedIn;
+ Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
+ @Override
+ public void run() {
+ if (curLevel < 0) {
+ mTestmode = false;
+ dummy.putExtra("level", saveLevel);
+ dummy.putExtra("plugged", savePlugged);
+ dummy.putExtra("testmode", false);
+ } else {
+ dummy.putExtra("level", curLevel);
+ dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
+ : 0);
+ dummy.putExtra("testmode", true);
+ }
+ context.sendBroadcast(dummy);
+
+ if (!mTestmode) return;
+
+ curLevel += incr;
+ if (curLevel == 100) {
+ incr *= -1;
+ }
+ mHandler.postDelayed(this, 200);
+ }
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index d907b0072eb1..cec0c0a25b35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -18,7 +18,8 @@ package com.android.systemui.statusbar.policy;
import android.app.ActivityManager;
import android.content.Context;
-
+import android.os.RemoteException;
+import android.view.WindowManagerGlobal;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.settings.CurrentUserTracker;
@@ -83,6 +84,20 @@ public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback {
return mCanSkipBouncer;
}
+ public void unlock() {
+ try {
+ WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void lock() {
+ try {
+ WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */);
+ } catch (RemoteException e) {
+ }
+ }
+
public void notifyKeyguardState(boolean showing, boolean secure) {
if (mShowing == showing && mSecure == secure) return;
mShowing = showing;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 0f9dd5cfc70b..e0823b41554d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -182,10 +182,10 @@ public class SecurityControllerImpl implements SecurityController {
@Override
public void onUserSwitched(int newUserId) {
mCurrentUserId = newUserId;
- if (mUserManager.getUserInfo(newUserId).isRestricted()) {
+ final UserInfo newUserInfo = mUserManager.getUserInfo(newUserId);
+ if (newUserInfo.isRestricted()) {
// VPN for a restricted profile is routed through its owner user
- // TODO: http://b/22950929
- mVpnUserId = UserHandle.USER_SYSTEM;
+ mVpnUserId = newUserInfo.restrictedProfileParentId;
} else {
mVpnUserId = mCurrentUserId;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
index a8d4f131b54e..6931d1ea6a6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -71,6 +71,11 @@ public final class UserInfoController {
public void addListener(OnUserInfoChangedListener callback) {
mCallbacks.add(callback);
+ callback.onUserInfoChanged(mUserName, mUserDrawable);
+ }
+
+ public void remListener(OnUserInfoChangedListener callback) {
+ mCallbacks.remove(callback);
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
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 81658941b339..e00b8907a01a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -752,9 +752,4 @@ public class UserSwitcherController {
}
}
}
-
- public static boolean isUserSwitcherAvailable(UserManager um) {
- return UserManager.supportsMultipleUsers() && um.isUserSwitcherEnabled();
- }
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 2587b9f237c8..bbe5dd90d11f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -171,7 +171,7 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
- public void onCameraLaunchGestureDetected() {
+ public void onCameraLaunchGestureDetected(int source) {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java
index 4387b33d0797..04a51f07b1d0 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java
@@ -9,8 +9,8 @@ import com.android.systemui.statusbar.phone.QSTileHost;
public class QSPagingSwitch extends TunerSwitch {
public static final String QS_PAGE_TILES =
- "dwifi,dbt,inversion,dnd,cell,airplane,rotation,flashlight,location,"
- + "hotspot,qwifi,qbt,qrotation,qflashlight,qairplane,cast";
+ "dwifi,dbt,dnd,cell,battery,user,rotation,flashlight,location,"
+ + "hotspot,qwifi,qbt,qlock,qflashlight,qairplane,inversion,cast";
public QSPagingSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
index 772f86643c2b..703ee6610314 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -206,8 +206,8 @@ public class QsTuner extends Fragment implements Callback {
private static class CustomHost extends QSTileHost {
public CustomHost(Context context) {
- super(context, null, null, null, null, null, null, null, null, null,
- null, null, new BlankSecurityController());
+ super(context, null, null, null, null, null, null, null, null, null, null,
+ null, null, new BlankSecurityController(), null);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 920f875576a9..9a78b6cbc023 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -39,7 +39,7 @@ import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.tuner.TunerService.Tunable;
-import static com.android.systemui.BatteryMeterView.SHOW_PERCENT_SETTING;
+import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
public class TunerFragment extends PreferenceFragment {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 50234b2e1b1b..715593891ccb 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -33,7 +33,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;
-import com.android.systemui.BatteryMeterView;
+import com.android.systemui.BatteryMeterDrawable;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
@@ -135,7 +135,7 @@ public class TunerService extends SystemUI {
public void clearAll() {
// A couple special cases.
Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
- Settings.System.putString(mContentResolver, BatteryMeterView.SHOW_PERCENT_SETTING, null);
+ Settings.System.putString(mContentResolver, BatteryMeterDrawable.SHOW_PERCENT_SETTING, null);
Intent intent = new Intent(DemoMode.ACTION_DEMO);
intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
mContext.sendBroadcast(intent);
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 8c830e8d9257..3759c918a519 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -611,7 +611,7 @@ nScriptIntrinsicBLAS_Double(JNIEnv *_env, jobject _this, jlong con, jlong id, ji
in_allocs[2] = (RsAllocation)C;
rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
- in_allocs, sizeof(in_allocs), nullptr,
+ in_allocs, NELEM(in_allocs), nullptr,
&call, sizeof(call), nullptr, 0);
}
@@ -646,7 +646,7 @@ nScriptIntrinsicBLAS_Complex(JNIEnv *_env, jobject _this, jlong con, jlong id, j
in_allocs[2] = (RsAllocation)C;
rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
- in_allocs, sizeof(in_allocs), nullptr,
+ in_allocs, NELEM(in_allocs), nullptr,
&call, sizeof(call), nullptr, 0);
}
@@ -681,7 +681,7 @@ nScriptIntrinsicBLAS_Z(JNIEnv *_env, jobject _this, jlong con, jlong id, jint fu
in_allocs[2] = (RsAllocation)C;
rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
- in_allocs, sizeof(in_allocs), nullptr,
+ in_allocs, NELEM(in_allocs), nullptr,
&call, sizeof(call), nullptr, 0);
}
@@ -707,7 +707,7 @@ nScriptIntrinsicBLAS_BNNM(JNIEnv *_env, jobject _this, jlong con, jlong id, jint
in_allocs[2] = (RsAllocation)C;
rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
- in_allocs, sizeof(in_allocs), nullptr,
+ in_allocs, NELEM(in_allocs), nullptr,
&call, sizeof(call), nullptr, 0);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 87a0b808f573..b52687a78298 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -45,28 +45,28 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
/**
* Flag for enabling the screen magnification feature.
*
- * @see #setEnabledFeatures(int)
+ * @see #setUserAndEnabledFeatures(int, int)
*/
static final int FLAG_FEATURE_SCREEN_MAGNIFIER = 0x00000001;
/**
* Flag for enabling the touch exploration feature.
*
- * @see #setEnabledFeatures(int)
+ * @see #setUserAndEnabledFeatures(int, int)
*/
static final int FLAG_FEATURE_TOUCH_EXPLORATION = 0x00000002;
/**
* Flag for enabling the filtering key events feature.
*
- * @see #setEnabledFeatures(int)
+ * @see #setUserAndEnabledFeatures(int, int)
*/
static final int FLAG_FEATURE_FILTER_KEY_EVENTS = 0x00000004;
/**
* Flag for enabling "Automatically click on mouse stop" feature.
*
- * @see #setEnabledFeatures(int)
+ * @see #setUserAndEnabledFeatures(int, int)
*/
static final int FLAG_FEATURE_AUTOCLICK = 0x00000008;
@@ -97,6 +97,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
private boolean mInstalled;
+ private int mUserId;
+
private int mEnabledFeatures;
private TouchExplorer mTouchExplorer;
@@ -327,13 +329,14 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
/* do nothing */
}
- void setEnabledFeatures(int enabledFeatures) {
- if (mEnabledFeatures == enabledFeatures) {
+ void setUserAndEnabledFeatures(int userId, int enabledFeatures) {
+ if (mEnabledFeatures == enabledFeatures && mUserId == userId) {
return;
}
if (mInstalled) {
disableFeatures();
}
+ mUserId = userId;
mEnabledFeatures = enabledFeatures;
if (mInstalled) {
enableFeatures();
@@ -350,7 +353,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
resetStreamState();
if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) {
- mAutoclickController = new AutoclickController(mContext);
+ mAutoclickController = new AutoclickController(mContext, mUserId);
addFirstEventHandler(mAutoclickController);
}
@@ -360,7 +363,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
- mScreenMagnifier = new ScreenMagnifier(mContext,
+ mScreenMagnifier = new ScreenMagnifier(mContext, mUserId,
Display.DEFAULT_DISPLAY, mAms);
addFirstEventHandler(mScreenMagnifier);
}
@@ -386,7 +389,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
mEventHandler = handler;
}
- void disableFeatures() {
+ private void disableFeatures() {
if (mAutoclickController != null) {
mAutoclickController.onDestroy();
mAutoclickController = null;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ff2a2ee3ca26..749a0807151a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1296,11 +1296,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
inputFilter = mInputFilter;
setInputFilter = true;
}
- mInputFilter.setEnabledFeatures(flags);
+ mInputFilter.setUserAndEnabledFeatures(userState.mUserId, flags);
} else {
if (mHasInputFilter) {
mHasInputFilter = false;
- mInputFilter.disableFeatures();
+ mInputFilter.setUserAndEnabledFeatures(userState.mUserId, 0);
inputFilter = null;
setInputFilter = true;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
index 8989625f979a..32833785a186 100644
--- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
@@ -51,6 +51,8 @@ import android.view.accessibility.AccessibilityEvent;
*
* It is expected that each instance will receive mouse events from a single mouse device. User of
* the class should handle cases where multiple mouse devices are present.
+ *
+ * Each instance is associated to a single user (and it does not handle user switch itself).
*/
public class AutoclickController implements EventStreamTransformation {
@@ -60,13 +62,15 @@ public class AutoclickController implements EventStreamTransformation {
private EventStreamTransformation mNext;
private final Context mContext;
+ private final int mUserId;
// Lazily created on the first mouse motion event.
private ClickScheduler mClickScheduler;
private ClickDelayObserver mClickDelayObserver;
- public AutoclickController(Context context) {
+ public AutoclickController(Context context, int userId) {
mContext = context;
+ mUserId = userId;
}
@Override
@@ -75,7 +79,7 @@ public class AutoclickController implements EventStreamTransformation {
if (mClickScheduler == null) {
Handler handler = new Handler(mContext.getMainLooper());
mClickScheduler = new ClickScheduler(handler, DEFAULT_CLICK_DELAY_MS);
- mClickDelayObserver = new ClickDelayObserver(handler);
+ mClickDelayObserver = new ClickDelayObserver(mUserId, handler);
mClickDelayObserver.start(mContext.getContentResolver(), mClickScheduler);
}
@@ -168,9 +172,11 @@ public class AutoclickController implements EventStreamTransformation {
private ContentResolver mContentResolver;
private ClickScheduler mClickScheduler;
+ private final int mUserId;
- public ClickDelayObserver(Handler handler) {
+ public ClickDelayObserver(int userId, Handler handler) {
super(handler);
+ mUserId = userId;
}
/**
@@ -199,7 +205,7 @@ public class AutoclickController implements EventStreamTransformation {
mContentResolver = contentResolver;
mClickScheduler = clickScheduler;
mContentResolver.registerContentObserver(mAutoclickDelaySettingUri, false, this,
- UserHandle.USER_ALL);
+ mUserId);
// Initialize mClickScheduler's initial delay value.
onChange(true, mAutoclickDelaySettingUri);
@@ -222,10 +228,9 @@ public class AutoclickController implements EventStreamTransformation {
@Override
public void onChange(boolean selfChange, Uri uri) {
if (mAutoclickDelaySettingUri.equals(uri)) {
- // TODO: Plumb current user id down to here and use getIntForUser.
- int delay = Settings.Secure.getInt(
+ int delay = Settings.Secure.getIntForUser(
mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY,
- DEFAULT_CLICK_DELAY_MS);
+ DEFAULT_CLICK_DELAY_MS, mUserId);
mClickScheduler.updateDelay(delay);
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
index 37276bdb8145..8845bc0246ba 100644
--- a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -29,7 +29,6 @@ import android.os.AsyncTask;
import android.os.Binder;
import android.os.Handler;
import android.os.Message;
-import android.os.SystemClock;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Property;
@@ -137,6 +136,8 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio
private final AccessibilityManagerService mAms;
+ private final int mUserId;
+
private final int mTapTimeSlop = ViewConfiguration.getJumpTapTimeout();
private final int mMultiTapTimeSlop;
private final int mTapDistanceSlop;
@@ -188,8 +189,10 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio
}
};
- public ScreenMagnifier(Context context, int displayId, AccessibilityManagerService service) {
+ public ScreenMagnifier(Context context, int userId, int displayId,
+ AccessibilityManagerService service) {
mContext = context;
+ mUserId = userId;
mWindowManager = LocalServices.getService(WindowManagerInternal.class);
mAms = service;
@@ -813,33 +816,12 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio
while (mDelayedEventQueue != null) {
MotionEventInfo info = mDelayedEventQueue;
mDelayedEventQueue = info.mNext;
- final long offset = SystemClock.uptimeMillis() - info.mCachedTimeMillis;
- MotionEvent event = obtainEventWithOffsetTimeAndDownTime(info.mEvent, offset);
- MotionEvent rawEvent = obtainEventWithOffsetTimeAndDownTime(info.mRawEvent, offset);
- ScreenMagnifier.this.onMotionEvent(event, rawEvent, info.mPolicyFlags);
- event.recycle();
- rawEvent.recycle();
+ ScreenMagnifier.this.onMotionEvent(info.mEvent, info.mRawEvent,
+ info.mPolicyFlags);
info.recycle();
}
}
- private MotionEvent obtainEventWithOffsetTimeAndDownTime(MotionEvent event, long offset) {
- final int pointerCount = event.getPointerCount();
- PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
- PointerProperties[] properties = getTempPointerPropertiesWithMinSize(pointerCount);
- for (int i = 0; i < pointerCount; i++) {
- event.getPointerCoords(i, coords[i]);
- event.getPointerProperties(i, properties[i]);
- }
- final long downTime = event.getDownTime() + offset;
- final long eventTime = event.getEventTime() + offset;
- return MotionEvent.obtain(downTime, eventTime,
- event.getAction(), pointerCount, properties, coords,
- event.getMetaState(), event.getButtonState(),
- 1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(),
- event.getSource(), event.getFlags());
- }
-
private void clearDelayedMotionEvents() {
while (mDelayedEventQueue != null) {
MotionEventInfo info = mDelayedEventQueue;
@@ -882,17 +864,17 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
- Settings.Secure.putFloat(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale);
+ Settings.Secure.putFloatForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale, mUserId);
return null;
}
}.execute();
}
private float getPersistedScale() {
- return Settings.Secure.getFloat(mContext.getContentResolver(),
+ return Settings.Secure.getFloatForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
- DEFAULT_MAGNIFICATION_SCALE);
+ DEFAULT_MAGNIFICATION_SCALE, mUserId);
}
private static boolean isScreenMagnificationAutoUpdateEnabled(Context context) {
@@ -915,7 +897,6 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio
public MotionEvent mEvent;
public MotionEvent mRawEvent;
public int mPolicyFlags;
- public long mCachedTimeMillis;
public static MotionEventInfo obtain(MotionEvent event, MotionEvent rawEvent,
int policyFlags) {
@@ -940,7 +921,6 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio
mEvent = MotionEvent.obtain(event);
mRawEvent = MotionEvent.obtain(rawEvent);
mPolicyFlags = policyFlags;
- mCachedTimeMillis = SystemClock.uptimeMillis();
}
public void recycle() {
@@ -964,7 +944,6 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio
mRawEvent.recycle();
mRawEvent = null;
mPolicyFlags = 0;
- mCachedTimeMillis = 0;
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6190a5ab357e..a7e6f1187719 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -754,6 +754,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_STARTING);
intentFilter.addAction(Intent.ACTION_USER_STOPPING);
+ intentFilter.addAction(Intent.ACTION_USER_ADDED);
+ intentFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverAsUser(
mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
@@ -3525,6 +3527,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void onUserAdded(int userId) {
+ synchronized(mVpns) {
+ final int vpnsSize = mVpns.size();
+ for (int i = 0; i < vpnsSize; i++) {
+ Vpn vpn = mVpns.valueAt(i);
+ vpn.onUserAdded(userId);
+ }
+ }
+ }
+
+ private void onUserRemoved(int userId) {
+ synchronized(mVpns) {
+ final int vpnsSize = mVpns.size();
+ for (int i = 0; i < vpnsSize; i++) {
+ Vpn vpn = mVpns.valueAt(i);
+ vpn.onUserRemoved(userId);
+ }
+ }
+ }
+
private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -3536,6 +3558,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
onUserStart(userId);
} else if (Intent.ACTION_USER_STOPPING.equals(action)) {
onUserStop(userId);
+ } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+ onUserAdded(userId);
+ } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ onUserRemoved(userId);
}
}
};
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 0c6eb40f5b08..ebcdf7c31901 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -31,6 +31,8 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorManager;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.hardware.display.DisplayManager;
@@ -111,7 +113,7 @@ public class DeviceIdleController extends SystemService
private INetworkPolicyManager mNetworkPolicyManager;
private DisplayManager mDisplayManager;
private SensorManager mSensorManager;
- private Sensor mSigMotionSensor;
+ private Sensor mMotionSensor;
private LocationManager mLocationManager;
private LocationRequest mLocationRequest;
private PendingIntent mSensingAlarmIntent;
@@ -123,7 +125,6 @@ public class DeviceIdleController extends SystemService
private boolean mForceIdle;
private boolean mScreenOn;
private boolean mCharging;
- private boolean mSigMotionActive;
private boolean mSensing;
private boolean mNotMoving;
private boolean mLocating;
@@ -268,13 +269,57 @@ public class DeviceIdleController extends SystemService
}
};
- private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
- @Override public void onTrigger(TriggerEvent event) {
+ private final class MotionListener extends TriggerEventListener
+ implements SensorEventListener {
+
+ boolean active = false;
+
+ @Override
+ public void onTrigger(TriggerEvent event) {
synchronized (DeviceIdleController.this) {
- significantMotionLocked();
+ active = false;
+ motionLocked();
+ }
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ synchronized (DeviceIdleController.this) {
+ mSensorManager.unregisterListener(this, mMotionSensor);
+ active = false;
+ motionLocked();
}
}
- };
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+
+ public boolean registerLocked() {
+ boolean success = false;
+ if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
+ success = mSensorManager.requestTriggerSensor(mMotionListener, mMotionSensor);
+ } else {
+ success = mSensorManager.registerListener(
+ mMotionListener, mMotionSensor, SensorManager.SENSOR_DELAY_NORMAL);
+ }
+ if (success) {
+ active = true;
+ } else {
+ Slog.e(TAG, "Unable to register for " + mMotionSensor);
+ }
+ return success;
+ }
+
+ public void unregisterLocked() {
+ if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
+ mSensorManager.cancelTriggerSensor(mMotionListener, mMotionSensor);
+ } else {
+ mSensorManager.unregisterListener(mMotionListener);
+ }
+ active = false;
+ }
+ }
+ private final MotionListener mMotionListener = new MotionListener();
private final LocationListener mGenericLocationListener = new LocationListener() {
@Override
@@ -349,7 +394,7 @@ public class DeviceIdleController extends SystemService
* This is the time, after becoming inactive, at which we start looking at the
* motion sensor to determine if the device is being left alone. We don't do this
* immediately after going inactive just because we don't want to be continually running
- * the significant motion sensor whenever the screen is off.
+ * the motion sensor whenever the screen is off.
* @see Settings.Global#DEVICE_IDLE_CONSTANTS
* @see #KEY_INACTIVE_TIMEOUT
*/
@@ -392,7 +437,7 @@ public class DeviceIdleController extends SystemService
/**
* This is the time, after the inactive timeout elapses, that we will wait looking
- * for significant motion until we truly consider the device to be idle.
+ * for motion until we truly consider the device to be idle.
* @see Settings.Global#DEVICE_IDLE_CONSTANTS
* @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT
*/
@@ -886,18 +931,19 @@ public class DeviceIdleController extends SystemService
int sigMotionSensorId = getContext().getResources().getInteger(
com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);
if (sigMotionSensorId > 0) {
- mSigMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
+ mMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
}
- if (mSigMotionSensor == null && getContext().getResources().getBoolean(
+ if (mMotionSensor == null && getContext().getResources().getBoolean(
com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) {
- mSigMotionSensor = mSensorManager.getDefaultSensor(
- Sensor.TYPE_WRIST_TILT_GESTURE);
+ mMotionSensor = mSensorManager.getDefaultSensor(
+ Sensor.TYPE_WRIST_TILT_GESTURE, true);
}
- if (mSigMotionSensor == null) {
+ if (mMotionSensor == null) {
// As a last ditch, fall back to SMD.
- mSigMotionSensor = mSensorManager.getDefaultSensor(
- Sensor.TYPE_SIGNIFICANT_MOTION);
+ mMotionSensor = mSensorManager.getDefaultSensor(
+ Sensor.TYPE_SIGNIFICANT_MOTION, true);
}
+
if (getContext().getResources().getBoolean(
com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
mLocationManager = (LocationManager) getContext().getSystemService(
@@ -1242,7 +1288,7 @@ public class DeviceIdleController extends SystemService
cancelAlarmLocked();
cancelSensingAlarmLocked();
cancelLocatingLocked();
- stopMonitoringSignificantMotion();
+ stopMonitoringMotionLocked();
mAnyMotionDetector.stop();
}
@@ -1271,8 +1317,8 @@ public class DeviceIdleController extends SystemService
switch (mState) {
case STATE_INACTIVE:
// We have now been inactive long enough, it is time to start looking
- // for significant motion and sleep some more while doing so.
- startMonitoringSignificantMotion();
+ // for motion and sleep some more while doing so.
+ startMonitoringMotionLocked();
scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
// Reset the upcoming idle delays.
mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
@@ -1353,17 +1399,16 @@ public class DeviceIdleController extends SystemService
}
}
- void significantMotionLocked() {
- if (DEBUG) Slog.d(TAG, "significantMotionLocked()");
- // When the sensor goes off, its trigger is automatically removed.
- mSigMotionActive = false;
+ void motionLocked() {
+ if (DEBUG) Slog.d(TAG, "motionLocked()");
+ // The motion sensor will have been disabled at this point
handleMotionDetectedLocked(mConstants.MOTION_INACTIVE_TIMEOUT, "motion");
}
void handleMotionDetectedLocked(long timeout, String type) {
// The device is not yet active, so we want to go back to the pending idle
- // state to wait again for no motion. Note that we only monitor for significant
- // motion after moving out of the inactive state, so no need to worry about that.
+ // state to wait again for no motion. Note that we only monitor for motion
+ // after moving out of the inactive state, so no need to worry about that.
if (mState != STATE_ACTIVE) {
scheduleReportActiveLocked(type, Process.myUid());
mState = STATE_ACTIVE;
@@ -1405,19 +1450,17 @@ public class DeviceIdleController extends SystemService
}
}
- void startMonitoringSignificantMotion() {
- if (DEBUG) Slog.d(TAG, "startMonitoringSignificantMotion()");
- if (mSigMotionSensor != null && !mSigMotionActive) {
- mSensorManager.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
- mSigMotionActive = true;
+ void startMonitoringMotionLocked() {
+ if (DEBUG) Slog.d(TAG, "startMonitoringMotionLocked()");
+ if (mMotionSensor != null && !mMotionListener.active) {
+ mMotionListener.registerLocked();
}
}
- void stopMonitoringSignificantMotion() {
- if (DEBUG) Slog.d(TAG, "stopMonitoringSignificantMotion()");
- if (mSigMotionActive) {
- mSensorManager.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
- mSigMotionActive = false;
+ void stopMonitoringMotionLocked() {
+ if (DEBUG) Slog.d(TAG, "stopMonitoringMotionLocked()");
+ if (mMotionSensor != null && mMotionListener.active) {
+ mMotionListener.unregisterLocked();
}
}
@@ -1446,7 +1489,7 @@ public class DeviceIdleController extends SystemService
void scheduleAlarmLocked(long delay, boolean idleUntil) {
if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
- if (mSigMotionSensor == null) {
+ if (mMotionSensor == null) {
// If there is no motion sensor on this device, then we won't schedule
// alarms, because we can't determine if the device is not moving. This effectively
// turns off normal execution of device idling, although it is still possible to
@@ -1929,11 +1972,11 @@ public class DeviceIdleController extends SystemService
pw.print(" mEnabled="); pw.println(mEnabled);
pw.print(" mForceIdle="); pw.println(mForceIdle);
- pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor);
+ pw.print(" mMotionSensor="); pw.println(mMotionSensor);
pw.print(" mCurDisplay="); pw.println(mCurDisplay);
pw.print(" mScreenOn="); pw.println(mScreenOn);
pw.print(" mCharging="); pw.println(mCharging);
- pw.print(" mSigMotionActive="); pw.println(mSigMotionActive);
+ pw.print(" mMotionActive="); pw.println(mMotionListener.active);
pw.print(" mSensing="); pw.print(mSensing); pw.print(" mNotMoving=");
pw.println(mNotMoving);
pw.print(" mLocating="); pw.print(mLocating); pw.print(" mHasGps=");
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 7c85001c9175..f2459852d706 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.ActivityManager;
+import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -263,7 +264,8 @@ public class GestureLauncherService extends SystemService {
}
if (launched) {
Slog.i(TAG, "Power button double tap gesture detected, launching camera.");
- launched = handleCameraLaunchGesture(false /* useWakelock */);
+ launched = handleCameraLaunchGesture(false /* useWakelock */,
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
if (launched) {
MetricsLogger.action(mContext, MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
(int) doubleTapInterval);
@@ -276,7 +278,7 @@ public class GestureLauncherService extends SystemService {
/**
* @return true if camera was launched, false otherwise.
*/
- private boolean handleCameraLaunchGesture(boolean useWakelock) {
+ private boolean handleCameraLaunchGesture(boolean useWakelock, int source) {
boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
if (!userSetupComplete) {
@@ -295,7 +297,7 @@ public class GestureLauncherService extends SystemService {
}
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
- service.onCameraLaunchGestureDetected();
+ service.onCameraLaunchGestureDetected(source);
return true;
}
@@ -334,7 +336,8 @@ public class GestureLauncherService extends SystemService {
Slog.d(TAG, String.format("Received a camera launch event: " +
"values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
}
- if (handleCameraLaunchGesture(true /* useWakelock */)) {
+ if (handleCameraLaunchGesture(true /* useWakelock */,
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
MetricsLogger.action(mContext, MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE);
trackCameraLaunchEvent(event);
}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 9dad7a181a06..ab1d775e3c32 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -37,6 +37,7 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.AppGlobals;
@@ -280,8 +281,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
boolean mSystemReady;
/**
- * Id of the currently selected input method.
+ * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
+ * method. This is to be synchronized with the secure settings keyed with
+ * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
+ *
+ * <p>This can be transiently {@code null} when the system is re-initializing input method
+ * settings, e.g., the system locale is just changed.</p>
+ *
+ * <p>Note that {@link #mCurId} is used to track which IME is being connected to
+ * {@link InputMethodManagerService}.</p>
+ *
+ * @see #mCurId
*/
+ @Nullable
String mCurMethodId;
/**
@@ -311,9 +323,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
EditorInfo mCurAttribute;
/**
- * The input method ID of the input method service that we are currently
+ * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
* connected to or in the process of connecting to.
+ *
+ * <p>This can be {@code null} when no input method is connected.</p>
+ *
+ * @see #mCurMethodId
*/
+ @Nullable
String mCurId;
/**
@@ -918,7 +935,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|| (newLocale != null && !newLocale.equals(mLastSystemLocale))) {
if (!updateOnlyWhenLocaleChanged) {
hideCurrentInputLocked(0, null);
- mCurMethodId = null;
unbindCurrentMethodLocked(true, false);
}
if (DEBUG) {
@@ -1474,7 +1490,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
channel.dispose();
}
- void unbindCurrentMethodLocked(boolean reportToClient, boolean savePosition) {
+ void unbindCurrentMethodLocked(boolean resetCurrentMethodAndClient, boolean savePosition) {
+ if (resetCurrentMethodAndClient) {
+ mCurMethodId = null;
+ }
+
if (mVisibleBound) {
mContext.unbindService(mVisibleConnection);
mVisibleBound = false;
@@ -1501,9 +1521,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurId = null;
clearCurMethodLocked();
- if (reportToClient && mCurClient != null) {
- executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
- MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
+ if (resetCurrentMethodAndClient) {
+ unbindCurrentClientLocked();
}
}
@@ -1857,13 +1876,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Unknown input method from prefs: " + id, e);
- mCurMethodId = null;
unbindCurrentMethodLocked(true, false);
}
mShortcutInputMethodsAndSubtypes.clear();
} else {
// There is no longer an input method set, so stop any current one.
- mCurMethodId = null;
unbindCurrentMethodLocked(true, false);
}
// Here is not the perfect place to reset the switching controller. Ideally
diff --git a/services/core/java/com/android/server/ThermalObserver.java b/services/core/java/com/android/server/ThermalObserver.java
new file mode 100644
index 000000000000..aee28fb6b295
--- /dev/null
+++ b/services/core/java/com/android/server/ThermalObserver.java
@@ -0,0 +1,146 @@
+/*
+ * 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.server;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.UEventObserver;
+import android.os.UserHandle;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * ThermalObserver for monitoring temperature changes.
+ */
+public class ThermalObserver extends SystemService {
+ private static final String TAG = "ThermalObserver";
+
+ private static final String CALLSTATE_UEVENT_MATCH =
+ "DEVPATH=/devices/virtual/switch/thermalstate";
+
+ private static final int MSG_THERMAL_STATE_CHANGED = 0;
+
+ private static final int SWITCH_STATE_NORMAL = 0;
+ private static final int SWITCH_STATE_WARNING = 1;
+ private static final int SWITCH_STATE_EXCEEDED = 2;
+
+ private final PowerManager mPowerManager;
+ private final PowerManager.WakeLock mWakeLock;
+
+ private final Object mLock = new Object();
+ private Integer mLastState;
+
+ private final UEventObserver mThermalWarningObserver = new UEventObserver() {
+ @Override
+ public void onUEvent(UEventObserver.UEvent event) {
+ updateLocked(Integer.parseInt(event.get("SWITCH_STATE")));
+ }
+ };
+
+ private final Handler mHandler = new Handler(true /*async*/) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_THERMAL_STATE_CHANGED:
+ handleThermalStateChange(msg.arg1);
+ mWakeLock.release();
+ break;
+ }
+ }
+ };
+
+ public ThermalObserver(Context context) {
+ super(context);
+ mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+ mThermalWarningObserver.startObserving(CALLSTATE_UEVENT_MATCH);
+ }
+
+ private void updateLocked(int state) {
+ Message message = new Message();
+ message.what = MSG_THERMAL_STATE_CHANGED;
+ message.arg1 = state;
+
+ mWakeLock.acquire();
+ mHandler.sendMessage(message);
+ }
+
+ private void handleThermalStateChange(int state) {
+ synchronized (mLock) {
+ mLastState = state;
+ Intent intent = new Intent(Intent.ACTION_THERMAL_EVENT);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+
+ final int thermalState;
+
+ switch (state) {
+ case SWITCH_STATE_WARNING:
+ thermalState = Intent.EXTRA_THERMAL_STATE_WARNING;
+ break;
+ case SWITCH_STATE_EXCEEDED:
+ thermalState = Intent.EXTRA_THERMAL_STATE_EXCEEDED;
+ break;
+ case SWITCH_STATE_NORMAL:
+ default:
+ thermalState = Intent.EXTRA_THERMAL_STATE_NORMAL;
+ break;
+ }
+
+ intent.putExtra(Intent.EXTRA_THERMAL_STATE, thermalState);
+
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(TAG, new BinderService());
+ }
+
+ private final class BinderService extends Binder {
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump thermal observer service from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ if (args == null || args.length == 0 || "-a".equals(args[0])) {
+ pw.println("Current Thermal Observer Service state:");
+ pw.println(" last state change: "
+ + (mLastState != null ? mLastState : "none"));
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index dbf128840c59..6b346123e94a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -29,6 +29,7 @@ import android.accounts.IAccountAuthenticator;
import android.accounts.IAccountAuthenticatorResponse;
import android.accounts.IAccountManager;
import android.accounts.IAccountManagerResponse;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -2526,6 +2527,7 @@ public class AccountManagerService
* Returns the accounts visible to the client within the context of a specific user
* @hide
*/
+ @NonNull
public Account[] getAccounts(int userId, String opPackageName) {
int callingUid = Binder.getCallingUid();
List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
@@ -2551,6 +2553,7 @@ public class AccountManagerService
*
* @hide
*/
+ @NonNull
public AccountAndUser[] getRunningAccounts() {
final int[] runningUserIds;
try {
@@ -2563,6 +2566,7 @@ public class AccountManagerService
}
/** {@hide} */
+ @NonNull
public AccountAndUser[] getAllAccounts() {
final List<UserInfo> users = getUserManager().getUsers();
final int[] userIds = new int[users.size()];
@@ -2572,6 +2576,7 @@ public class AccountManagerService
return getAccounts(userIds);
}
+ @NonNull
private AccountAndUser[] getAccounts(int[] userIds) {
final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
for (int userId : userIds) {
@@ -2591,10 +2596,12 @@ public class AccountManagerService
}
@Override
+ @NonNull
public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
return getAccountsAsUser(type, userId, null, -1, opPackageName);
}
+ @NonNull
private Account[] getAccountsAsUser(
String type,
int userId,
@@ -2649,6 +2656,7 @@ public class AccountManagerService
}
}
+ @NonNull
private Account[] getAccountsInternal(
UserAccounts userAccounts,
int callingUid,
@@ -2672,7 +2680,15 @@ public class AccountManagerService
}
@Override
- public boolean addSharedAccountAsUser(Account account, int userId) {
+ public void addSharedAccountsFromParentUser(int parentUserId, int userId) {
+ checkManageUsersPermission("addSharedAccountsFromParentUser");
+ Account[] accounts = getAccountsAsUser(null, parentUserId, mContext.getOpPackageName());
+ for (Account account : accounts) {
+ addSharedAccountAsUser(account, userId);
+ }
+ }
+
+ private boolean addSharedAccountAsUser(Account account, int userId) {
userId = handleIncomingUser(userId);
UserAccounts accounts = getUserAccounts(userId);
SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
@@ -2764,11 +2780,13 @@ public class AccountManagerService
}
@Override
+ @NonNull
public Account[] getAccounts(String type, String opPackageName) {
return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
}
@Override
+ @NonNull
public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
int callingUid = Binder.getCallingUid();
if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
@@ -2780,6 +2798,7 @@ public class AccountManagerService
}
@Override
+ @NonNull
public Account[] getAccountsByTypeForPackage(String type, String packageName,
String opPackageName) {
int packageUid = -1;
@@ -3844,6 +3863,14 @@ public class AccountManagerService
return false;
}
+ private static void checkManageUsersPermission(String message) {
+ if (ActivityManager.checkComponentPermission(
+ android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("You need MANAGE_USERS permission to: " + message);
+ }
+ }
+
private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
int callerUid) {
if (callerUid == Process.SYSTEM_UID) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bd10c63edbda..617264c29efd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -20,8 +20,11 @@ import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.HOME_STACK_ID;
import static android.app.ActivityManager.INVALID_STACK_ID;
+import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -8685,7 +8688,32 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
return;
}
- mStackSupervisor.resizeTaskLocked(task, bounds, resizeMode);
+ // Place the task in the right stack if it isn't there already based on
+ // the requested bounds.
+ // The stack transition logic is:
+ // - a null bounds on a freeform task moves that task to fullscreen
+ // - a non-null bounds on a non-freeform (fullscreen OR docked) task moves
+ // that task to freeform
+ // - otherwise the task is not moved
+ // Note it's not allowed to resize a home stack task, or a docked task.
+ int stackId = task.stack.mStackId;
+ if (stackId == HOME_STACK_ID || stackId == DOCKED_STACK_ID) {
+ throw new IllegalArgumentException("trying to resizeTask on a "
+ + "home or docked task");
+ }
+ if (bounds == null && stackId == FREEFORM_WORKSPACE_STACK_ID) {
+ stackId = FULLSCREEN_WORKSPACE_STACK_ID;
+ } else if (bounds != null && stackId != FREEFORM_WORKSPACE_STACK_ID ) {
+ stackId = FREEFORM_WORKSPACE_STACK_ID;
+ }
+ boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0;
+ if (stackId != task.stack.mStackId) {
+ mStackSupervisor.moveTaskToStackUncheckedLocked(
+ task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
+ preserveWindow = false;
+ }
+
+ mStackSupervisor.resizeTaskLocked(task, bounds, resizeMode, preserveWindow);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -11893,7 +11921,8 @@ public final class ActivityManagerService extends ActivityManagerNative
updateCurrentProfileIdsLocked();
mRecentTasks.clear();
- mRecentTasks.addAll(mTaskPersister.restoreTasksLocked());
+ mRecentTasks.addAll(mTaskPersister.restoreTasksLocked(
+ getUserManagerLocked().getUserIds()));
mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
mTaskPersister.startPersisting();
@@ -20644,9 +20673,6 @@ public final class ActivityManagerService extends ActivityManagerNative
// Kill all the processes for the user.
forceStopUserLocked(userId, "finish user");
}
-
- // Explicitly remove the old information in mRecentTasks.
- mRecentTasks.removeTasksForUserLocked(userId);
}
for (int i=0; i<callbacks.size(); i++) {
@@ -20665,6 +20691,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ void onUserRemovedLocked(int userId) {
+ mRecentTasks.removeTasksForUserLocked(userId);
+ }
+
@Override
public UserInfo getCurrentUser() {
if ((checkCallingPermission(INTERACT_ACROSS_USERS)
@@ -20949,6 +20979,13 @@ public final class ActivityManagerService extends ActivityManagerNative
return homeActivity == null ? null : homeActivity.realActivity;
}
}
+
+ @Override
+ public void onUserRemoved(int userId) {
+ synchronized (ActivityManagerService.this) {
+ ActivityManagerService.this.onUserRemovedLocked(userId);
+ }
+ }
}
private final class SleepTokenImpl extends SleepToken {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 5d106dce294b..a796ea7d4ab5 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1957,7 +1957,6 @@ final class ActivityStack {
? AppTransition.TRANSIT_ACTIVITY_CLOSE
: AppTransition.TRANSIT_TASK_CLOSE, false);
}
- mWindowManager.setAppWillBeHidden(prev.appToken);
mWindowManager.setAppVisibility(prev.appToken, false);
} else {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
@@ -1973,10 +1972,6 @@ final class ActivityStack {
: AppTransition.TRANSIT_TASK_OPEN, false);
}
}
- if (false) {
- mWindowManager.setAppWillBeHidden(prev.appToken);
- mWindowManager.setAppVisibility(prev.appToken, false);
- }
} else {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
if (mNoAnimActivities.contains(next)) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 17a44720deaf..98b6ee6d2402 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -24,6 +24,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
@@ -87,6 +88,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.os.WorkSource;
@@ -1348,8 +1350,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
r.launchFailed = false;
if (stack.updateLRUListLocked(r)) {
- Slog.w(TAG, "Activity " + r
- + " being launched, but already in LRU list");
+ Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
}
if (andResume) {
@@ -2968,6 +2969,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
return;
}
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
+
ActivityRecord r = stack.topRunningActivityLocked(null);
mTmpBounds.clear();
@@ -3051,9 +3054,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
resumeTopActivitiesLocked(stack, null, null);
}
}
+
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
- void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode) {
+ void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
if (!task.mResizeable) {
Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
return;
@@ -3061,7 +3066,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// If this is a forced resize, let it go through even if the bounds is not changing,
// as we might need a relayout due to surface size change (to/from fullscreen).
- final boolean forced = (resizeMode == RESIZE_MODE_FORCED);
+ final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) {
// Nothing to do here...
return;
@@ -3079,20 +3084,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
return;
}
- // The stack of a task is determined by its size (fullscreen vs non-fullscreen).
- // Place the task in the right stack if it isn't there already based on the requested
- // bounds.
- int stackId = task.stack.mStackId;
- if (bounds == null && stackId != FULLSCREEN_WORKSPACE_STACK_ID) {
- stackId = FULLSCREEN_WORKSPACE_STACK_ID;
- } else if (bounds != null
- && stackId != FREEFORM_WORKSPACE_STACK_ID && stackId != DOCKED_STACK_ID) {
- stackId = FREEFORM_WORKSPACE_STACK_ID;
- }
- final boolean changedStacks = stackId != task.stack.mStackId;
- if (changedStacks) {
- moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
- }
+ // Do not move the task to another stack here.
+ // This method assumes that the task is already placed in the right stack.
+ // we do not mess with that decision and we only do the resize!
+
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + task.taskId);
final Configuration overrideConfig = task.updateOverrideConfiguration(bounds);
// This variable holds information whether the configuration didn't change in a signficant
@@ -3103,27 +3099,17 @@ public final class ActivityStackSupervisor implements DisplayListener {
ActivityRecord r = task.topRunningActivityLocked(null);
if (r != null) {
final ActivityStack stack = task.stack;
- final boolean resizedByUser = resizeMode == RESIZE_MODE_USER;
- final boolean preserveWindow = resizedByUser && !changedStacks;
kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow);
// All other activities must be made visible with their correct configuration.
ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
if (!kept) {
resumeTopActivitiesLocked(stack, null, null);
- if (changedStacks && stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
- // We are about to relaunch the activity because its configuration changed
- // due to being maximized, i.e. size change. The activity will first
- // remove the old window and then add a new one. This call will tell window
- // manager about this, so it can preserve the old window until the new
- // one is drawn. This prevents having a gap between the removal and
- // addition, in which no window is visible. We also want the entrace of the
- // new window to be properly animated.
- mWindowManager.setReplacingWindow(r.appToken, true /* animate */);
- }
}
}
}
mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced);
+
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
@@ -3204,7 +3190,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
* @param reason Reason the task is been moved.
* @return The stack the task was moved to.
*/
- private ActivityStack moveTaskToStackUncheckedLocked(
+ ActivityStack moveTaskToStackUncheckedLocked(
TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
final ActivityRecord r = task.getTopActivity();
final boolean wasFocused = isFrontStack(task.stack) && (topRunningActivityLocked() == r);
@@ -3246,17 +3232,30 @@ public final class ActivityStackSupervisor implements DisplayListener {
return;
}
final String reason = "moveTaskToStack";
+ if (stackId == DOCKED_STACK_ID || stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+ // We are about to relaunch the activity because its configuration changed due to
+ // being maximized, i.e. size change. The activity will first remove the old window
+ // and then add a new one. This call will tell window manager about this, so it can
+ // preserve the old window until the new one is drawn. This prevents having a gap
+ // between the removal and addition, in which no window is visible. We also want the
+ // entrace of the new window to be properly animated.
+ ActivityRecord r = task.getTopActivity();
+ mWindowManager.setReplacingWindow(r.appToken, true /* animate */);
+ }
final ActivityStack stack =
moveTaskToStackUncheckedLocked(task, stackId, toTop, forceFocus, reason);
// Make sure the task has the appropriate bounds/size for the stack it is in.
if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
- resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM);
+ resizeTaskLocked(task, stack.mBounds,
+ RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
} else if (stackId == FREEFORM_WORKSPACE_STACK_ID
&& task.mBounds == null && task.mLastNonFullscreenBounds != null) {
- resizeTaskLocked(task, task.mLastNonFullscreenBounds, RESIZE_MODE_SYSTEM);
+ resizeTaskLocked(task, task.mLastNonFullscreenBounds,
+ RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
} else if (stackId == DOCKED_STACK_ID) {
- resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM);
+ resizeTaskLocked(task, stack.mBounds,
+ RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
}
// The task might have already been running and its visibility needs to be synchronized with
@@ -4617,16 +4616,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
return mActivityDisplay != null;
}
- void getBounds(Point outBounds) {
- synchronized (mService) {
- if (mActivityDisplay != null) {
- mActivityDisplay.getBounds(outBounds);
- } else {
- outBounds.set(0, 0);
- }
- }
- }
-
// TODO: Make sure every change to ActivityRecord.visible results in a call to this.
void setVisible(boolean visible) {
if (mVisible != visible) {
@@ -4798,12 +4787,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
mStacks.remove(stack);
}
- void getBounds(Point bounds) {
- mDisplay.getDisplayInfo(mDisplayInfo);
- bounds.x = mDisplayInfo.appWidth;
- bounds.y = mDisplayInfo.appHeight;
- }
-
void setVisibleBehindActivity(ActivityRecord r) {
mVisibleBehindActivity = r;
}
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index aa154a7c3850..871331b770e2 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -35,6 +35,7 @@ import android.util.SparseArray;
import android.util.Xml;
import android.os.Process;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
@@ -330,7 +331,7 @@ public class TaskPersister {
return null;
}
- ArrayList<TaskRecord> restoreTasksLocked() {
+ ArrayList<TaskRecord> restoreTasksLocked(final int [] validUserIds) {
final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
@@ -362,15 +363,18 @@ public class TaskPersister {
if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" +
task);
if (task != null) {
- task.isPersistable = true;
// XXX Don't add to write queue... there is no reason to write
// out the stuff we just read, if we don't write it we will
// read the same thing again.
//mWriteQueue.add(new TaskWriteQueueItem(task));
- tasks.add(task);
final int taskId = task.taskId;
- recoveredTaskIds.add(taskId);
mStackSupervisor.setNextTaskId(taskId);
+ // Check if it's a valid user id. Don't add tasks for removed users.
+ if (ArrayUtils.contains(validUserIds, task.userId)) {
+ task.isPersistable = true;
+ tasks.add(task);
+ recoveredTaskIds.add(taskId);
+ }
} else {
Slog.e(TAG, "Unable to restore taskFile=" + taskFile + ": " +
fileToString(taskFile));
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 43f5baab793f..7e14b2b78f0f 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1193,7 +1193,7 @@ final class TaskRecord {
mOverrideConfig = Configuration.EMPTY;
} else {
mBounds = new Rect(bounds);
- if (stack.mStackId != DOCKED_STACK_ID) {
+ if (stack == null || stack.mStackId != DOCKED_STACK_ID) {
mLastNonFullscreenBounds = mBounds;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 99ca050c9ae7..c4b57f1945a1 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -501,7 +501,6 @@ public class AudioService extends IAudioService.Stub {
private volatile IRingtonePlayer mRingtonePlayer;
private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
- private int mDeviceRotation = Surface.ROTATION_0;
// Request to override default use of A2DP for media.
private boolean mBluetoothA2dpEnabled;
@@ -545,8 +544,6 @@ public class AudioService extends IAudioService.Stub {
// If absolute volume is supported in AVRCP device
private boolean mAvrcpAbsVolSupported = false;
- private AudioOrientationEventListener mOrientationListener;
-
private static Long mLastDeviceConnectMsgTime = new Long(0);
private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
@@ -669,15 +666,7 @@ public class AudioService extends IAudioService.Stub {
}
mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
if (mMonitorRotation) {
- mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay().getRotation();
- Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
-
- mOrientationListener = new AudioOrientationEventListener(mContext);
- mOrientationListener.enable();
-
- // initialize rotation in AudioSystem
- setRotationForAudioSystem();
+ RotationHelper.init(mContext, mAudioHandler);
}
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
@@ -805,7 +794,7 @@ public class AudioService extends IAudioService.Stub {
setOrientationForAudioSystem();
}
if (mMonitorRotation) {
- setRotationForAudioSystem();
+ RotationHelper.updateOrientation();
}
synchronized (mBluetoothA2dpEnabledLock) {
@@ -1058,25 +1047,6 @@ public class AudioService extends IAudioService.Stub {
return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
}
- private class AudioOrientationEventListener
- extends OrientationEventListener {
- public AudioOrientationEventListener(Context context) {
- super(context);
- }
-
- @Override
- public void onOrientationChanged(int orientation) {
- //Even though we're responding to phone orientation events,
- //use display rotation so audio stays in sync with video/dialogs
- int newRotation = ((WindowManager) mContext.getSystemService(
- Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
- if (newRotation != mDeviceRotation) {
- mDeviceRotation = newRotation;
- setRotationForAudioSystem();
- }
- }
- }
-
///////////////////////////////////////////////////////////////////////////
// IPC methods
///////////////////////////////////////////////////////////////////////////
@@ -2524,11 +2494,14 @@ public class AudioService extends IAudioService.Stub {
}
/** @see AudioManager#setBluetoothScoOn(boolean) */
- public void setBluetoothScoOn(boolean on){
+ public void setBluetoothScoOn(boolean on) {
if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
return;
}
+ setBluetoothScoOnInt(on);
+ }
+ public void setBluetoothScoOnInt(boolean on) {
if (on) {
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
} else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
@@ -2889,6 +2862,8 @@ public class AudioService extends IAudioService.Stub {
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
}
+ AudioSystem.setParameters("A2dpSuspended=false");
+ setBluetoothScoOnInt(false);
}
private void broadcastScoConnectionState(int state) {
@@ -5061,14 +5036,13 @@ public class AudioService extends IAudioService.Stub {
}
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
if (mMonitorRotation) {
- mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
- mOrientationListener.enable();
+ RotationHelper.enable();
}
AudioSystem.setParameters("screen_state=on");
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
if (mMonitorRotation) {
//reduce wakeups (save current) by only listening when display is on
- mOrientationListener.disable();
+ RotationHelper.disable();
}
AudioSystem.setParameters("screen_state=off");
} else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
@@ -5317,6 +5291,7 @@ public class AudioService extends IAudioService.Stub {
}
}
+ //TODO move to an external "orientation helper" class
private void setOrientationForAudioSystem() {
switch (mDeviceOrientation) {
case Configuration.ORIENTATION_LANDSCAPE:
@@ -5340,26 +5315,6 @@ public class AudioService extends IAudioService.Stub {
}
}
- private void setRotationForAudioSystem() {
- switch (mDeviceRotation) {
- case Surface.ROTATION_0:
- AudioSystem.setParameters("rotation=0");
- break;
- case Surface.ROTATION_90:
- AudioSystem.setParameters("rotation=90");
- break;
- case Surface.ROTATION_180:
- AudioSystem.setParameters("rotation=180");
- break;
- case Surface.ROTATION_270:
- AudioSystem.setParameters("rotation=270");
- break;
- default:
- Log.e(TAG, "Unknown device rotation");
- }
- }
-
-
// Handles request to override default use of A2DP for media.
// Must be called synchronized on mConnectedDevices
public void setBluetoothA2dpOnInt(boolean on) {
diff --git a/services/core/java/com/android/server/audio/RotationHelper.java b/services/core/java/com/android/server/audio/RotationHelper.java
new file mode 100644
index 000000000000..f03e6c7c545a
--- /dev/null
+++ b/services/core/java/com/android/server/audio/RotationHelper.java
@@ -0,0 +1,209 @@
+/*
+ * 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.server.audio;
+
+import android.content.Context;
+import android.media.AudioSystem;
+import android.os.Handler;
+import android.util.Log;
+import android.view.OrientationEventListener;
+import android.view.Surface;
+import android.view.WindowManager;
+
+import com.android.server.policy.WindowOrientationListener;
+
+/**
+ * Class to handle device rotation events for AudioService, and forward device rotation
+ * to the audio HALs through AudioSystem.
+ *
+ * The role of this class is to monitor device orientation changes, and upon rotation,
+ * verify the UI orientation. In case of a change, send the new orientation, in increments
+ * of 90deg, through AudioSystem.
+ *
+ * Note that even though we're responding to device orientation events, we always
+ * query the display rotation so audio stays in sync with video/dialogs. This is
+ * done with .getDefaultDisplay().getRotation() from WINDOW_SERVICE.
+ */
+class RotationHelper {
+
+ private static final String TAG = "AudioService.RotationHelper";
+
+ private static AudioOrientationListener sOrientationListener;
+ private static AudioWindowOrientationListener sWindowOrientationListener;
+
+ private static final Object sRotationLock = new Object();
+ private static int sDeviceRotation = Surface.ROTATION_0; // R/W synchronized on sRotationLock
+
+ private static Context sContext;
+
+ /**
+ * post conditions:
+ * - (sWindowOrientationListener != null) xor (sOrientationListener != null)
+ * - sWindowOrientationListener xor sOrientationListener is enabled
+ * - sContext != null
+ */
+ static void init(Context context, Handler handler) {
+ if (context == null) {
+ throw new IllegalArgumentException("Invalid null context");
+ }
+ sContext = context;
+ sWindowOrientationListener = new AudioWindowOrientationListener(context, handler);
+ sWindowOrientationListener.enable();
+ if (!sWindowOrientationListener.canDetectOrientation()) {
+ // cannot use com.android.server.policy.WindowOrientationListener, revert to public
+ // orientation API
+ Log.i(TAG, "Not using WindowOrientationListener, reverting to OrientationListener");
+ sWindowOrientationListener.disable();
+ sWindowOrientationListener = null;
+ sOrientationListener = new AudioOrientationListener(context);
+ sOrientationListener.enable();
+ }
+ }
+
+ static void enable() {
+ if (sWindowOrientationListener != null) {
+ sWindowOrientationListener.enable();
+ } else {
+ sOrientationListener.enable();
+ }
+ updateOrientation();
+ }
+
+ static void disable() {
+ if (sWindowOrientationListener != null) {
+ sWindowOrientationListener.disable();
+ } else {
+ sOrientationListener.disable();
+ }
+ }
+
+ /**
+ * Query current display rotation and publish the change if any.
+ */
+ static void updateOrientation() {
+ // Even though we're responding to device orientation events,
+ // use display rotation so audio stays in sync with video/dialogs
+ int newRotation = ((WindowManager) sContext.getSystemService(
+ Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
+ synchronized(sRotationLock) {
+ if (newRotation != sDeviceRotation) {
+ sDeviceRotation = newRotation;
+ publishRotation(sDeviceRotation);
+ }
+ }
+ }
+
+ private static void publishRotation(int rotation) {
+ Log.v(TAG, "publishing device rotation =" + rotation + " (x90deg)");
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ AudioSystem.setParameters("rotation=0");
+ break;
+ case Surface.ROTATION_90:
+ AudioSystem.setParameters("rotation=90");
+ break;
+ case Surface.ROTATION_180:
+ AudioSystem.setParameters("rotation=180");
+ break;
+ case Surface.ROTATION_270:
+ AudioSystem.setParameters("rotation=270");
+ break;
+ default:
+ Log.e(TAG, "Unknown device rotation");
+ }
+ }
+
+ /**
+ * Uses android.view.OrientationEventListener
+ */
+ final static class AudioOrientationListener extends OrientationEventListener {
+ AudioOrientationListener(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onOrientationChanged(int orientation) {
+ updateOrientation();
+ }
+ }
+
+ /**
+ * Uses com.android.server.policy.WindowOrientationListener
+ */
+ final static class AudioWindowOrientationListener extends WindowOrientationListener {
+ private static RotationCheckThread sRotationCheckThread;
+
+ AudioWindowOrientationListener(Context context, Handler handler) {
+ super(context, handler);
+ }
+
+ public void onProposedRotationChanged(int rotation) {
+ updateOrientation();
+ if (sRotationCheckThread != null) {
+ sRotationCheckThread.endCheck();
+ }
+ sRotationCheckThread = new RotationCheckThread();
+ sRotationCheckThread.beginCheck();
+ }
+ }
+
+ /**
+ * When com.android.server.policy.WindowOrientationListener report an orientation change,
+ * the UI may not have rotated yet. This thread polls with gradually increasing delays
+ * the new orientation.
+ */
+ final static class RotationCheckThread extends Thread {
+ // how long to wait between each rotation check
+ private final int[] WAIT_TIMES_MS = { 10, 20, 50, 100, 100, 200, 200, 500 };
+ private int mWaitCounter;
+ private final Object mCounterLock = new Object();
+
+ RotationCheckThread() {
+ super("RotationCheck");
+ }
+
+ void beginCheck() {
+ synchronized(mCounterLock) {
+ mWaitCounter = 0;
+ }
+ try {
+ start();
+ } catch (IllegalStateException e) { }
+ }
+
+ void endCheck() {
+ synchronized(mCounterLock) {
+ mWaitCounter = WAIT_TIMES_MS.length;
+ }
+ }
+
+ public void run() {
+ int newRotation;
+ while (mWaitCounter < WAIT_TIMES_MS.length) {
+ updateOrientation();
+ int waitTimeMs;
+ synchronized(mCounterLock) {
+ waitTimeMs = WAIT_TIMES_MS[mWaitCounter];
+ mWaitCounter++;
+ }
+ try {
+ sleep(waitTimeMs);
+ } catch (InterruptedException e) { }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 3df3cd0b587b..2bea278aad1a 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -20,9 +20,6 @@ import static android.Manifest.permission.BIND_VPN_SERVICE;
import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
-import static android.os.UserHandle.PER_USER_RANGE;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
import android.Manifest;
import android.app.AppGlobals;
@@ -34,13 +31,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -126,7 +121,6 @@ public class Vpn {
/* list of users using this VPN. */
@GuardedBy("this")
private List<UidRange> mVpnUsers = null;
- private BroadcastReceiver mUserIntentReceiver = null;
// Handle of user initiating VPN.
private final int mUserHandle;
@@ -146,31 +140,6 @@ public class Vpn {
} catch (RemoteException e) {
Log.wtf(TAG, "Problem registering observer", e);
}
- // TODO: http://b/22950929
- if (userHandle == UserHandle.USER_SYSTEM) {
- // Owner's VPN also needs to handle restricted users
- mUserIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_NULL);
- if (userHandle == UserHandle.USER_NULL) return;
-
- if (Intent.ACTION_USER_ADDED.equals(action)) {
- onUserAdded(userHandle);
- } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
- onUserRemoved(userHandle);
- }
- }
- };
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_ADDED);
- intentFilter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiverAsUser(
- mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
- }
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, "");
// TODO: Copy metered attribute and bandwidths from physical transport, b/16207332
@@ -439,8 +408,8 @@ public class Vpn {
}
addVpnUserLocked(mUserHandle);
- // If we are owner assign all Restricted Users to this VPN
- if (mUserHandle == UserHandle.USER_OWNER) {
+ // If the user can have restricted profiles, assign all its restricted profiles to this VPN
+ if (canHaveRestrictedProfile(mUserHandle)) {
token = Binder.clearCallingIdentity();
List<UserInfo> users;
try {
@@ -449,7 +418,7 @@ public class Vpn {
Binder.restoreCallingIdentity(token);
}
for (UserInfo user : users) {
- if (user.isRestricted()) {
+ if (user.isRestricted() && (user.restrictedProfileParentId == mUserHandle)) {
addVpnUserLocked(user.id);
}
}
@@ -457,6 +426,15 @@ public class Vpn {
mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()]));
}
+ private boolean canHaveRestrictedProfile(int userId) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ return UserManager.get(mContext).canHaveRestrictedProfile(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) {
networkInfo.setIsAvailable(false);
networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
@@ -681,12 +659,11 @@ public class Vpn {
mStatusIntent = null;
}
- private void onUserAdded(int userHandle) {
- // If the user is restricted tie them to the owner's VPN
- synchronized(Vpn.this) {
- UserManager mgr = UserManager.get(mContext);
- UserInfo user = mgr.getUserInfo(userHandle);
- if (user.isRestricted()) {
+ public void onUserAdded(int userHandle) {
+ // If the user is restricted tie them to the parent user's VPN
+ UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
+ if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+ synchronized(Vpn.this) {
try {
addVpnUserLocked(userHandle);
if (mNetworkAgent != null) {
@@ -700,12 +677,11 @@ public class Vpn {
}
}
- private void onUserRemoved(int userHandle) {
+ public void onUserRemoved(int userHandle) {
// clean up if restricted
- synchronized(Vpn.this) {
- UserManager mgr = UserManager.get(mContext);
- UserInfo user = mgr.getUserInfo(userHandle);
- if (user.isRestricted()) {
+ UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
+ if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+ synchronized(Vpn.this) {
try {
removeVpnUserLocked(userHandle);
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 533f425e33f7..452378ff1e45 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -837,7 +837,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (mPendingScreenOff && target != Display.STATE_OFF) {
setScreenState(Display.STATE_OFF);
mPendingScreenOff = false;
- mPowerState.dismissColorFade();
}
if (target == Display.STATE_ON) {
@@ -911,7 +910,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// A black surface is already hiding the contents of the screen.
setScreenState(Display.STATE_OFF);
mPendingScreenOff = false;
- mPowerState.dismissColorFade();
} else if (performScreenOffTransition
&& mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ?
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index be37f524eb8d..088d96e4a6e0 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -544,7 +544,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId);
}
}
- if (physIndex > 0 && mActivePhysIndex == physIndex) {
+ if (mActivePhysIndex == physIndex) {
return;
}
SurfaceControl.setActiveConfig(getDisplayTokenLocked(), physIndex);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0c884f1558fa..7b15aad7b6ca 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -27,6 +27,7 @@ import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.AutomaticZenRule;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.ITransientNotification;
@@ -101,6 +102,7 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -1172,8 +1174,8 @@ public class NotificationManagerService extends SystemService {
// Don't allow client applications to cancel foreground service notis.
cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Binder.getCallingUid() == Process.SYSTEM_UID
- ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL,
- null);
+ ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId,
+ REASON_NOMAN_CANCEL, null);
}
@Override
@@ -1594,6 +1596,50 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public List<AutomaticZenRule> getAutomaticZenRules() throws RemoteException {
+ enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
+ return mZenModeHelper.getAutomaticZenRules();
+ }
+
+ @Override
+ public AutomaticZenRule getAutomaticZenRule(String name) throws RemoteException {
+ enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
+ return mZenModeHelper.getAutomaticZenRule(name);
+ }
+
+ @Override
+ public boolean addOrUpdateAutomaticZenRule(AutomaticZenRule automaticZenRule)
+ throws RemoteException {
+ Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
+ Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
+ Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
+ Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
+ enforcePolicyAccess(Binder.getCallingUid(), "addOrUpdateZenModeRule");
+
+ return mZenModeHelper.addOrUpdateAutomaticZenRule(automaticZenRule,
+ "addOrUpdateAutomaticZenRule");
+ }
+
+ @Override
+ public boolean renameAutomaticZenRule(String oldName, String newName) {
+ Preconditions.checkNotNull(oldName, "oldName is null");
+ Preconditions.checkNotNull(newName, "newName is null");
+ enforcePolicyAccess(Binder.getCallingUid(), "renameAutomaticZenRule");
+
+ return mZenModeHelper.renameAutomaticZenRule(
+ oldName, newName, "renameAutomaticZenRule");
+ }
+
+ @Override
+ public boolean removeAutomaticZenRule(String name) throws RemoteException {
+ Preconditions.checkNotNull(name, "Name is null");
+ // Verify that they can modify zen rules.
+ enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
+
+ return mZenModeHelper.removeAutomaticZenRule(name, "removeAutomaticZenRule");
+ }
+
+ @Override
public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
enforcePolicyAccess(pkg, "setInterruptionFilter");
final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
@@ -1641,7 +1687,30 @@ public class NotificationManagerService extends SystemService {
message);
}
+ private void enforcePolicyAccess(int uid, String method) {
+ if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
+ android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
+ return;
+ }
+ boolean accessAllowed = false;
+ String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
+ final int packageCount = packages.length;
+ for (int i = 0; i < packageCount; i++) {
+ if (checkPolicyAccess(packages[i])) {
+ accessAllowed = true;
+ }
+ }
+ if (!accessAllowed) {
+ Slog.w(TAG, "Notification policy access denied calling " + method);
+ throw new SecurityException("Notification policy access denied");
+ }
+ }
+
private void enforcePolicyAccess(String pkg, String method) {
+ if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
+ android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
+ return;
+ }
if (!checkPolicyAccess(pkg)) {
Slog.w(TAG, "Notification policy access denied calling " + method);
throw new SecurityException("Notification policy access denied");
@@ -1684,7 +1753,7 @@ public class NotificationManagerService extends SystemService {
public boolean matchesCallFilter(Bundle extras) {
enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
return mZenModeHelper.matchesCallFilter(
- UserHandle.getCallingUserHandle(),
+ Binder.getCallingUserHandle(),
extras,
mRankingHelper.findExtractor(ValidateNotificationPeople.class),
MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index cbe61c3da5af..4d41e3a9d734 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -21,11 +21,13 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION;
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import android.app.AppOpsManager;
+import android.app.AutomaticZenRule;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
@@ -34,6 +36,7 @@ import android.media.AudioManagerInternal;
import android.media.AudioSystem;
import android.media.VolumePolicy;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -62,6 +65,7 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -196,6 +200,121 @@ public class ZenModeHelper {
return mZenMode;
}
+ public List<AutomaticZenRule> getAutomaticZenRules() {
+ List<AutomaticZenRule> rules = new ArrayList<>();
+ if (mConfig == null) return rules;
+ for(ZenRule rule : mConfig.automaticRules.values()) {
+ if (canManageAutomaticZenRule(rule)) {
+ rules.add(createAutomaticZenRule(rule));
+ }
+ }
+ return rules;
+ }
+
+ public AutomaticZenRule getAutomaticZenRule(String name) {
+ if (mConfig == null) return null;
+ for(ZenRule rule : mConfig.automaticRules.values()) {
+ if (canManageAutomaticZenRule(rule) && rule.name.equals(name)) {
+ return createAutomaticZenRule(rule);
+ }
+ }
+ return null;
+ }
+
+ public boolean addOrUpdateAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
+ if (mConfig == null) return false;
+ if (DEBUG) {
+ Log.d(TAG, "addOrUpdateAutomaticZenRule zenRule=" + automaticZenRule
+ + " reason=" + reason);
+ }
+ final ZenModeConfig newConfig = mConfig.copy();
+ String ruleId = findMatchingRuleId(newConfig, automaticZenRule.getName());
+ ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
+ if (ruleId == null) {
+ ruleId = newConfig.newRuleId();
+ rule.name = automaticZenRule.getName();
+ rule.component = automaticZenRule.getOwner();
+ } else {
+ rule = newConfig.automaticRules.get(ruleId);
+ if (!canManageAutomaticZenRule(rule)) {
+ throw new SecurityException(
+ "Cannot update rules not owned by your condition provider");
+ }
+ }
+ if (rule.enabled != automaticZenRule.isEnabled()) {
+ rule.snoozing = false;
+ }
+ rule.condition = null;
+ rule.conditionId = automaticZenRule.getConditionId();
+ rule.enabled = automaticZenRule.isEnabled();
+ rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
+ automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
+ newConfig.automaticRules.put(ruleId, rule);
+ return setConfig(newConfig, reason, true);
+ }
+
+ public boolean renameAutomaticZenRule(String oldName, String newName, String reason) {
+ if (mConfig == null) return false;
+ if (DEBUG) {
+ Log.d(TAG, "renameAutomaticZenRule oldName=" + oldName + " newName=" + newName
+ + " reason=" + reason);
+ }
+ final ZenModeConfig newConfig = mConfig.copy();
+ String ruleId = findMatchingRuleId(newConfig, oldName);
+ if (ruleId == null) {
+ return false;
+ } else {
+ ZenRule rule = newConfig.automaticRules.get(ruleId);
+ if (!canManageAutomaticZenRule(rule)) {
+ throw new SecurityException(
+ "Cannot update rules not owned by your condition provider");
+ }
+ rule.name = newName;
+ return setConfig(newConfig, reason, true);
+ }
+ }
+
+ public boolean removeAutomaticZenRule(String name, String reason) {
+ if (mConfig == null) return false;
+ final ZenModeConfig newConfig = mConfig.copy();
+ String ruleId = findMatchingRuleId(newConfig, name);
+ if (ruleId != null) {
+ ZenRule rule = newConfig.automaticRules.get(ruleId);
+ if (canManageAutomaticZenRule(rule)) {
+ newConfig.automaticRules.remove(ruleId);
+ if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + name + " reason=" + reason);
+ } else {
+ throw new SecurityException(
+ "Cannot delete rules not owned by your condition provider");
+ }
+ }
+ return setConfig(newConfig, reason, true);
+ }
+
+ public boolean canManageAutomaticZenRule(ZenRule rule) {
+ if (mContext.checkCallingPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ } else {
+ String[] packages = mContext.getPackageManager().getPackagesForUid(
+ Binder.getCallingUid());
+ if (packages != null) {
+ final int packageCount = packages.length;
+ for (int i = 0; i < packageCount; i++) {
+ if (packages[i].equals(rule.component.getPackageName())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+ private AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
+ return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
+ NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled);
+ }
+
public void setManualZenMode(int zenMode, Uri conditionId, String reason) {
setManualZenMode(zenMode, conditionId, reason, true /*setRingerMode*/);
}
@@ -225,6 +344,15 @@ public class ZenModeHelper {
setConfig(newConfig, reason, setRingerMode);
}
+ private String findMatchingRuleId(ZenModeConfig config, String ruleName) {
+ for (String ruleId : config.automaticRules.keySet()) {
+ if (config.automaticRules.get(ruleId).name.equals(ruleName)) {
+ return ruleId;
+ }
+ }
+ return null;
+ }
+
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mZenMode=");
pw.println(Global.zenModeToString(mZenMode));
@@ -248,8 +376,9 @@ public class ZenModeHelper {
}
pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s,"
+ "events=%s,reminders=%s)\n",
- config.allowCalls, config.allowCallsFrom, config.allowRepeatCallers,
- config.allowMessages, config.allowMessagesFrom,
+ config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
+ config.allowRepeatCallers, config.allowMessages,
+ ZenModeConfig.sourceToString(config.allowMessagesFrom),
config.allowEvents, config.allowReminders);
pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
if (config.automaticRules.isEmpty()) return;
@@ -271,7 +400,7 @@ public class ZenModeHelper {
}
config.manualRule = null; // don't restore the manual rule
if (config.automaticRules != null) {
- for (ZenModeConfig.ZenRule automaticRule : config.automaticRules.values()) {
+ for (ZenRule automaticRule : config.automaticRules.values()) {
// don't restore transient state from restored automatic rules
automaticRule.snoozing = false;
automaticRule.condition = null;
@@ -318,36 +447,41 @@ public class ZenModeHelper {
}
private boolean setConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
- if (config == null || !config.isValid()) {
- Log.w(TAG, "Invalid config in setConfig; " + config);
- return false;
- }
- if (config.user != mUser) {
- // simply store away for background users
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (config == null || !config.isValid()) {
+ Log.w(TAG, "Invalid config in setConfig; " + config);
+ return false;
+ }
+ if (config.user != mUser) {
+ // simply store away for background users
+ mConfigs.put(config.user, config);
+ if (DEBUG) Log.d(TAG, "setConfig: store config for user " + config.user);
+ return true;
+ }
+ mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
mConfigs.put(config.user, config);
- if (DEBUG) Log.d(TAG, "setConfig: store config for user " + config.user);
+ if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
+ ZenLog.traceConfig(reason, mConfig, config);
+ final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
+ getNotificationPolicy(config));
+ mConfig = config;
+ if (config.equals(mConfig)) {
+ dispatchOnConfigChanged();
+ }
+ if (policyChanged){
+ dispatchOnPolicyChanged();
+ }
+ final String val = Integer.toString(mConfig.hashCode());
+ Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
+ if (!evaluateZenMode(reason, setRingerMode)) {
+ applyRestrictions(); // evaluateZenMode will also apply restrictions if changed
+ }
+ mConditions.evaluateConfig(config, true /*processSubscriptions*/);
return true;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
- mConfigs.put(config.user, config);
- if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
- ZenLog.traceConfig(reason, mConfig, config);
- final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
- getNotificationPolicy(config));
- mConfig = config;
- if (config.equals(mConfig)) {
- dispatchOnConfigChanged();
- }
- if (policyChanged){
- dispatchOnPolicyChanged();
- }
- final String val = Integer.toString(mConfig.hashCode());
- Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
- if (!evaluateZenMode(reason, setRingerMode)) {
- applyRestrictions(); // evaluateZenMode will also apply restrictions if changed
- }
- mConditions.evaluateConfig(config, true /*processSubscriptions*/);
- return true;
}
private int getZenModeSetting() {
@@ -505,6 +639,7 @@ public class ZenModeHelper {
.getString(R.string.zen_mode_default_weeknights_name);
rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
rule1.zenMode = Global.ZEN_MODE_ALARMS;
+ rule1.component = ScheduleConditionProvider.COMPONENT;
config.automaticRules.put(config.newRuleId(), rule1);
final ScheduleInfo weekends = new ScheduleInfo();
@@ -518,6 +653,7 @@ public class ZenModeHelper {
.getString(R.string.zen_mode_default_weekends_name);
rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends);
rule2.zenMode = Global.ZEN_MODE_ALARMS;
+ rule2.component = ScheduleConditionProvider.COMPONENT;
config.automaticRules.put(config.newRuleId(), rule2);
}
@@ -532,6 +668,7 @@ public class ZenModeHelper {
rule.name = mContext.getResources().getString(R.string.zen_mode_default_events_name);
rule.conditionId = ZenModeConfig.toEventConditionId(events);
rule.zenMode = Global.ZEN_MODE_ALARMS;
+ rule.component = EventConditionProvider.COMPONENT;
config.automaticRules.put(config.newRuleId(), rule);
}
@@ -572,6 +709,7 @@ public class ZenModeHelper {
rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule);
rule.zenMode = v1.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
: Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ rule.component = ScheduleConditionProvider.COMPONENT;
rt.automaticRules.put(rt.newRuleId(), rule);
} else {
Log.i(TAG, "No existing V1 downtime found, generating default schedules");
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index f292c9c4c3d8..d8676167497f 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -31,6 +31,21 @@ import com.android.server.SystemService;
public final class Installer extends SystemService {
private static final String TAG = "Installer";
+ /* ***************************************************************************
+ * IMPORTANT: These values are passed to native code. Keep them in sync with
+ * frameworks/native/cmds/installd/installd.h
+ * **************************************************************************/
+ /** Application should be visible to everyone */
+ public static final int DEXOPT_PUBLIC = 1 << 1;
+ /** Application wants to run in VM safe mode */
+ public static final int DEXOPT_SAFEMODE = 1 << 2;
+ /** Application wants to allow debugging of its code */
+ public static final int DEXOPT_DEBUGGABLE = 1 << 3;
+ /** The system boot has finished */
+ public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
+ /** Run the application with the JIT compiler */
+ public static final int DEXOPT_USEJIT = 1 << 5;
+
private final InstallerConnection mInstaller;
public Installer(Context context) {
@@ -75,39 +90,24 @@ public final class Installer extends SystemService {
return mInstaller.execute(builder.toString());
}
- public int dexopt(String apkPath, int uid, boolean isPublic,
- String instructionSet, int dexoptNeeded) {
- return dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded, true);
- }
-
- public int dexopt(String apkPath, int uid, boolean isPublic,
- String instructionSet, int dexoptNeeded, boolean bootComplete) {
+ public int dexopt(String apkPath, int uid, String instructionSet,
+ int dexoptNeeded, int dexFlags) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
- return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded,
- bootComplete);
- }
-
- public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
- String instructionSet, int dexoptNeeded, boolean vmSafeMode,
- boolean debuggable, @Nullable String outputPath) {
- return dexopt(apkPath, uid, isPublic, pkgName, instructionSet, dexoptNeeded, vmSafeMode,
- debuggable, outputPath, true);
+ return mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags);
}
- public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
- String instructionSet, int dexoptNeeded, boolean vmSafeMode,
- boolean debuggable, @Nullable String outputPath, boolean bootComplete) {
+ public int dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+ int dexoptNeeded, @Nullable String outputPath, int dexFlags) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
- return mInstaller.dexopt(apkPath, uid, isPublic, pkgName,
- instructionSet, dexoptNeeded, vmSafeMode,
- debuggable, outputPath, bootComplete);
+ return mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
+ outputPath, dexFlags);
}
public int idmap(String targetApkPath, String overlayApkPath, int uid) {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index b692def44153..6c6871fd8dfd 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -35,6 +35,11 @@ import java.util.List;
import dalvik.system.DexFile;
+import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;
+import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
+import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
+import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
+import static com.android.server.pm.Installer.DEXOPT_USEJIT;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -71,7 +76,8 @@ final class PackageDexOptimizer {
* {@link PackageManagerService#mInstallLock}.
*/
int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
- boolean forceDex, boolean defer, boolean inclDependencies, boolean bootComplete) {
+ boolean forceDex, boolean defer, boolean inclDependencies,
+ boolean bootComplete, boolean useJit) {
ArraySet<String> done;
if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
done = new ArraySet<String>();
@@ -86,7 +92,8 @@ final class PackageDexOptimizer {
mDexoptWakeLock.acquire();
}
try {
- return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete, done);
+ return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete,
+ useJit, done);
} finally {
if (useLock) {
mDexoptWakeLock.release();
@@ -96,7 +103,8 @@ final class PackageDexOptimizer {
}
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
- boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) {
+ boolean forceDex, boolean defer, boolean bootComplete, boolean useJit,
+ ArraySet<String> done) {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
@@ -104,11 +112,11 @@ final class PackageDexOptimizer {
done.add(pkg.packageName);
if (pkg.usesLibraries != null) {
performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer,
- bootComplete, done);
+ bootComplete, useJit, done);
}
if (pkg.usesOptionalLibraries != null) {
performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer,
- bootComplete, done);
+ bootComplete, useJit, done);
}
}
@@ -175,11 +183,17 @@ final class PackageDexOptimizer {
Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
+ pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+ " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
- + " oatDir = " + oatDir + " bootComplete=" + bootComplete);
+ + " oatDir = " + oatDir + " bootComplete=" + bootComplete
+ + " useJit=" + useJit);
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ final int dexFlags =
+ (!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0)
+ | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
+ | (debuggable ? DEXOPT_DEBUGGABLE : 0)
+ | (bootComplete ? DEXOPT_BOOTCOMPLETE : 0)
+ | (useJit ? DEXOPT_USEJIT : 0);
final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
- !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
- dexoptNeeded, vmSafeMode, debuggable, oatDir, bootComplete);
+ pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir, dexFlags);
// Dex2oat might fail due to compiler / verifier errors. We soldier on
// regardless, and attempt to interpret the app as a safety net.
@@ -236,12 +250,13 @@ final class PackageDexOptimizer {
}
private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
- boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) {
+ boolean forceDex, boolean defer, boolean bootComplete, boolean useJit,
+ ArraySet<String> done) {
for (String libName : libs) {
PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
libName);
if (libPkg != null && !done.contains(libName)) {
- performDexOptLI(libPkg, instructionSets, forceDex, defer, bootComplete, done);
+ performDexOptLI(libPkg, instructionSets, forceDex, defer, bootComplete, useJit, done);
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0366fff4eee9..cf09b846ad4e 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -140,6 +140,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
private static final String ATTR_APP_ICON = "appIcon";
private static final String ATTR_APP_LABEL = "appLabel";
private static final String ATTR_ORIGINATING_URI = "originatingUri";
+ private static final String ATTR_ORIGINATING_UID = "originatingUid";
private static final String ATTR_REFERRER_URI = "referrerUri";
private static final String ATTR_ABI_OVERRIDE = "abiOverride";
private static final String ATTR_VOLUME_UUID = "volumeUuid";
@@ -405,6 +406,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
+ params.originatingUid =
+ readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
@@ -477,6 +480,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
+ writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4a473fd42741..a441cb2e511b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -222,11 +222,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// waived if the installer is the device owner.
DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
Context.DEVICE_POLICY_SERVICE);
+ final boolean isPermissionGranted =
+ (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
+ == PackageManager.PERMISSION_GRANTED);
+ final boolean isInstallerRoot = (installerUid == Process.ROOT_UID);
+ final boolean forcePermissionPrompt =
+ (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(installerPackageName);
- if ((mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
- == PackageManager.PERMISSION_GRANTED)
- || (installerUid == Process.ROOT_UID)
- || mIsInstallerDeviceOwner) {
+ if ((isPermissionGranted
+ || isInstallerRoot
+ || mIsInstallerDeviceOwner)
+ && !forcePermissionPrompt) {
mPermissionsAccepted = true;
} else {
mPermissionsAccepted = false;
@@ -955,7 +961,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (accepted) {
// Mark and kick off another install pass
- mPermissionsAccepted = true;
+ synchronized (mLock) {
+ mPermissionsAccepted = true;
+ }
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
} else {
destroyInternal();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 17a3f56a1bf6..2009ccf797ab 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -75,6 +75,7 @@ import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.ArrayUtils.appendInt;
+import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -2015,7 +2016,8 @@ public class PackageManagerService extends IPackageManager.Stub {
int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
alreadyDexOpted.add(lib);
- mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false);
+ mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
+ dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
@@ -2063,7 +2065,8 @@ public class PackageManagerService extends IPackageManager.Stub {
try {
int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
- mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false);
+ mInstaller.dexopt(path, Process.SYSTEM_UID, dexCodeInstructionSet,
+ dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
@@ -6248,7 +6251,7 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mInstallLock) {
mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */,
false /* force dex */, false /* defer */, true /* include dependencies */,
- false /* boot complete */);
+ false /* boot complete */, false /*useJit*/);
}
}
@@ -6308,7 +6311,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final String[] instructionSets = new String[] { targetInstructionSet };
int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
false /* forceDex */, false /* defer */, true /* inclDependencies */,
- true /* boot complete */);
+ true /* boot complete */, false /*useJit*/);
return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
}
} finally {
@@ -6359,7 +6362,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
true /*forceDex*/, false /* defer */, true /* inclDependencies */,
- true /* boot complete */);
+ true /* boot complete */, false /*useJit*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -7176,7 +7179,7 @@ public class PackageManagerService extends IPackageManager.Stub {
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */,
- (scanFlags & SCAN_BOOTING) == 0);
+ (scanFlags & SCAN_BOOTING) == 0, false /*useJit*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
@@ -7257,7 +7260,7 @@ public class PackageManagerService extends IPackageManager.Stub {
int result = mPackageDexOptimizer.performDexOpt(clientPkg,
null /* instruction sets */, forceDex,
(scanFlags & SCAN_DEFER_DEX) != 0, false,
- (scanFlags & SCAN_BOOTING) == 0);
+ (scanFlags & SCAN_BOOTING) == 0, false /*useJit*/);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
"scanPackageLI failed to dexopt clientLibPkgs");
@@ -7881,7 +7884,7 @@ public class PackageManagerService extends IPackageManager.Stub {
int result = mPackageDexOptimizer.performDexOpt(ps.pkg,
null /* instruction sets */, forceDexOpt, deferDexOpt, true,
- bootComplete);
+ bootComplete, false /*useJit*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
@@ -9683,7 +9686,8 @@ public class PackageManagerService extends IPackageManager.Stub {
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user) {
final VerificationParams verifParams = new VerificationParams(
- null, sessionParams.originatingUri, sessionParams.referrerUri, installerUid, null);
+ null, sessionParams.originatingUri, sessionParams.referrerUri,
+ sessionParams.originatingUid, null);
verifParams.setInstallerUid(installerUid);
final OriginInfo origin;
@@ -12572,8 +12576,7 @@ public class PackageManagerService extends IPackageManager.Stub {
int result = mPackageDexOptimizer
.performDexOpt(pkg, null /* instruction sets */, false /* forceDex */,
false /* defer */, false /* inclDependencies */,
- true /* boot complete */);
-
+ true /*bootComplete*/, false /*useJit*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1924bab6fac6..6386a916d518 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -16,9 +16,11 @@
package com.android.server.pm;
+import android.accounts.Account;
import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
import android.app.IStopUserCallback;
import android.app.admin.DevicePolicyManager;
@@ -63,6 +65,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.server.LocalServices;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -129,7 +132,7 @@ public class UserManagerService extends IUserManager.Stub {
private static final int MIN_USER_ID = 10;
- private static final int USER_VERSION = 5;
+ private static final int USER_VERSION = 6;
private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
@@ -240,13 +243,15 @@ public class UserManagerService extends IUserManager.Stub {
synchronized (mPackagesLock) {
// Prune out any partially created/partially removed users.
ArrayList<UserInfo> partials = new ArrayList<UserInfo>();
- for (int i = 0; i < mUsers.size(); i++) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
UserInfo ui = mUsers.valueAt(i);
if ((ui.partial || ui.guestToRemove) && i != 0) {
partials.add(ui);
}
}
- for (int i = 0; i < partials.size(); i++) {
+ final int partialsSize = partials.size();
+ for (int i = 0; i < partialsSize; i++) {
UserInfo ui = partials.get(i);
Slog.w(LOG_TAG, "Removing partially created user " + ui.id
+ " (name=" + ui.name + ")");
@@ -270,7 +275,8 @@ public class UserManagerService extends IUserManager.Stub {
public UserInfo getPrimaryUser() {
checkManageUsersPermission("query users");
synchronized (mPackagesLock) {
- for (int i = 0; i < mUsers.size(); i++) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
UserInfo ui = mUsers.valueAt(i);
if (ui.isPrimary()) {
return ui;
@@ -285,7 +291,8 @@ public class UserManagerService extends IUserManager.Stub {
checkManageUsersPermission("query users");
synchronized (mPackagesLock) {
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
- for (int i = 0; i < mUsers.size(); i++) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
UserInfo ui = mUsers.valueAt(i);
if (ui.partial) {
continue;
@@ -321,7 +328,8 @@ public class UserManagerService extends IUserManager.Stub {
// Probably a dying user
return users;
}
- for (int i = 0; i < mUsers.size(); i++) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
UserInfo profile = mUsers.valueAt(i);
if (!isProfileOf(user, profile)) {
continue;
@@ -406,6 +414,24 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ @Override
+ public boolean canHaveRestrictedProfile(int userId) {
+ checkManageUsersPermission("canHaveRestrictedProfile");
+ synchronized (mPackagesLock) {
+ final UserInfo userInfo = getUserInfoLocked(userId);
+ if (userInfo == null || !userInfo.canHaveProfile()) {
+ return false;
+ }
+ if (!userInfo.isAdmin()) {
+ return false;
+ }
+ }
+ DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ // restricted profile can be created if there is no DO set and the admin user has no PO
+ return dpm.getDeviceOwner() == null && dpm.getProfileOwnerAsUser(userId) == null;
+ }
+
/*
* Should be locked on mUsers before calling this.
*/
@@ -846,6 +872,20 @@ public class UserManagerService extends IUserManager.Stub {
userVersion = 5;
}
+ if (userVersion < 6) {
+ final boolean splitSystemUser = UserManager.isSplitSystemUser();
+ for (int i = 0; i < mUsers.size(); i++) {
+ UserInfo user = mUsers.valueAt(i);
+ // In non-split mode, only user 0 can have restricted profiles
+ if (!splitSystemUser && user.isRestricted()
+ && (user.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID)) {
+ user.restrictedProfileParentId = UserHandle.USER_SYSTEM;
+ scheduleWriteUserLocked(user);
+ }
+ }
+ userVersion = 6;
+ }
+
if (userVersion < USER_VERSION) {
Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
+ USER_VERSION);
@@ -976,7 +1016,8 @@ public class UserManagerService extends IUserManager.Stub {
serializer.startTag(null, TAG_GUEST_RESTRICTIONS);
writeRestrictionsLocked(serializer, mGuestRestrictions);
serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
- for (int i = 0; i < mUsers.size(); i++) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
UserInfo user = mUsers.valueAt(i);
serializer.startTag(null, TAG_USER);
serializer.attribute(null, ATTR_ID, Integer.toString(user.id));
@@ -1386,6 +1427,25 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
+ * @hide
+ */
+ public UserInfo createRestrictedProfile(String name, int parentUserId) {
+ checkManageUsersPermission("setupRestrictedProfile");
+ final UserInfo user = createProfileForUser(name, UserInfo.FLAG_RESTRICTED, parentUserId);
+ if (user == null) {
+ return null;
+ }
+ setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
+ // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
+ // the putIntForUser() will fail.
+ android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ android.provider.Settings.Secure.LOCATION_MODE,
+ android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id);
+ setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id);
+ return user;
+ }
+
+ /**
* Find the current guest user. If the Guest user is partial,
* then do not include it in the results as it is about to die.
*/
@@ -1534,6 +1594,9 @@ public class UserManagerService extends IUserManager.Stub {
}
new Thread() {
public void run() {
+ // Clean up any ActivityManager state
+ LocalServices.getService(ActivityManagerInternal.class)
+ .onUserRemoved(userHandle);
synchronized (mInstallLock) {
synchronized (mPackagesLock) {
removeUserStateLocked(userHandle);
@@ -1898,14 +1961,15 @@ public class UserManagerService extends IUserManager.Stub {
*/
private void updateUserIdsLocked() {
int num = 0;
- for (int i = 0; i < mUsers.size(); i++) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
if (!mUsers.valueAt(i).partial) {
num++;
}
}
final int[] newUsers = new int[num];
int n = 0;
- for (int i = 0; i < mUsers.size(); i++) {
+ for (int i = 0; i < userSize; i++) {
if (!mUsers.valueAt(i).partial) {
newUsers[n++] = mUsers.keyAt(i);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index dbc3970cf4cf..c265000f13f5 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2105,6 +2105,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case TYPE_WALLPAPER:
// wallpaper is at the bottom, though the window manager may move it.
return 2;
+ case TYPE_DOCK_DIVIDER:
+ return 2;
case TYPE_PHONE:
return 3;
case TYPE_SEARCH_BAR:
@@ -2135,56 +2137,54 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case TYPE_INPUT_METHOD_DIALOG:
// on-screen keyboards and other such input method user interfaces go here.
return 13;
- case TYPE_DOCK_DIVIDER:
- return 14;
case TYPE_KEYGUARD_SCRIM:
// the safety window that shows behind keyguard while keyguard is starting
- return 15;
+ return 14;
case TYPE_STATUS_BAR_SUB_PANEL:
- return 16;
+ return 15;
case TYPE_STATUS_BAR:
- return 17;
+ return 16;
case TYPE_STATUS_BAR_PANEL:
- return 18;
+ return 17;
case TYPE_KEYGUARD_DIALOG:
- return 19;
+ return 18;
case TYPE_VOLUME_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
- return 20;
+ return 19;
case TYPE_SYSTEM_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
- return 21;
+ return 20;
case TYPE_NAVIGATION_BAR:
// the navigation bar, if available, shows atop most things
- return 22;
+ return 21;
case TYPE_NAVIGATION_BAR_PANEL:
// some panels (e.g. search) need to show on top of the navigation bar
- return 23;
+ return 22;
case TYPE_SYSTEM_ERROR:
// system-level error dialogs
- return 24;
+ return 23;
case TYPE_MAGNIFICATION_OVERLAY:
// used to highlight the magnified portion of a display
- return 25;
+ return 24;
case TYPE_DISPLAY_OVERLAY:
// used to simulate secondary display devices
- return 26;
+ return 25;
case TYPE_DRAG:
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
- return 27;
+ return 26;
case TYPE_ACCESSIBILITY_OVERLAY:
// overlay put by accessibility services to intercept user interaction
- return 28;
+ return 27;
case TYPE_SECURE_SYSTEM_OVERLAY:
- return 29;
+ return 28;
case TYPE_BOOT_PROGRESS:
- return 30;
+ return 29;
case TYPE_POINTER:
// the (mouse) pointer layer
- return 31;
+ return 30;
}
Log.e(TAG, "Unknown window type: " + type);
return 2;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 5d0193108891..25d646d2bb3b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -28,5 +28,5 @@ public interface StatusBarManagerInternal {
void showScreenPinningRequest();
void showAssistDisclosure();
void startAssist(Bundle args);
- void onCameraLaunchGestureDetected();
+ void onCameraLaunchGestureDetected(int source);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 11a16394a502..19b03d5e56cd 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -178,10 +178,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
@Override
- public void onCameraLaunchGestureDetected() {
+ public void onCameraLaunchGestureDetected(int source) {
if (mBar != null) {
try {
- mBar.onCameraLaunchGestureDetected();
+ mBar.onCameraLaunchGestureDetected(source);
} catch (RemoteException e) {
}
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 192b168122bd..cc51d204e98d 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1003,19 +1003,36 @@ public class AppTransition implements Dump {
return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
}
- private Animation createRelaunchAnimation(int appWidth, int appHeight) {
+ private Animation createRelaunchAnimation(int appWidth, int appHeight,
+ Rect containingFrame) {
getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
final int left = mTmpFromClipRect.left;
final int top = mTmpFromClipRect.top;
mTmpFromClipRect.offset(-left, -top);
mTmpToClipRect.set(0, 0, appWidth, appHeight);
AnimationSet set = new AnimationSet(true);
- ClipRectAnimation clip = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
- TranslateAnimation translate = new TranslateAnimation(left, 0, top, 0);
- clip.setInterpolator(mDecelerateInterpolator);
- set.addAnimation(clip);
+ float fromWidth = mTmpFromClipRect.width();
+ float toWidth = mTmpToClipRect.width();
+ float fromHeight = mTmpFromClipRect.height();
+ float toHeight = mTmpToClipRect.height();
+ if (fromWidth <= toWidth && fromHeight <= toHeight) {
+ // The final window is larger in both dimensions than current window (e.g. we are
+ // maximizing), so we can simply unclip the new window and there will be no disappearing
+ // frame.
+ set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect));
+ } else {
+ // The disappearing window has one larger dimension. We need to apply scaling, so the
+ // first frame of the entry animation matches the old window.
+ set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
+ }
+
+ // We might not be going exactly full screen, but instead be aligned under the status bar.
+ // We need to take this into account when creating the translate animation.
+ TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
+ 0, top - containingFrame.top, 0);
set.addAnimation(translate);
set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+ set.setZAdjustment(Animation.ZORDER_TOP);
return set;
}
@@ -1056,7 +1073,12 @@ public class AppTransition implements Dump {
+ " anim=" + a + " transit=" + appTransitionToString(transit)
+ " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
} else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
- a = createRelaunchAnimation(appWidth, appHeight);
+ a = createRelaunchAnimation(appWidth, appHeight, containingFrame);
+ if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+ "applyAnimation:"
+ + " anim=" + a + " nextAppTransition=" + mNextAppTransition
+ + " transit=" + appTransitionToString(transit)
+ + " Callers=" + Debug.getCallers(3));
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
a = loadAnimationRes(mNextAppTransitionPackage, enter ?
mNextAppTransitionEnter : mNextAppTransitionExit);
@@ -1077,6 +1099,7 @@ public class AppTransition implements Dump {
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
"applyAnimation:"
+ " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
+ + " transit=" + appTransitionToString(transit)
+ " Callers=" + Debug.getCallers(3));
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ff216c5c763d..5a1ed582358c 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -74,10 +74,6 @@ class AppWindowToken extends WindowToken {
// case do not clear allDrawn until the animation completes.
boolean deferClearAllDrawn;
- // Is this token going to be hidden in a little while? If so, it
- // won't be taken into account for setting the screen orientation.
- boolean willBeHidden;
-
// Is this window's surface needed? This is almost like hidden, except
// it will sometimes be true a little earlier: when the token has
// been shown, but is still waiting for its app transition to execute
@@ -321,7 +317,6 @@ class AppWindowToken extends WindowToken {
pw.print(" requestedOrientation="); pw.println(requestedOrientation);
pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
pw.print(" clientHidden="); pw.print(clientHidden);
- pw.print(" willBeHidden="); pw.print(willBeHidden);
pw.print(" reportedDrawn="); pw.print(reportedDrawn);
pw.print(" reportedVisible="); pw.println(reportedVisible);
if (paused) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ede377de0b14..6b5ecdc70a7b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -126,6 +126,7 @@ class DisplayContent {
display.getMetrics(mDisplayMetrics);
isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
mService = service;
+ initializeDisplayBaseInfo();
mDividerControllerLocked = new DockedStackDividerController(service.mContext, this);
}
@@ -192,6 +193,21 @@ class DisplayContent {
}
}
+ void initializeDisplayBaseInfo() {
+ synchronized(mDisplaySizeLock) {
+ // Bootstrap the default logical display from the display manager.
+ final DisplayInfo newDisplayInfo =
+ mService.mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+ if (newDisplayInfo != null) {
+ mDisplayInfo.copyFrom(newDisplayInfo);
+ }
+ mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth;
+ mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight;
+ mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
+ mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+ }
+ }
+
void getLogicalDisplayRect(Rect out) {
// Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
final int orientation = mDisplayInfo.rotation;
@@ -247,7 +263,7 @@ class DisplayContent {
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = tasks.get(taskNdx);
task.getBounds(mTmpRect);
- if (task.inFreeformWorkspace() && mTmpRect.contains(x, y)) {
+ if (mTmpRect.contains(x, y)) {
return task.mTaskId;
}
}
@@ -567,13 +583,8 @@ class DisplayContent {
return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
}
- TaskStack getDockedStack() {
- for (int i = mStacks.size() - 1; i >= 0; i--) {
- TaskStack stack = mStacks.get(i);
- if (stack.mStackId == DOCKED_STACK_ID) {
- return stack;
- }
- }
- return null;
+ TaskStack getDockedStackLocked() {
+ final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ return (stack != null && stack.isVisibleLocked()) ? stack : null;
}
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ad207d4b8939..8c5d319439ba 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.DOCKED_STACK_ID;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
@@ -23,11 +24,19 @@ import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static com.android.server.wm.TaskStack.DOCKED_BOTTOM;
+import static com.android.server.wm.TaskStack.DOCKED_INVALID;
+import static com.android.server.wm.TaskStack.DOCKED_LEFT;
+import static com.android.server.wm.TaskStack.DOCKED_RIGHT;
+import static com.android.server.wm.TaskStack.DOCKED_TOP;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.os.RemoteException;
+import android.util.Slog;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -35,13 +44,20 @@ import android.view.WindowManagerGlobal;
/**
* Controls showing and hiding of a docked stack divider on the display.
*/
-public class DockedStackDividerController {
+public class DockedStackDividerController implements View.OnTouchListener {
private static final String TAG = "DockedStackDivider";
private final Context mContext;
private final int mDividerWidth;
private final DisplayContent mDisplayContent;
private View mView;
private Rect mTmpRect = new Rect();
+ private Rect mLastResizeRect = new Rect();
+ private int mStartX;
+ private int mStartY;
+ private TaskStack mTaskStack;
+ private Rect mOriginalRect = new Rect();
+ private int mDockSide;
+
DockedStackDividerController(Context context, DisplayContent displayContent) {
mContext = context;
@@ -53,6 +69,7 @@ public class DockedStackDividerController {
private void addDivider() {
View view = LayoutInflater.from(mContext).inflate(
com.android.internal.R.layout.docked_stack_divider, null);
+ view.setOnTouchListener(this);
WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
mDividerWidth, MATCH_PARENT, TYPE_DOCK_DIVIDER,
@@ -65,6 +82,7 @@ public class DockedStackDividerController {
}
private void removeDivider() {
+ mView.setOnTouchListener(null);
WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
manager.removeView(mView, true /* immediate */);
mView = null;
@@ -75,7 +93,7 @@ public class DockedStackDividerController {
}
void update() {
- TaskStack stack = mDisplayContent.getDockedStack();
+ TaskStack stack = mDisplayContent.getDockedStackLocked();
if (stack != null && mView == null) {
addDivider();
} else if (stack == null && mView != null) {
@@ -87,9 +105,8 @@ public class DockedStackDividerController {
return mDividerWidth;
}
-
void positionDockedStackedDivider(Rect frame) {
- TaskStack stack = mDisplayContent.getDockedStack();
+ TaskStack stack = mDisplayContent.getDockedStackLocked();
if (stack == null) {
// Unfortunately we might end up with still having a divider, even though the underlying
// stack was already removed. This is because we are on AM thread and the removal of the
@@ -99,19 +116,84 @@ public class DockedStackDividerController {
final @TaskStack.DockSide int side = stack.getDockSide();
stack.getBounds(mTmpRect);
switch (side) {
- case TaskStack.DOCKED_LEFT:
+ case DOCKED_LEFT:
frame.set(mTmpRect.right, frame.top, mTmpRect.right + frame.width(), frame.bottom);
break;
- case TaskStack.DOCKED_TOP:
+ case DOCKED_TOP:
frame.set(frame.left, mTmpRect.bottom, mTmpRect.right,
mTmpRect.bottom + frame.height());
break;
- case TaskStack.DOCKED_RIGHT:
+ case DOCKED_RIGHT:
frame.set(mTmpRect.left - frame.width(), frame.top, mTmpRect.left, frame.bottom);
break;
- case TaskStack.DOCKED_BOTTOM:
+ case DOCKED_BOTTOM:
frame.set(frame.left, mTmpRect.top - frame.height(), frame.right, mTmpRect.top);
break;
}
}
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ final int action = event.getAction() & MotionEvent.ACTION_MASK;
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ // We use raw values, because getX/Y() would give us results relative to the
+ // dock divider bounds.
+ mStartX = (int) event.getRawX();
+ mStartY = (int) event.getRawY();
+ synchronized (mDisplayContent.mService.mWindowMap) {
+ mTaskStack = mDisplayContent.getDockedStackLocked();
+ mTaskStack.getBounds(mOriginalRect);
+ mDockSide = mTaskStack.getDockSide();
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (mTaskStack != null) {
+ resizeStack(event);
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mTaskStack = null;
+ mDockSide = TaskStack.DOCKED_INVALID;
+ break;
+ }
+ return true;
+ }
+
+ private void resizeStack(MotionEvent event) {
+ mTmpRect.set(mOriginalRect);
+ final int deltaX = (int) event.getRawX() - mStartX;
+ final int deltaY = (int) event.getRawY() - mStartY;
+ switch (mDockSide) {
+ case DOCKED_LEFT:
+ mTmpRect.right += deltaX;
+ break;
+ case DOCKED_TOP:
+ mTmpRect.bottom += deltaY;
+ break;
+ case DOCKED_RIGHT:
+ mTmpRect.left += deltaX;
+ break;
+ case DOCKED_BOTTOM:
+ mTmpRect.top += deltaY;
+ break;
+ }
+ if (mTmpRect.equals(mLastResizeRect)) {
+ return;
+ }
+ mLastResizeRect.set(mTmpRect);
+ try {
+ mDisplayContent.mService.mActivityManager.resizeStack(DOCKED_STACK_ID, mTmpRect);
+ } catch (RemoteException e) {
+ }
+ }
+
+ boolean isResizing() {
+ return mTaskStack != null;
+ }
+
+ int getWidthAdjustment() {
+ return getWidth() / 2;
+ }
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 4244205aabf8..6c391ade60cc 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
import android.app.ActivityManagerNative;
import android.graphics.Rect;
@@ -170,7 +171,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
private void addInputWindowHandleLw(final InputWindowHandle inputWindowHandle,
final WindowState child, int flags, final int type, final boolean isVisible,
- final boolean hasFocus, final boolean hasWallpaper) {
+ final boolean hasFocus, final boolean hasWallpaper, DisplayContent displayContent) {
// Add a window to our list of input windows.
inputWindowHandle.name = child.toString();
final boolean modal = (flags & (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -202,6 +203,20 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
inputWindowHandle.frameTop = frame.top;
inputWindowHandle.frameRight = frame.right;
inputWindowHandle.frameBottom = frame.bottom;
+ if (child.mAttrs.type == TYPE_DOCK_DIVIDER) {
+ // We need to determine if the divider is horizontal or vertical and adjust its handle
+ // frame accordingly.
+ int adjustment = displayContent.mDividerControllerLocked.getWidthAdjustment();
+ if (inputWindowHandle.frameRight - inputWindowHandle.frameLeft >
+ inputWindowHandle.frameTop - inputWindowHandle.frameBottom) {
+ // Horizontal divider.
+ inputWindowHandle.frameTop -= adjustment;
+ inputWindowHandle.frameBottom += adjustment;
+ } else {
+ inputWindowHandle.frameLeft -= adjustment;
+ inputWindowHandle.frameRight += adjustment;
+ }
+ }
if (child.mGlobalScale != 1) {
// If we are scaling the window, input coordinates need
@@ -277,7 +292,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
final int numDisplays = mService.mDisplayContents.size();
final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList();
+ final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
+ final WindowList windows = displayContent.getWindowList();
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState child = windows.get(winNdx);
final InputChannel inputChannel = child.mInputChannel;
@@ -315,7 +331,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
}
addInputWindowHandleLw(inputWindowHandle, child, flags, type, isVisible, hasFocus,
- hasWallpaper);
+ hasWallpaper, displayContent);
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d1111f70346a..1f986dd90b10 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -17,9 +17,11 @@
package com.android.server.wm;
import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
import static com.android.server.wm.WindowManagerService.TAG;
import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import android.content.res.Configuration;
@@ -245,8 +247,32 @@ class Task implements DimLayer.DimLayerUser {
return true;
}
+ /** Return true if the current bound can get outputted to the rest of the system as-is. */
+ private boolean useCurrentBounds() {
+ final DisplayContent displayContent = mStack.getDisplayContent();
+ if (mFullscreen
+ || mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID
+ || mStack.mStackId == DOCKED_STACK_ID
+ || displayContent == null
+ || displayContent.getDockedStackLocked() != null) {
+ return true;
+ }
+ return false;
+ }
+
+ /** Bounds of the task with other system factors taken into consideration. */
void getBounds(Rect out) {
- out.set(mBounds);
+ if (useCurrentBounds()) {
+ // No need to adjust the output bounds if fullscreen or the docked stack is visible
+ // since it is already what we want to represent to the rest of the system.
+ out.set(mBounds);
+ return;
+ }
+
+ // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
+ // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+ // system.
+ mStack.getDisplayContent().getLogicalDisplayRect(out);
}
void setDragResizing(boolean dragResizing) {
@@ -274,7 +300,13 @@ class Task implements DimLayer.DimLayerUser {
// this happens, so update the task bounds so it stays in the same place.
mTmpRect2.set(mBounds);
displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
- setBounds(mTmpRect2, mOverrideConfig);
+ if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
+ // Post message to inform activity manager of the bounds change simulating
+ // a one-way call. We do this to prevent a deadlock between window manager
+ // lock and activity manager lock been held.
+ mService.mH.sendMessage(mService.mH.obtainMessage(
+ RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds));
+ }
}
/** Updates the dim layer bounds, recreating it if needed. */
@@ -433,10 +465,6 @@ class Task implements DimLayer.DimLayerUser {
return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
}
- boolean inDockedWorkspace() {
- return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
- }
-
WindowState getTopAppMainWindow() {
final int tokensCount = mAppTokens.size();
return tokensCount > 0 ? mAppTokens.get(tokensCount - 1).findMainWindow() : null;
@@ -444,7 +472,13 @@ class Task implements DimLayer.DimLayerUser {
@Override
public boolean isFullscreen() {
- return mFullscreen;
+ if (useCurrentBounds()) {
+ return mFullscreen;
+ }
+ // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
+ // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+ // system.
+ return true;
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index d1904d80ebc5..9da7406e8d3c 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -19,9 +19,10 @@ package com.android.server.wm;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.RESIZE_MODE_FORCED;
import static android.app.ActivityManager.RESIZE_MODE_USER;
+import static android.app.ActivityManager.RESIZE_MODE_USER_FORCED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static com.android.server.wm.WindowManagerService.DEBUG_TASK_POSITIONING;
import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
@@ -33,6 +34,7 @@ import android.graphics.Rect;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
+import android.os.Trace;
import android.util.DisplayMetrics;
import android.util.Slog;
import android.view.Choreographer;
@@ -145,10 +147,12 @@ class TaskPositioner implements DimLayer.DimLayerUser {
synchronized (mService.mWindowMap) {
mDragEnded = notifyMoveLocked(newX, newY);
}
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.TaskPositioner.resizeTask");
try {
mService.mActivityManager.resizeTask(
mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
} catch(RemoteException e) {}
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
} break;
case MotionEvent.ACTION_UP: {
@@ -175,7 +179,7 @@ class TaskPositioner implements DimLayer.DimLayerUser {
// We were using fullscreen surface during resizing. Request
// resizeTask() one last time to restore surface to window size.
mService.mActivityManager.resizeTask(
- mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_FORCED);
+ mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED);
}
if (mCurrentDimSide != CTRL_NONE) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 96fcf93b5981..f030b9a23e64 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -18,13 +18,13 @@ package com.android.server.wm;
import static android.app.ActivityManager.*;
import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT;
+import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
import static com.android.server.wm.WindowManagerService.TAG;
import android.annotation.IntDef;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Debug;
-import android.os.RemoteException;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -58,7 +58,7 @@ public class TaskStack implements DimLayer.DimLayerUser {
/** For comparison with DisplayContent bounds. */
private Rect mTmpRect = new Rect();
- private Rect TmpRect2 = new Rect();
+ private Rect mTmpRect2 = new Rect();
/** Content limits relative to the DisplayContent this sits in. */
private Rect mBounds = new Rect();
@@ -86,6 +86,7 @@ public class TaskStack implements DimLayer.DimLayerUser {
static final int DOCKED_TOP = 2;
static final int DOCKED_RIGHT = 3;
static final int DOCKED_BOTTOM = 4;
+
@IntDef({
DOCKED_INVALID,
DOCKED_LEFT,
@@ -180,24 +181,60 @@ public class TaskStack implements DimLayer.DimLayerUser {
return true;
}
- void getBounds(Rect out) {
+ /** Bounds of the stack without adjusting for other factors in the system like visibility
+ * of docked stack.
+ * Most callers should be using {@link #getBounds} as it take into consideration other system
+ * factors. */
+ void getRawBounds(Rect out) {
out.set(mBounds);
}
+ /** Return true if the current bound can get outputted to the rest of the system as-is. */
+ private boolean useCurrentBounds() {
+ if (mFullscreen
+ || mStackId == DOCKED_STACK_ID
+ || mDisplayContent == null
+ || mDisplayContent.getDockedStackLocked() != null) {
+ return true;
+ }
+ return false;
+ }
+
+ /** Bounds of the stack with other system factors taken into consideration. */
+ void getBounds(Rect out) {
+ if (useCurrentBounds()) {
+ // No need to adjust the output bounds if fullscreen or the docked stack is visible
+ // since it is already what we want to represent to the rest of the system.
+ out.set(mBounds);
+ return;
+ }
+
+ // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
+ // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+ // system.
+ mDisplayContent.getLogicalDisplayRect(out);
+ }
+
void updateDisplayInfo(Rect bounds) {
if (mDisplayContent != null) {
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
+ }
if (bounds != null) {
setBounds(bounds);
} else if (mFullscreen) {
setBounds(null);
} else {
- TmpRect2.set(mBounds);
+ mTmpRect2.set(mBounds);
mDisplayContent.rotateBounds(
- mRotation, mDisplayContent.getDisplayInfo().rotation, TmpRect2);
- setBounds(TmpRect2);
- }
- for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
- mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
+ mRotation, mDisplayContent.getDisplayInfo().rotation, mTmpRect2);
+ if (setBounds(mTmpRect2)) {
+ // Post message to inform activity manager of the bounds change simulating
+ // a one-way call. We do this to prevent a deadlock between window manager
+ // lock and activity manager lock been held.
+ mService.mH.sendMessage(
+ mService.mH.obtainMessage(RESIZE_STACK, mStackId, -1, mBounds));
+ }
}
}
}
@@ -345,15 +382,19 @@ public class TaskStack implements DimLayer.DimLayerUser {
mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId());
Rect bounds = null;
- final boolean dockedStackExists = mService.mStackIdToStack.get(DOCKED_STACK_ID) != null;
- if (mStackId == DOCKED_STACK_ID || (dockedStackExists
+ final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ if (mStackId == DOCKED_STACK_ID || (dockedStack != null
&& mStackId >= FIRST_STATIC_STACK_ID && mStackId <= LAST_STATIC_STACK_ID)) {
// The existence of a docked stack affects the size of any static stack created since
// the docked stack occupies a dedicated region on screen.
bounds = new Rect();
displayContent.getLogicalDisplayRect(mTmpRect);
- getInitialDockedStackBounds(mTmpRect, bounds, mStackId,
- mDisplayContent.mDividerControllerLocked.getWidth() / 2);
+ mTmpRect2.setEmpty();
+ if (dockedStack != null) {
+ dockedStack.getRawBounds(mTmpRect2);
+ }
+ getInitialDockedStackBounds(mTmpRect, bounds, mStackId, mTmpRect2,
+ mDisplayContent.mDividerControllerLocked.getWidthAdjustment());
}
updateDisplayInfo(bounds);
@@ -362,7 +403,7 @@ public class TaskStack implements DimLayer.DimLayerUser {
// Attaching a docked stack to the display affects the size of all other static
// stacks since the docked stack occupies a dedicated region on screen.
// Resize existing static stacks so they are pushed to the side of the docked stack.
- resizeNonDockedStacks(!FULLSCREEN);
+ resizeNonDockedStacks(!FULLSCREEN, mBounds);
}
}
@@ -372,29 +413,49 @@ public class TaskStack implements DimLayer.DimLayerUser {
* @param displayRect The bounds of the display the docked stack is on.
* @param outBounds Output bounds that should be used for the stack.
* @param stackId Id of stack we are calculating the bounds for.
+ * @param dockedBounds Bounds of the docked stack.
* @param adjustment
*/
- private static void getInitialDockedStackBounds(Rect displayRect, Rect outBounds, int stackId,
- int adjustment) {
- // Docked stack start off occupying half the screen space.
+ private static void getInitialDockedStackBounds(
+ Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int adjustment) {
final boolean dockedStack = stackId == DOCKED_STACK_ID;
final boolean splitHorizontally = displayRect.width() > displayRect.height();
final boolean topOrLeftCreateMode =
WindowManagerService.sDockedStackCreateMode == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
- final boolean placeTopOrLeft = (dockedStack && topOrLeftCreateMode)
- || (!dockedStack && !topOrLeftCreateMode);
+
outBounds.set(displayRect);
- if (placeTopOrLeft) {
+ if (dockedStack) {
+ // The initial bounds of the docked stack when it is created half the screen space and
+ // its bounds can be adjusted after that. The bounds of all other stacks are adjusted
+ // to occupy whatever screen space the docked stack isn't occupying.
+ if (topOrLeftCreateMode) {
+ if (splitHorizontally) {
+ outBounds.right = displayRect.centerX() - adjustment;
+ } else {
+ outBounds.bottom = displayRect.centerY() - adjustment;
+ }
+ } else {
+ if (splitHorizontally) {
+ outBounds.left = displayRect.centerX() + adjustment;
+ } else {
+ outBounds.top = displayRect.centerY() + adjustment;
+ }
+ }
+ return;
+ }
+
+ // Other stacks occupy whatever space is left by the docked stack.
+ if (!topOrLeftCreateMode) {
if (splitHorizontally) {
- outBounds.right = displayRect.centerX() - adjustment;
+ outBounds.right = dockedBounds.left - adjustment;
} else {
- outBounds.bottom = displayRect.centerY() - adjustment;
+ outBounds.bottom = dockedBounds.top - adjustment;
}
} else {
if (splitHorizontally) {
- outBounds.left = displayRect.centerX() + adjustment;
+ outBounds.left = dockedBounds.right + adjustment;
} else {
- outBounds.top = displayRect.centerY() + adjustment;
+ outBounds.top = dockedBounds.bottom + adjustment;
}
}
}
@@ -403,11 +464,14 @@ public class TaskStack implements DimLayer.DimLayerUser {
* based on the presence of a docked stack.
* @param fullscreen If true the stacks will be resized to fullscreen, else they will be
* resized to the appropriate size based on the presence of a docked stack.
+ * @param dockedBounds Bounds of the docked stack.
*/
- private void resizeNonDockedStacks(boolean fullscreen) {
- mDisplayContent.getLogicalDisplayRect(mTmpRect);
+ private void resizeNonDockedStacks(boolean fullscreen, Rect dockedBounds) {
+ // Not using mTmpRect because we are posting the object in a message.
+ final Rect bounds = new Rect();
+ mDisplayContent.getLogicalDisplayRect(bounds);
if (!fullscreen) {
- getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID,
+ getInitialDockedStackBounds(bounds, bounds, FULLSCREEN_WORKSPACE_STACK_ID, dockedBounds,
mDisplayContent.mDividerControllerLocked.getWidth());
}
@@ -418,11 +482,8 @@ public class TaskStack implements DimLayer.DimLayerUser {
if (otherStackId != DOCKED_STACK_ID
&& otherStackId >= FIRST_STATIC_STACK_ID
&& otherStackId <= LAST_STATIC_STACK_ID) {
- try {
- mService.mActivityManager.resizeStack(otherStackId, mTmpRect);
- } catch (RemoteException e) {
- // This will not happen since we are in the same process.
- }
+ mService.mH.sendMessage(
+ mService.mH.obtainMessage(RESIZE_STACK, otherStackId, -1, bounds));
}
}
}
@@ -438,8 +499,7 @@ public class TaskStack implements DimLayer.DimLayerUser {
for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
// We are in the middle of changing the state of displays/stacks/tasks. We need
// to finish that, before we let layout interfere with it.
- mService.removeWindowInnerLocked(appWindows.get(winNdx),
- false /* performLayout */);
+ mService.removeWindowLocked(appWindows.get(winNdx));
doAnotherLayoutPass = true;
}
}
@@ -451,7 +511,7 @@ public class TaskStack implements DimLayer.DimLayerUser {
if (mStackId == DOCKED_STACK_ID) {
// Docked stack was detached from the display, so we no longer need to restrict the
// region of the screen other static stacks occupy. Go ahead and make them fullscreen.
- resizeNonDockedStacks(FULLSCREEN);
+ resizeNonDockedStacks(FULLSCREEN, null);
}
close();
@@ -520,9 +580,23 @@ public class TaskStack implements DimLayer.DimLayerUser {
}
}
+ /** Fullscreen status of the stack without adjusting for other factors in the system like
+ * visibility of docked stack.
+ * Most callers should be using {@link #isFullscreen} as it take into consideration other
+ * system factors. */
+ boolean getRawFullscreen() {
+ return mFullscreen;
+ }
+
@Override
public boolean isFullscreen() {
- return mFullscreen;
+ if (useCurrentBounds()) {
+ return mFullscreen;
+ }
+ // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
+ // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+ // system.
+ return true;
}
@Override
@@ -566,4 +640,16 @@ public class TaskStack implements DimLayer.DimLayerUser {
return DOCKED_INVALID;
}
}
+
+ boolean isVisibleLocked() {
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ Task task = mTasks.get(i);
+ for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
+ if (!task.mAppTokens.get(j).hidden) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 22f9f50fe6dd..74572cfcdee2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -221,6 +222,7 @@ public class WindowManagerService extends IWindowManager.Stub
static final boolean HIDE_STACK_CRAWLS = true;
static final int LAYOUT_REPEAT_THRESHOLD = 4;
+
static final boolean PROFILE_ORIENTATION = false;
static final boolean localLOGV = DEBUG;
@@ -1894,13 +1896,13 @@ public class WindowManagerService extends IWindowManager.Stub
return res;
}
- if (outInputChannel != null && (attrs.inputFeatures
- & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
+ final boolean openInputChannels = (outInputChannel != null
+ && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
+ if (openInputChannels) {
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
-
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
@@ -2174,10 +2176,7 @@ public class WindowManagerService extends IWindowManager.Stub
// The exit animation is running... wait for it!
win.mExiting = true;
win.mRemoveOnExit = true;
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- displayContent.layoutNeeded = true;
- }
+ win.setDisplayLayoutNeeded();
final boolean focusChanged = updateFocusedWindowLocked(
UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
mWindowPlacerLocked.performSurfacePlacement();
@@ -2206,7 +2205,7 @@ public class WindowManagerService extends IWindowManager.Stub
removeWindowInnerLocked(win, true);
}
- void removeWindowInnerLocked(WindowState win, boolean performLayout) {
+ private void removeWindowInnerLocked(WindowState win, boolean performLayout) {
if (win.mRemoved) {
// Nothing to do.
return;
@@ -2300,10 +2299,7 @@ public class WindowManagerService extends IWindowManager.Stub
windows.remove(win);
if (!mWindowPlacerLocked.isInLayout()) {
assignLayersLocked(windows);
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- displayContent.layoutNeeded = true;
- }
+ win.setDisplayLayoutNeeded();
if (performLayout) {
mWindowPlacerLocked.performSurfacePlacement();
}
@@ -2385,10 +2381,7 @@ public class WindowManagerService extends IWindowManager.Stub
w.mGivenVisibleInsets.scale(w.mGlobalScale);
w.mGivenTouchableRegion.scale(w.mGlobalScale);
}
- final DisplayContent displayContent = w.getDisplayContent();
- if (displayContent != null) {
- displayContent.layoutNeeded = true;
- }
+ w.setDisplayLayoutNeeded();
mWindowPlacerLocked.performSurfacePlacement();
}
}
@@ -2730,10 +2723,7 @@ public class WindowManagerService extends IWindowManager.Stub
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- displayContent.layoutNeeded = true;
- }
+ win.setDisplayLayoutNeeded();
win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
configChanged = updateOrientationFromAppTokensLocked(false);
mWindowPlacerLocked.performSurfacePlacement();
@@ -2826,10 +2816,7 @@ public class WindowManagerService extends IWindowManager.Stub
getDefaultDisplayContentLocked().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- displayContent.layoutNeeded = true;
- }
+ win.setDisplayLayoutNeeded();
mWindowPlacerLocked.requestTraversal();
}
}
@@ -3268,8 +3255,7 @@ public class WindowManagerService extends IWindowManager.Stub
// if we're about to tear down this window and not seek for
// the behind activity, don't use it for orientation
- if (!findingBehind
- && (!atoken.hidden && atoken.hiddenRequested)) {
+ if (!findingBehind && !atoken.hidden && atoken.hiddenRequested) {
if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
+ " -- going to hide");
continue;
@@ -3290,7 +3276,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
// We ignore any hidden applications on the top.
- if (atoken.hiddenRequested || atoken.willBeHidden) {
+ if (atoken.hiddenRequested) {
if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
+ " -- hidden on top");
continue;
@@ -3786,7 +3772,6 @@ public class WindowManagerService extends IWindowManager.Stub
if (!ttoken.hidden) {
wtoken.hidden = false;
wtoken.hiddenRequested = false;
- wtoken.willBeHidden = false;
}
if (wtoken.clientHidden != ttoken.clientHidden) {
wtoken.clientHidden = ttoken.clientHidden;
@@ -3842,25 +3827,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- @Override
- public void setAppWillBeHidden(IBinder token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppWillBeHidden()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- AppWindowToken wtoken;
-
- synchronized(mWindowMap) {
- wtoken = findAppWindowToken(token);
- if (wtoken == null) {
- Slog.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
- return;
- }
- wtoken.willBeHidden = true;
- }
- }
-
public void setAppFullscreen(IBinder token, boolean toOpaque) {
synchronized (mWindowMap) {
AppWindowToken atoken = findAppWindowToken(token);
@@ -3897,7 +3863,6 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.sendAppVisibilityToClients();
}
- wtoken.willBeHidden = false;
// Allow for state changes and animation to be applied if:
// * token is transitioning visibility state
// * or the token was marked as hidden and is exiting before we had a chance to play the
@@ -3950,10 +3915,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
changed = true;
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- displayContent.layoutNeeded = true;
- }
+ win.setDisplayLayoutNeeded();
}
} else if (win.isVisibleNow()) {
if (!runningAppAnimation) {
@@ -3967,10 +3929,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
changed = true;
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- displayContent.layoutNeeded = true;
- }
+ win.setDisplayLayoutNeeded();
}
}
@@ -4138,10 +4097,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
w.mLastFreezeDuration = 0;
unfrozeWindows = true;
- final DisplayContent displayContent = w.getDisplayContent();
- if (displayContent != null) {
- displayContent.layoutNeeded = true;
- }
+ w.setDisplayLayoutNeeded();
}
}
if (force || unfrozeWindows) {
@@ -4444,7 +4400,6 @@ public class WindowManagerService extends IWindowManager.Stub
mInputMonitor.setUpdateInputWindowsNeededLw();
mWindowPlacerLocked.performSurfacePlacement();
mInputMonitor.updateInputWindowsLw(false /*force*/);
-
//dump();
}
@@ -4529,20 +4484,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
stack.attachDisplayContent(displayContent);
displayContent.attachStack(stack, onTop);
- if (stack.mStackId == DOCKED_STACK_ID) {
- mH.obtainMessage(H.UPDATE_DOCKED_STACK_DIVIDER,
- displayContent).sendToTarget();
- }
moveStackWindowsLocked(displayContent);
final WindowList windows = displayContent.getWindowList();
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
windows.get(winNdx).reportResized();
}
- if (stack.isFullscreen()) {
+ if (stack.getRawFullscreen()) {
return null;
}
Rect bounds = new Rect();
- stack.getBounds(bounds);
+ stack.getRawBounds(bounds);
return bounds;
}
}
@@ -4555,11 +4506,6 @@ public class WindowManagerService extends IWindowManager.Stub
void detachStackLocked(DisplayContent displayContent, TaskStack stack) {
displayContent.detachStack(stack);
stack.detachDisplay();
- // We can't directly remove the divider, because only the WM thread can do these operations
- // and we can be on AM thread.
- if (stack.mStackId == DOCKED_STACK_ID) {
- mH.obtainMessage(H.UPDATE_DOCKED_STACK_DIVIDER, displayContent).sendToTarget();
- }
}
public void detachStack(int stackId) {
@@ -4665,7 +4611,7 @@ public class WindowManagerService extends IWindowManager.Stub
stack.getDisplayContent().layoutNeeded = true;
mWindowPlacerLocked.performSurfacePlacement();
}
- return stack.isFullscreen();
+ return stack.getRawFullscreen();
}
}
@@ -7152,22 +7098,7 @@ public class WindowManagerService extends IWindowManager.Stub
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
mAnimator.addDisplayLocked(displayId);
- synchronized(displayContent.mDisplaySizeLock) {
- // Bootstrap the default logical display from the display manager.
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- DisplayInfo newDisplayInfo = mDisplayManagerInternal.getDisplayInfo(displayId);
- if (newDisplayInfo != null) {
- displayInfo.copyFrom(newDisplayInfo);
- }
- displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
- displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
- displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
- displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
- displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
- displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
- displayContent.mBaseDisplayRect.set(0, 0,
- displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight);
- }
+ displayContent.initializeDisplayBaseInfo();
}
}
}
@@ -7230,6 +7161,9 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int UPDATE_DOCKED_STACK_DIVIDER = 42;
+ public static final int RESIZE_STACK = 43;
+ public static final int RESIZE_TASK = 44;
+
@Override
public void handleMessage(Message msg) {
if (DEBUG_WINDOW_TRACE) {
@@ -7776,6 +7710,22 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
break;
+ case RESIZE_TASK: {
+ try {
+ mActivityManager.resizeTask(msg.arg1, (Rect) msg.obj, msg.arg2);
+ } catch (RemoteException e) {
+ // This will not happen since we are in the same process.
+ }
+ }
+ break;
+ case RESIZE_STACK: {
+ try {
+ mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj);
+ } catch (RemoteException e) {
+ // This will not happen since we are in the same process.
+ }
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG, "handleMessage: exit");
@@ -8317,7 +8267,7 @@ public class WindowManagerService extends IWindowManager.Stub
final int numTokens = tokens.size();
for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
final AppWindowToken wtoken = tokens.get(tokenNdx);
- if (wtoken.mIsExiting) {
+ if (wtoken.mIsExiting && !wtoken.mReplacingWindow) {
continue;
}
i = reAddAppWindowsLocked(displayContent, i, wtoken);
@@ -8387,6 +8337,13 @@ public class WindowManagerService extends IWindowManager.Stub
} else if (wtoken != null) {
winAnimator.mAnimLayer =
w.mLayer + wtoken.mAppAnimator.animLayerAdjustment;
+ if (wtoken.mReplacingWindow && wtoken.mAnimateReplacingWindow) {
+ // We know that we will be animating a relaunching window in the near future,
+ // which will receive a z-order increase. We want the replaced window to
+ // immediately receive the same treatment, e.g. to be above the dock divider.
+ w.mLayer += TYPE_LAYER_OFFSET;
+ winAnimator.mAnimLayer += TYPE_LAYER_OFFSET;
+ }
} else {
winAnimator.mAnimLayer = w.mLayer;
}
@@ -9909,6 +9866,12 @@ public class WindowManagerService extends IWindowManager.Stub
return mWindowMap;
}
+ /**
+ * Hint to a token that its activity will relaunch, which will trigger removal and addition of
+ * a window.
+ * @param token Application token for which the activity will be relaunched.
+ * @param animate Whether to animate the addition of the new window.
+ */
public void setReplacingWindow(IBinder token, boolean animate) {
synchronized (mWindowMap) {
AppWindowToken appWindowToken = findAppWindowToken(token);
@@ -10098,8 +10061,6 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void saveLastInputMethodWindowForTransition() {
synchronized (mWindowMap) {
- // TODO(multidisplay): Pass in the displayID.
- DisplayContent displayContent = getDefaultDisplayContentLocked();
if (mInputMethodWindow != null) {
mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c73dbaf607eb..55ddbc06d959 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
@@ -34,10 +35,12 @@ import static com.android.server.wm.WindowManagerService.DEBUG_POWER;
import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.WorkSource;
import android.util.DisplayMetrics;
import android.util.TimeUtils;
@@ -129,7 +132,6 @@ final class WindowState implements WindowManagerPolicy.WindowState {
boolean mAttachedHidden; // is our parent window hidden?
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
boolean mDragResizing;
- boolean mDragResizeChanging;
RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
@@ -1321,6 +1323,12 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
}
+ void setDisplayLayoutNeeded() {
+ if (mDisplayContent != null) {
+ mDisplayContent.layoutNeeded = true;
+ }
+ }
+
private class DeathRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
@@ -1465,10 +1473,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// We want the tag name to be somewhat stable so that it is easier to correlate
// in wake lock statistics. So in particular, we don't want to include the
// window's hash code as in toString().
- CharSequence tag = mAttrs.getTitle();
- if (tag == null) {
- tag = mAttrs.packageName;
- }
+ final CharSequence tag = getWindowTag();
mDrawLock = mService.mPowerManager.newWakeLock(
PowerManager.DRAW_WAKE_LOCK, "Window:" + tag);
mDrawLock.setReferenceCounted(false);
@@ -1605,6 +1610,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
void reportResized() {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
try {
if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
+ ": " + mCompatFrame);
@@ -1670,6 +1676,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mService.mPendingRemove.add(this);
mService.mWindowPlacerLocked.requestTraversal();
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
public void registerFocusObserver(IWindowFocusObserver observer) {
@@ -1701,13 +1708,23 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
boolean isDragResizeChanged() {
+ return mDragResizing != computeDragResizing();
+ }
+
+ private boolean computeDragResizing() {
final Task task = getTask();
- return task != null && mDragResizing != task.isDragResizing();
+ if (task == null) {
+ return false;
+ }
+ if (task.isDragResizing()) {
+ return true;
+ }
+ return mDisplayContent.mDividerControllerLocked.isResizing() &&
+ !task.inFreeformWorkspace() && !task.isFullscreen();
}
void setDragResizing() {
- final Task task = getTask();
- mDragResizing = task != null && task.isDragResizing();
+ mDragResizing = computeDragResizing();
}
boolean isDragResizing() {
@@ -1901,15 +1918,20 @@ final class WindowState implements WindowManagerPolicy.WindowState {
String makeInputChannelName() {
return Integer.toHexString(System.identityHashCode(this))
- + " " + mAttrs.getTitle();
+ + " " + getWindowTag();
+ }
+
+ private CharSequence getWindowTag() {
+ CharSequence tag = mAttrs.getTitle();
+ if (tag == null || tag.length() <= 0) {
+ tag = mAttrs.packageName;
+ }
+ return tag;
}
@Override
public String toString() {
- CharSequence title = mAttrs.getTitle();
- if (title == null || title.length() <= 0) {
- title = mAttrs.packageName;
- }
+ final CharSequence title = getWindowTag();
if (mStringNameCache == null || mLastTitle != title || mWasExiting != mExiting) {
mLastTitle = title;
mWasExiting = mExiting;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 07e1fce4c741..60bf57154bc6 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static com.android.server.wm.WindowManagerService.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerService.DEBUG_LAYERS;
@@ -868,14 +869,18 @@ class WindowStateAnimator {
mSurfaceW = width;
mSurfaceH = height;
- final boolean isHwAccelerated = (attrs.flags &
- WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+ final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
if (!PixelFormat.formatHasAlpha(attrs.format)
+ // Don't make surface with surfaceInsets opaque as they display a
+ // translucent shadow.
&& attrs.surfaceInsets.left == 0
&& attrs.surfaceInsets.top == 0
&& attrs.surfaceInsets.right == 0
- && attrs.surfaceInsets.bottom == 0) {
+ && attrs.surfaceInsets.bottom == 0
+ // Don't make surface opaque when resizing to reduce the amount of
+ // artifacts shown in areas the app isn't drawing content to.
+ && !w.isDragResizing()) {
flags |= SurfaceControl.OPAQUE;
}
@@ -1087,6 +1092,8 @@ class WindowStateAnimator {
mAnimator.getScreenRotationAnimationLocked(displayId);
final boolean screenAnimation =
screenRotationAnimation != null && screenRotationAnimation.isAnimating();
+
+ mHasClipRect = false;
if (selfTransformation || attachedTransformation != null
|| appTransformation != null || screenAnimation) {
// cache often used attributes locally
@@ -1165,7 +1172,6 @@ class WindowStateAnimator {
// transforming since it is more important to have that
// animation be smooth.
mShownAlpha = mAlpha;
- mHasClipRect = false;
if (!mService.mLimitedAlphaCompositing
|| (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
|| (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
@@ -1368,7 +1374,12 @@ class WindowStateAnimator {
// so we need to translate to match the actual surface coordinates.
clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
- adjustCropToStackBounds(w, clipRect);
+ // We don't want to clip to stack bounds windows that are currently doing entrance
+ // animation. This is necessary for docking operation, otherwise the window will be
+ // suddenly cut off.
+ if (!mAnimator.mAnimating) {
+ adjustCropToStackBounds(w, clipRect);
+ }
if (!clipRect.equals(mLastClipRect)) {
mLastClipRect.set(clipRect);
@@ -1394,7 +1405,11 @@ class WindowStateAnimator {
private void adjustCropToStackBounds(WindowState w, Rect clipRect) {
final AppWindowToken appToken = w.mAppToken;
- if (appToken != null && appToken.mCropWindowsToStack) {
+ // We don't apply the the stack bounds to the window that is being replaced, because it was
+ // living in a different stack. If we suddenly crop it to the new stack bounds, it might
+ // get cut off. We don't want it to happen, so we let it ignore the stack bounds until it
+ // gets removed. The window that will replace it will abide them.
+ if (appToken != null && appToken.mCropWindowsToStack && !appToken.mReplacingWindow) {
TaskStack stack = w.getTask().mStack;
stack.getBounds(mTmpStackBounds);
final int surfaceX = (int) mSurfaceX;
@@ -1707,8 +1722,7 @@ class WindowStateAnimator {
return false;
}
final LayoutParams attrs = mWin.getAttrs();
- final boolean isHwAccelerated = (attrs.flags &
- WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+ final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
if (format == mSurfaceFormat) {
setOpaqueLocked(!PixelFormat.formatHasAlpha(attrs.format));
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index e77ebe76b291..df0a1c9d43d5 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -47,6 +47,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.provider.Settings;
+import android.util.ArraySet;
import android.util.Slog;
import android.view.Display;
import android.view.DisplayInfo;
@@ -966,6 +967,7 @@ class WindowSurfacePlacer {
}
mService.mPolicy.finishLayoutLw();
+ mService.mH.obtainMessage(UPDATE_DOCKED_STACK_DIVIDER, displayContent).sendToTarget();
}
/**
@@ -1228,11 +1230,15 @@ class WindowSurfacePlacer {
final WindowState oldWallpaper =
mWallpaperControllerLocked.isWallpaperTargetAnimating()
? null : wallpaperTarget;
+ final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps;
+ final ArraySet<AppWindowToken> closingApps = mService.mClosingApps;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New wallpaper target=" + wallpaperTarget
+ ", oldWallpaper=" + oldWallpaper
+ ", lower target=" + lowerWallpaperTarget
- + ", upper target=" + upperWallpaperTarget);
+ + ", upper target=" + upperWallpaperTarget
+ + ", openingApps=" + openingApps
+ + ", closingApps=" + closingApps);
mService.mAnimateWallpaperWithTarget = false;
if (closingAppHasWallpaper && openingAppHasWallpaper) {
if (DEBUG_APP_TRANSITIONS)
@@ -1251,15 +1257,16 @@ class WindowSurfacePlacer {
}
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New transit: " + AppTransition.appTransitionToString(transit));
- } else if ((oldWallpaper != null) && !mService.mOpeningApps.isEmpty()
- && !mService.mOpeningApps.contains(oldWallpaper.mAppToken)) {
- // We are transitioning from an activity with
- // a wallpaper to one without.
+ } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
+ && !openingApps.contains(oldWallpaper.mAppToken)
+ && closingApps.contains(oldWallpaper.mAppToken)) {
+ // We are transitioning from an activity with a wallpaper to one without.
transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New transit away from wallpaper: "
+ AppTransition.appTransitionToString(transit));
- } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()) {
+ } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() &&
+ openingApps.contains(wallpaperTarget.mAppToken)) {
// We are transitioning from an activity without
// a wallpaper to now showing the wallpaper
transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3f70e0c7ccae..2dd7cdea7305 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -29,6 +29,7 @@ import static org.xmlpull.v1.XmlPullParser.TEXT;
import android.Manifest.permission;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accounts.AccountManager;
+import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
@@ -54,6 +55,7 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
@@ -76,7 +78,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.PersistableBundle;
import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RecoverySystem;
@@ -269,16 +270,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
| DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
final Context mContext;
- final PackageManager mPackageManager;
+ final Injector mInjector;
+ final IPackageManager mIPackageManager;
final UserManager mUserManager;
final LocalService mLocalService;
- final PowerManagerInternal mPowerManagerInternal;
-
- final IWindowManager mIWindowManager;
- final NotificationManager mNotificationManager;
-
// Stores and loads state on device and profile owners.
private final Owners mOwners;
@@ -994,7 +991,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean removed = false;
if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
DevicePolicyData policy = getUserData(userHandle);
- IPackageManager pm = getIPackageManager();
synchronized (this) {
for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
ActiveAdmin aa = policy.mAdminList.get(i);
@@ -1003,9 +999,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// then check if the package and receiver still exist.
final String adminPackage = aa.info.getPackageName();
if (packageName == null || packageName.equals(adminPackage)) {
- if (pm.getPackageInfo(adminPackage, 0, userHandle) == null
- || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle)
- == null) {
+ if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null
+ || mIPackageManager.getReceiverInfo(
+ aa.info.getComponent(), 0, userHandle) == null) {
removed = true;
policy.mAdminList.remove(i);
policy.mAdminMap.remove(aa.info.getComponent());
@@ -1026,7 +1022,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|| packageName.equals(policy.mDelegatedCertInstallerPackage))) {
try {
// Check if delegated cert installer package is removed.
- if (pm.getPackageInfo(
+ if (mIPackageManager.getPackageInfo(
policy.mDelegatedCertInstallerPackage, 0, userHandle) == null) {
policy.mDelegatedCertInstallerPackage = null;
saveSettingsLocked(policy.mUserHandle);
@@ -1038,148 +1034,146 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- /** Unit test will override it to inject a mock. */
+ /**
+ * Unit test will subclass it to inject mocks.
+ */
@VisibleForTesting
- Owners newOwners() {
- return new Owners(mContext);
- }
+ static class Injector {
- /** Unit test will override it to inject a mock. */
- @VisibleForTesting
- UserManager getUserManager() {
- return UserManager.get(mContext);
- }
+ private final Context mContext;
- /** Unit test will override it to inject a mock. */
- @VisibleForTesting
- PackageManager getPackageManager() {
- return mContext.getPackageManager();
- }
+ Injector(Context context) {
+ mContext = context;
+ }
- /** Unit test will override it to inject a mock. */
- @VisibleForTesting
- NotificationManager getNotificationManager() {
- return mContext.getSystemService(NotificationManager.class);
- }
+ Owners newOwners() {
+ return new Owners(mContext);
+ }
- /** Unit test will override it to inject a mock. */
- @VisibleForTesting
- PowerManagerInternal getPowerManagerInternal() {
- return LocalServices.getService(PowerManagerInternal.class);
- }
+ UserManager getUserManager() {
+ return UserManager.get(mContext);
+ }
- /** Unit test will override it to inject a mock. */
- @VisibleForTesting
- IWindowManager getIWindowManager() {
- return IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
- }
+ NotificationManager getNotificationManager() {
+ return mContext.getSystemService(NotificationManager.class);
+ }
- /** Unit test will override it to inject a mock. */
- @VisibleForTesting
- IActivityManager getIActivityManager() {
- return ActivityManagerNative.getDefault();
- }
+ PowerManagerInternal getPowerManagerInternal() {
+ return LocalServices.getService(PowerManagerInternal.class);
+ }
- /** Unit test will override it to inject a mock. */
- @VisibleForTesting
- IPackageManager getIPackageManager() {
- return AppGlobals.getPackageManager();
- }
+ IWindowManager getIWindowManager() {
+ return IWindowManager.Stub
+ .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
+ }
- /** Unit test will override it to inject a mock. */
- @VisibleForTesting
- LockPatternUtils newLockPatternUtils(Context context) {
- return new LockPatternUtils(context);
- }
+ IActivityManager getIActivityManager() {
+ return ActivityManagerNative.getDefault();
+ }
- /** Unit test will override it to inject. */
- @VisibleForTesting
- Looper getMyLooper() {
- return Looper.myLooper();
- }
+ IPackageManager getIPackageManager() {
+ return AppGlobals.getPackageManager();
+ }
- @VisibleForTesting
- long binderClearCallingIdentity() {
- return Binder.clearCallingIdentity();
- }
+ IBackupManager getIBackupManager() {
+ return IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ }
- @VisibleForTesting
- void binderRestoreCallingIdentity(long token) {
- Binder.restoreCallingIdentity(token);
- }
+ IAudioService getIAudioService() {
+ return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE));
+ }
- @VisibleForTesting
- int binderGetCallingUid() {
- return Binder.getCallingUid();
- }
+ LockPatternUtils newLockPatternUtils() {
+ return new LockPatternUtils(mContext);
+ }
- @VisibleForTesting
- int binderGetCallingPid() {
- return Binder.getCallingPid();
- }
+ Looper getMyLooper() {
+ return Looper.myLooper();
+ }
- @VisibleForTesting
- UserHandle binderGetCallingUserHandle() {
- return Binder.getCallingUserHandle();
- }
+ long binderClearCallingIdentity() {
+ return Binder.clearCallingIdentity();
+ }
- @VisibleForTesting
- boolean binderIsCallingUidMyUid() {
- return getCallingUid() == Process.myUid();
- }
+ void binderRestoreCallingIdentity(long token) {
+ Binder.restoreCallingIdentity(token);
+ }
- @VisibleForTesting
- File environmentGetUserSystemDirectory(int userId) {
- return Environment.getUserSystemDirectory(userId);
- }
+ int binderGetCallingUid() {
+ return Binder.getCallingUid();
+ }
- @VisibleForTesting
- void powerManagerGoToSleep(long time, int reason, int flags) {
- mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags);
- }
+ int binderGetCallingPid() {
+ return Binder.getCallingPid();
+ }
- @VisibleForTesting
- boolean systemPropertiesGetBoolean(String key, boolean def) {
- return SystemProperties.getBoolean(key, def);
- }
+ UserHandle binderGetCallingUserHandle() {
+ return Binder.getCallingUserHandle();
+ }
- @VisibleForTesting
- long systemPropertiesGetLong(String key, long def) {
- return SystemProperties.getLong(key, def);
- }
+ boolean binderIsCallingUidMyUid() {
+ return getCallingUid() == Process.myUid();
+ }
- @VisibleForTesting
- String systemPropertiesGet(String key, String def) {
- return SystemProperties.get(key, def);
- }
+ File environmentGetUserSystemDirectory(int userId) {
+ return Environment.getUserSystemDirectory(userId);
+ }
- @VisibleForTesting
- String systemPropertiesGet(String key) {
- return SystemProperties.get(key);
- }
+ void powerManagerGoToSleep(long time, int reason, int flags) {
+ mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags);
+ }
- @VisibleForTesting
- void systemPropertiesSet(String key, String value) {
- SystemProperties.set(key, value);
+ boolean systemPropertiesGetBoolean(String key, boolean def) {
+ return SystemProperties.getBoolean(key, def);
+ }
+
+ long systemPropertiesGetLong(String key, long def) {
+ return SystemProperties.getLong(key, def);
+ }
+
+ String systemPropertiesGet(String key, String def) {
+ return SystemProperties.get(key, def);
+ }
+
+ String systemPropertiesGet(String key) {
+ return SystemProperties.get(key);
+ }
+
+ void systemPropertiesSet(String key, String value) {
+ SystemProperties.set(key, value);
+ }
+
+ boolean userManagerIsSplitSystemUser() {
+ return UserManager.isSplitSystemUser();
+ }
+
+ String getDevicePolicyFilePathForSystemUser() {
+ return "/data/system/";
+ }
}
/**
* Instantiates the service.
*/
public DevicePolicyManagerService(Context context) {
- mContext = context;
- mHandler = new Handler(getMyLooper());
- mOwners = newOwners();
+ this(new Injector(context));
+ }
+
+ @VisibleForTesting
+ DevicePolicyManagerService(Injector injector) {
+ mInjector = injector;
+ mContext = Preconditions.checkNotNull(injector.mContext);
+ mHandler = new Handler(Preconditions.checkNotNull(injector.getMyLooper()));
+ mOwners = Preconditions.checkNotNull(injector.newOwners());
- mUserManager = Preconditions.checkNotNull(getUserManager());
- mPackageManager = Preconditions.checkNotNull(getPackageManager());
- mPowerManagerInternal = Preconditions.checkNotNull(getPowerManagerInternal());
- mIWindowManager = Preconditions.checkNotNull(getIWindowManager());
- mNotificationManager = Preconditions.checkNotNull(getNotificationManager());
+ mUserManager = Preconditions.checkNotNull(injector.getUserManager());
+ mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
mLocalService = new LocalService();
- mHasFeature = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
+ mHasFeature = mContext.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
if (!mHasFeature) {
// Skip the rest of the initialization
return;
@@ -1191,35 +1185,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
filter.addAction(Intent.ACTION_USER_STARTED);
filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
- context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
- context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
LocalServices.addService(DevicePolicyManagerInternal.class, mLocalService);
}
/**
- * We need it for testing to allow accessing context from the test-only subclass while this
- * class's constructor is still running.
- */
- @VisibleForTesting
- Context getContext() {
- return mContext;
- }
-
- /**
* Creates and loads the policy data from xml.
* @param userHandle the user for whom to load the policy data
* @return
*/
+ @NonNull
DevicePolicyData getUserData(int userHandle) {
synchronized (this) {
DevicePolicyData policy = mUserData.get(userHandle);
@@ -1243,11 +1229,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* @return
*/
DevicePolicyData getUserDataUnchecked(int userHandle) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
return getUserData(userHandle);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -1264,7 +1250,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (policy != null) {
mUserData.remove(userHandle);
}
- File policyFile = new File(environmentGetUserSystemDirectory(userHandle),
+ File policyFile = new File(mInjector.environmentGetUserSystemDirectory(userHandle),
DEVICE_POLICIES_XML);
policyFile.delete();
Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
@@ -1304,7 +1290,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
alarmTime = now + alarmInterval;
}
- long token = binderClearCallingIdentity();
+ long token = mInjector.binderClearCallingIdentity();
try {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
@@ -1316,7 +1302,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
am.set(AlarmManager.RTC, alarmTime, pi);
}
} finally {
- binderRestoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
}
@@ -1332,7 +1318,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
throws SecurityException {
- final int callingUid = binderGetCallingUid();
+ final int callingUid = mInjector.binderGetCallingUid();
ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid);
if (result != null) {
@@ -1356,7 +1342,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ admin.info.getTagForPolicy(reqPolicy));
} else {
throw new SecurityException("No active admin owned by uid "
- + binderGetCallingUid() + " for policy #" + reqPolicy);
+ + mInjector.binderGetCallingUid() + " for policy #" + reqPolicy);
}
}
@@ -1372,7 +1358,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (admin.getUid() != uid) {
throw new SecurityException("Admin " + who + " is not owned by uid "
- + binderGetCallingUid());
+ + mInjector.binderGetCallingUid());
}
if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) {
return admin;
@@ -1536,17 +1522,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private JournaledFile makeJournaledFile(int userHandle) {
final String base = userHandle == UserHandle.USER_SYSTEM
- ? getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML
- : new File(environmentGetUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
- .getAbsolutePath();
+ ? mInjector.getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML
+ : new File(mInjector.environmentGetUserSystemDirectory(userHandle),
+ DEVICE_POLICIES_XML).getAbsolutePath();
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
- @VisibleForTesting
- String getDevicePolicyFilePathForSystemUser() {
- return "/data/system/";
- }
-
private void saveSettingsLocked(int userHandle) {
DevicePolicyData policy = getUserData(userHandle);
JournaledFile journal = makeJournaledFile(userHandle);
@@ -1657,11 +1638,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void sendChangedNotification(int userHandle) {
Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -1793,9 +1774,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// sufficiently what is currently set. Note that this is only
// a sanity check in case the two get out of sync; this should
// never normally happen.
- final long identity = binderClearCallingIdentity();
+ final long identity = mInjector.binderClearCallingIdentity();
try {
- LockPatternUtils utils = newLockPatternUtils(mContext);
+ LockPatternUtils utils = mInjector.newLockPatternUtils();
if (utils.getActivePasswordQuality(userHandle) < policy.mActivePasswordQuality) {
Slog.w(LOG_TAG, "Active password quality 0x"
+ Integer.toHexString(policy.mActivePasswordQuality)
@@ -1811,7 +1792,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
policy.mActivePasswordNonLetter = 0;
}
} finally {
- binderRestoreCallingIdentity(identity);
+ mInjector.binderRestoreCallingIdentity(identity);
}
validatePasswordOwnerLocked(policy);
@@ -1825,26 +1806,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void updateLockTaskPackagesLocked(List<String> packages, int userId) {
- IActivityManager am = getIActivityManager();
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- am.updateLockTaskPackages(userId, packages.toArray(new String[packages.size()]));
+ mInjector.getIActivityManager()
+ .updateLockTaskPackages(userId, packages.toArray(new String[packages.size()]));
} catch (RemoteException e) {
// Not gonna happen.
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
private void updateDeviceOwnerLocked() {
- IActivityManager am = getIActivityManager();
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- am.updateDeviceOwner(getDeviceOwner());
+ mInjector.getIActivityManager()
+ .updateDeviceOwner(getDeviceOwner());
} catch (RemoteException e) {
// Not gonna happen.
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -1889,17 +1870,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Ensure the status of the camera is synced down to the system. Interested native services
// should monitor this value and act accordingly.
String cameraPropertyForUser = SYSTEM_PROP_DISABLE_CAMERA_PREFIX + policy.mUserHandle;
- boolean systemState = systemPropertiesGetBoolean(cameraPropertyForUser, false);
+ boolean systemState = mInjector.systemPropertiesGetBoolean(cameraPropertyForUser, false);
boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
if (cameraDisabled != systemState) {
- long token = binderClearCallingIdentity();
+ long token = mInjector.binderClearCallingIdentity();
try {
String value = cameraDisabled ? "1" : "0";
if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
+ cameraPropertyForUser + "] = " + value);
- systemPropertiesSet(cameraPropertyForUser, value);
+ mInjector.systemPropertiesSet(cameraPropertyForUser, value);
} finally {
- binderRestoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
}
}
@@ -1939,14 +1920,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void ensureDeviceOwnerUserStarted() {
if (mOwners.hasDeviceOwner()) {
- final IActivityManager am = getIActivityManager();
final int userId = mOwners.getDeviceOwnerUserId();
if (VERBOSE_LOG) {
Log.v(LOG_TAG, "Starting non-system DO user: " + userId);
}
if (userId != UserHandle.USER_SYSTEM) {
try {
- am.startUserInBackground(userId);
+ mInjector.getIActivityManager().startUserInBackground(userId);
// STOPSHIP Prevent the DO user from being killed.
@@ -2047,7 +2027,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
}
if (!hasCert) {
- mNotificationManager.cancelAsUser(
+ mInjector.getNotificationManager().cancelAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, userHandle);
return;
}
@@ -2092,7 +2072,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
com.android.internal.R.color.system_notification_accent_color))
.build();
- mNotificationManager.notifyAsUser(
+ mInjector.getNotificationManager().notifyAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
}
}
@@ -2121,7 +2101,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new IllegalArgumentException("Bad admin: " + adminReceiver);
}
synchronized (this) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
if (!refreshing
&& getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
@@ -2148,7 +2128,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
onEnableData, null);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -2242,7 +2222,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (admin == null) {
return;
}
- if (admin.getUid() != binderGetCallingUid()) {
+ if (admin.getUid() != mInjector.binderGetCallingUid()) {
// Active device owners must remain active admins.
if (isDeviceOwner(adminReceiver.getPackageName())) {
return;
@@ -2250,11 +2230,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
}
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
removeActiveAdminLocked(adminReceiver, userHandle);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -2524,7 +2504,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return null;
}
- if (binderIsCallingUidMyUid()) {
+ if (mInjector.binderIsCallingUidMyUid()) {
return new ArrayList<>(activeAdmin.crossProfileWidgetProviders);
} else {
return activeAdmin.crossProfileWidgetProviders;
@@ -3089,7 +3069,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- int callingUid = binderGetCallingUid();
+ int callingUid = mInjector.binderGetCallingUid();
DevicePolicyData policy = getUserData(userHandle);
if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user");
@@ -3105,7 +3085,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Don't do this with the lock held, because it is going to call
// back in to the service.
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
LockPatternUtils utils = new LockPatternUtils(mContext);
if (!TextUtils.isEmpty(password)) {
@@ -3126,7 +3106,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
return true;
@@ -3176,7 +3156,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
if (timeMs <= 0) {
timeMs = Integer.MAX_VALUE;
@@ -3188,9 +3168,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
policy.mLastMaximumTimeToLock = timeMs;
- mPowerManagerInternal.setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
+ // TODO It can overflow. Cap it.
+ mInjector.getPowerManagerInternal()
+ .setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -3242,26 +3224,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void lockNowUnchecked() {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
// Power off the display
- powerManagerGoToSleep(SystemClock.uptimeMillis(),
+ mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
// Ensure the device is locked
new LockPatternUtils(mContext).requireStrongAuth(
STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL);
- mIWindowManager.lockNow(null);
+ mInjector.getIWindowManager().lockNow(null);
} catch (RemoteException e) {
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
- private boolean isExtStorageEncrypted() {
- String state = systemPropertiesGet("vold.decrypt");
- return !"".equals(state);
- }
-
@Override
public void enforceCanManageCaCerts(ComponentName who) {
if (who == null) {
@@ -3276,7 +3253,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private boolean isCallerDelegatedCertInstaller() {
- final int callingUid = binderGetCallingUid();
+ final int callingUid = mInjector.binderGetCallingUid();
final int userHandle = UserHandle.getUserId(callingUid);
synchronized (this) {
final DevicePolicyData policy = getUserData(userHandle);
@@ -3311,7 +3288,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
- final long id = binderClearCallingIdentity();
+ final long id = mInjector.binderClearCallingIdentity();
try {
final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
try {
@@ -3326,7 +3303,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
Thread.currentThread().interrupt();
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return false;
}
@@ -3342,7 +3319,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
enforceCanManageCaCerts(admin);
final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
- final long id = binderClearCallingIdentity();
+ final long id = mInjector.binderClearCallingIdentity();
try {
final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
try {
@@ -3358,7 +3335,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
Thread.currentThread().interrupt();
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -3374,7 +3351,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
- final long id = binderClearCallingIdentity();
+ final long id = mInjector.binderClearCallingIdentity();
try {
final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
try {
@@ -3389,7 +3366,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.w(LOG_TAG, "Interrupted while installing certificate", e);
Thread.currentThread().interrupt();
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return false;
}
@@ -3398,11 +3375,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias,
final IBinder response) {
// Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers.
- if (UserHandle.getAppId(binderGetCallingUid()) != Process.SYSTEM_UID) {
+ if (UserHandle.getAppId(mInjector.binderGetCallingUid()) != Process.SYSTEM_UID) {
return;
}
- final UserHandle caller = binderGetCallingUserHandle();
+ final UserHandle caller = mInjector.binderGetCallingUserHandle();
// If there is a profile owner, redirect to that; otherwise query the device owner.
ComponentName aliasChooser = getProfileOwner(caller.getIdentifier());
if (aliasChooser == null && caller.isOwner()) {
@@ -3423,7 +3400,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS, alias);
intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE, response);
- final long id = binderClearCallingIdentity();
+ final long id = mInjector.binderClearCallingIdentity();
try {
mContext.sendOrderedBroadcastAsUser(intent, caller, null, new BroadcastReceiver() {
@Override
@@ -3433,7 +3410,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}, null, Activity.RESULT_OK, null, null);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -3504,7 +3481,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final String source = admin.info.getComponent().flattenToShortString();
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName())
@@ -3525,7 +3502,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
wipeDeviceOrUserLocked(wipeExtRequested, userHandle,
"DevicePolicyManager.wipeData() from " + source);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -3538,7 +3515,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void run() {
try {
- IActivityManager am = getIActivityManager();
+ IActivityManager am = mInjector.getIActivityManager();
if (am.getCurrentUser().id == userHandle) {
am.switchUser(UserHandle.USER_SYSTEM);
}
@@ -3566,11 +3543,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setStyle(new Notification.BigTextStyle().bigText(contentText))
.build();
- mNotificationManager.notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
+ mInjector.getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
}
private void clearWipeProfileNotification() {
- mNotificationManager.cancel(PROFILE_WIPED_NOTIFICATION_ID);
+ mInjector.getNotificationManager().cancel(PROFILE_WIPED_NOTIFICATION_ID);
}
@Override
@@ -3630,7 +3607,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|| p.mActivePasswordNumeric != numbers
|| p.mActivePasswordSymbols != symbols
|| p.mActivePasswordNonLetter != nonletter) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
p.mActivePasswordQuality = quality;
p.mActivePasswordLength = length;
@@ -3648,7 +3625,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -3684,7 +3661,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
boolean wipeData = false;
int identifier = 0;
@@ -3715,7 +3692,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"reportFailedPasswordAttempt()");
}
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -3728,7 +3705,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
policy.mFailedPasswordAttempts = 0;
policy.mPasswordOwner = -1;
@@ -3739,7 +3716,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
}
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -3790,11 +3767,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Reset the global proxy accordingly
// Do this using system permissions, as apps cannot write to secure settings
- long origId = binderClearCallingIdentity();
+ long origId = mInjector.binderClearCallingIdentity();
try {
resetGlobalProxyLocked(policy);
} finally {
- binderRestoreCallingIdentity(origId);
+ mInjector.binderRestoreCallingIdentity(origId);
}
return null;
}
@@ -3829,13 +3806,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
}
- long token = binderClearCallingIdentity();
+ long token = mInjector.binderClearCallingIdentity();
try {
ConnectivityManager connectivityManager = (ConnectivityManager)
mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.setGlobalProxy(proxyInfo);
} finally {
- binderRestoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
}
@@ -3996,15 +3973,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
*/
private int getEncryptionStatus() {
- String status = systemPropertiesGet("ro.crypto.state", "unsupported");
+ String status = mInjector.systemPropertiesGet("ro.crypto.state", "unsupported");
if ("encrypted".equalsIgnoreCase(status)) {
- final long token = binderClearCallingIdentity();
+ final long token = mInjector.binderClearCallingIdentity();
try {
return LockPatternUtils.isDeviceEncrypted()
? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
: DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY;
} finally {
- binderRestoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
} else if ("unencrypted".equalsIgnoreCase(status)) {
return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
@@ -4069,13 +4046,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void updateScreenCaptureDisabledInWindowManager(int userHandle, boolean disabled) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- mIWindowManager.setScreenCaptureDisabled(userHandle, disabled);
+ mInjector.getIWindowManager().setScreenCaptureDisabled(userHandle, disabled);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Unable to notify WindowManager.", e);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -4100,12 +4077,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Turn AUTO_TIME on in settings if it is required
if (required) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AUTO_TIME, 1 /* AUTO_TIME on */);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -4214,7 +4191,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return 0;
}
enforceCrossUserPermission(userHandle);
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
synchronized (this) {
if (who != null) {
@@ -4257,7 +4234,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return which;
}
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -4267,7 +4244,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
if (packageName == null
- || !Owners.isInstalledForUser(packageName, userId)) {
+ || !isPackageInstalledForUser(packageName, userId)) {
throw new IllegalArgumentException("Invalid package name " + packageName
+ " for device owner");
}
@@ -4275,15 +4252,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
enforceCanSetDeviceOwner(userId);
// Shutting down backup manager service permanently.
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- IBackupManager ibm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+ mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, false);
} catch (RemoteException e) {
throw new IllegalStateException("Failed deactivating backup service.", e);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
mOwners.setDeviceOwner(packageName, ownerName, userId);
@@ -4291,12 +4266,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
updateDeviceOwnerLocked();
Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
- ident = binderClearCallingIdentity();
+ ident = mInjector.binderClearCallingIdentity();
try {
// TODO Send to system too?
mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
return true;
}
@@ -4328,11 +4303,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!mHasFeature) {
return null;
}
+ // TODO: Do we really need it? getDeviceOwner() doesn't require it.
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
synchronized (this) {
if (!mOwners.hasDeviceOwner()) {
return null;
}
+ // TODO This totally ignores the name passed to setDeviceOwner (change for b/20679292)
+ // Should setDeviceOwner/ProfileOwner still take a name?
String deviceOwnerPackage = mOwners.getDeviceOwnerPackageName();
return getApplicationLabel(deviceOwnerPackage, UserHandle.USER_SYSTEM);
}
@@ -4361,7 +4339,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Preconditions.checkNotNull(packageName, "packageName is null");
try {
int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
- if (uid != binderGetCallingUid()) {
+ if (uid != mInjector.binderGetCallingUid()) {
throw new SecurityException("Invalid packageName");
}
} catch (NameNotFoundException e) {
@@ -4377,15 +4355,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mOwners.writeDeviceOwner();
updateDeviceOwnerLocked();
// Reactivate backup service.
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- IBackupManager ibm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+ mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, true);
} catch (RemoteException e) {
throw new IllegalStateException("Failed reactivating backup service.", e);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -4397,15 +4373,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (initializer == null ||
!mOwners.hasDeviceOwner() ||
- !Owners.isInstalledForUser(initializer.getPackageName(),
+ !isPackageInstalledForUser(initializer.getPackageName(),
mOwners.getDeviceOwnerUserId())) {
throw new IllegalArgumentException("Invalid component name " + initializer
+ " for device initializer or no device owner set");
}
boolean isInitializerSystemApp;
try {
- isInitializerSystemApp = isSystemApp(getIPackageManager(),
- initializer.getPackageName(), binderGetCallingUserHandle().getIdentifier());
+ isInitializerSystemApp = isSystemApp(mIPackageManager,
+ initializer.getPackageName(),
+ mInjector.binderGetCallingUserHandle().getIdentifier());
} catch (RemoteException | IllegalArgumentException e) {
isInitializerSystemApp = false;
Slog.e(LOG_TAG, "Fail to check if device initialzer is system app.", e);
@@ -4488,9 +4465,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, UserHandle.getCallingUserId());
- if (admin.getUid() != binderGetCallingUid()) {
+ if (admin.getUid() != mInjector.binderGetCallingUid()) {
throw new SecurityException("Admin " + who + " is not owned by uid "
- + binderGetCallingUid());
+ + mInjector.binderGetCallingUid());
}
if (!isDeviceInitializer(admin.info.getPackageName())
@@ -4499,12 +4476,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"clearDeviceInitializer can only be called by the device initializer/owner");
}
synchronized (this) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
mOwners.clearDeviceInitializer();
mOwners.writeDeviceOwner();
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -4515,7 +4492,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
if (who == null
- || !Owners.isInstalledForUser(who.getPackageName(), userHandle)) {
+ || !isPackageInstalledForUser(who.getPackageName(), userHandle)) {
throw new IllegalArgumentException("Component " + who
+ " not installed for userId:" + userHandle);
}
@@ -4532,7 +4509,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!mHasFeature) {
return;
}
- UserHandle callingUser = binderGetCallingUserHandle();
+ UserHandle callingUser = mInjector.binderGetCallingUserHandle();
// Check if this is the profile owner who is calling
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
synchronized (this) {
@@ -4552,15 +4529,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
policy.mStatusBarDisabled = false;
saveSettingsLocked(userId);
- final long ident = binderClearCallingIdentity();
+ final long ident = mInjector.binderClearCallingIdentity();
try {
clearUserRestrictions(userHandle);
- getIPackageManager().updatePermissionFlagsForAllApps(
+ mIPackageManager.updatePermissionFlagsForAllApps(
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
0 /* flagValues */, userHandle.getIdentifier());
} catch (RemoteException re) {
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -4568,11 +4545,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void clearUserRestrictions(UserHandle userHandle) {
Bundle userRestrictions = mUserManager.getUserRestrictions();
mUserManager.setUserRestrictions(new Bundle(), userHandle);
- IAudioService iAudioService = IAudioService.Stub.asInterface(
- ServiceManager.getService(Context.AUDIO_SERVICE));
if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) {
try {
- iAudioService.setMasterMute(true, 0, mContext.getPackageName(),
+ mInjector.getIAudioService().setMasterMute(true, 0, mContext.getPackageName(),
userHandle.getIdentifier());
} catch (RemoteException e) {
// Not much we can do here.
@@ -4580,7 +4555,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) {
try {
- iAudioService.setMicrophoneMute(true, mContext.getPackageName(),
+ mInjector.getIAudioService().setMicrophoneMute(true, mContext.getPackageName(),
userHandle.getIdentifier());
} catch (RemoteException e) {
// Not much we can do here.
@@ -4597,9 +4572,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!mHasFeature) {
return true;
}
- DevicePolicyData policy = getUserData(userHandle);
- // If policy is null, return true, else check if the setup has completed.
- return policy == null || policy.mUserSetupComplete;
+ return getUserData(userHandle).mUserSetupComplete;
}
@Override
@@ -4620,11 +4593,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"This method can only be called by device initializers");
}
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
if (!isDeviceOwner(activeAdmin.info.getPackageName())) {
- IPackageManager ipm = getIPackageManager();
- ipm.setComponentEnabledSetting(who,
+ mIPackageManager.setComponentEnabledSetting(who,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP, userId);
@@ -4641,7 +4613,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.i(LOG_TAG, "Can't talk to package manager", e);
return false;
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return true;
}
@@ -4659,7 +4631,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
mUserManager.setUserEnabled(userId);
UserInfo parent = mUserManager.getProfileParent(userId);
@@ -4669,7 +4641,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, new UserHandle(parent.id));
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -4681,11 +4653,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Check if this is the profile owner (includes device owner).
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
mUserManager.setUserName(userId, profileName);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -4735,7 +4707,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* Canonical name for a given package.
*/
private String getApplicationLabel(String packageName, int userHandle) {
- long token = binderClearCallingIdentity();
+ long token = mInjector.binderClearCallingIdentity();
try {
final Context userContext;
try {
@@ -4753,7 +4725,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
return result != null ? result.toString() : null;
} finally {
- binderRestoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
}
@@ -4779,7 +4751,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new IllegalStateException("Trying to set the profile owner, but profile owner "
+ "is already set.");
}
- int callingUid = binderGetCallingUid();
+ int callingUid = mInjector.binderGetCallingUid();
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
if (hasUserSetupCompleted(userHandle) &&
AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) {
@@ -4812,13 +4784,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new IllegalStateException("User not running: " + userId);
}
- int callingUid = binderGetCallingUid();
+ int callingUid = mInjector.binderGetCallingUid();
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
if (!hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
return;
}
// STOPSHIP Do proper check in split user mode
- if (!UserManager.isSplitSystemUser()) {
+ if (!mInjector.userManagerIsSplitSystemUser()) {
if (mUserManager.getUserCount() > 1) {
throw new IllegalStateException(
"Not allowed to set the device owner because there "
@@ -4837,7 +4809,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
// STOPSHIP Do proper check in split user mode
- if (!UserManager.isSplitSystemUser()) {
+ if (!mInjector.userManagerIsSplitSystemUser()) {
if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
throw new IllegalStateException("Cannot set the device owner if the device is "
+ "already set-up");
@@ -4849,7 +4821,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (userHandle < 0) {
throw new IllegalArgumentException("Invalid userId " + userHandle);
}
- final int callingUid = binderGetCallingUid();
+ final int callingUid = mInjector.binderGetCallingUid();
if (userHandle == UserHandle.getUserId(callingUid)) return;
if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
mContext.enforceCallingOrSelfPermission(
@@ -4865,32 +4837,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private UserInfo getProfileParent(int userHandle) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
return mUserManager.getProfileParent(userHandle);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
private boolean isManagedProfile(int userHandle) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
return mUserManager.getUserInfo(userHandle).isManagedProfile();
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
private void enableIfNecessary(String packageName, int userId) {
try {
- IPackageManager ipm = getIPackageManager();
- ApplicationInfo ai = ipm.getApplicationInfo(packageName,
+ ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName,
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
userId);
if (ai.enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
- ipm.setApplicationEnabledSetting(packageName,
+ mIPackageManager.setApplicationEnabledSetting(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
}
@@ -4904,8 +4875,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
- + binderGetCallingPid()
- + ", uid=" + binderGetCallingUid());
+ + mInjector.binderGetCallingPid()
+ + ", uid=" + mInjector.binderGetCallingUid());
return;
}
@@ -4946,14 +4917,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- IPackageManager pm = getIPackageManager();
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- pm.addPersistentPreferredActivity(filter, activity, userHandle);
+ mIPackageManager.addPersistentPreferredActivity(filter, activity, userHandle);
} catch (RemoteException re) {
// Shouldn't happen
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -4965,14 +4935,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- IPackageManager pm = getIPackageManager();
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- pm.clearPackagePersistentPreferredActivities(packageName, userHandle);
+ mIPackageManager.clearPackagePersistentPreferredActivities(packageName, userHandle);
} catch (RemoteException re) {
// Shouldn't happen
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -4984,11 +4953,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5086,7 +5055,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public ComponentName getRestrictionsProvider(int userHandle) {
synchronized (this) {
- if (binderGetCallingUid() != Process.SYSTEM_UID) {
+ if (mInjector.binderGetCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Only the system can query the permission provider");
}
DevicePolicyData userData = getUserData(userHandle);
@@ -5101,8 +5070,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- IPackageManager pm = getIPackageManager();
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserInfo parent = mUserManager.getProfileParent(callingUserId);
if (parent == null) {
@@ -5111,17 +5079,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
if ((flags & DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED) != 0) {
- pm.addCrossProfileIntentFilter(filter, who.getPackageName(), callingUserId,
- parent.id, 0);
+ mIPackageManager.addCrossProfileIntentFilter(
+ filter, who.getPackageName(), callingUserId, parent.id, 0);
}
if ((flags & DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT) != 0) {
- pm.addCrossProfileIntentFilter(filter, who.getPackageName(),
+ mIPackageManager.addCrossProfileIntentFilter(filter, who.getPackageName(),
parent.id, callingUserId, 0);
}
} catch (RemoteException re) {
// Shouldn't happen
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5132,8 +5100,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- IPackageManager pm = getIPackageManager();
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserInfo parent = mUserManager.getProfileParent(callingUserId);
if (parent == null) {
@@ -5142,15 +5109,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
// Removing those that go from the managed profile to the parent.
- pm.clearCrossProfileIntentFilters(callingUserId, who.getPackageName());
+ mIPackageManager.clearCrossProfileIntentFilters(
+ callingUserId, who.getPackageName());
// And those that go from the parent to the managed profile.
// If we want to support multiple managed profiles, we will have to only remove
// those that have callingUserId as their target.
- pm.clearCrossProfileIntentFilters(parent.id, who.getPackageName());
+ mIPackageManager.clearCrossProfileIntentFilters(parent.id, who.getPackageName());
} catch (RemoteException re) {
// Shouldn't happen
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5162,7 +5130,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private boolean checkPackagesInPermittedListOrSystem(List<String> enabledPackages,
List<String> permittedList) {
int userIdToCheck = UserHandle.getCallingUserId();
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
// If we have an enabled packages list for a managed profile the packages
// we should check are installed for the parent user.
@@ -5171,12 +5139,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
userIdToCheck = user.profileGroupId;
}
- IPackageManager pm = getIPackageManager();
for (String enabledPackage : enabledPackages) {
boolean systemService = false;
try {
- ApplicationInfo applicationInfo = pm.getApplicationInfo(enabledPackage,
- PackageManager.GET_UNINSTALLED_PACKAGES, userIdToCheck);
+ ApplicationInfo applicationInfo = mIPackageManager.getApplicationInfo(
+ enabledPackage, PackageManager.GET_UNINSTALLED_PACKAGES, userIdToCheck);
systemService = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
} catch (RemoteException e) {
Log.i(LOG_TAG, "Can't talk to package managed", e);
@@ -5186,7 +5153,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return true;
}
@@ -5211,7 +5178,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (packageList != null) {
int userId = UserHandle.getCallingUserId();
List<AccessibilityServiceInfo> enabledServices = null;
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserInfo user = mUserManager.getUserInfo(userId);
if (user.isManagedProfile()) {
@@ -5221,7 +5188,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
if (enabledServices != null) {
@@ -5292,7 +5259,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// If we have a permitted list add all system accessibility services.
if (result != null) {
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserInfo user = mUserManager.getUserInfo(userId);
if (user.isManagedProfile()) {
@@ -5303,7 +5270,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
List<AccessibilityServiceInfo> installedServices =
accessibilityManager.getInstalledAccessibilityServiceList();
- IPackageManager pm = getIPackageManager();
if (installedServices != null) {
for (AccessibilityServiceInfo service : installedServices) {
ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
@@ -5314,7 +5280,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -5324,12 +5290,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private boolean checkCallerIsCurrentUserOrProfile() {
int callingUserId = UserHandle.getCallingUserId();
- long token = binderClearCallingIdentity();
+ long token = mInjector.binderClearCallingIdentity();
try {
UserInfo currentUser;
UserInfo callingUser = mUserManager.getUserInfo(callingUserId);
try {
- currentUser = getIActivityManager().getCurrentUser();
+ currentUser = mInjector.getIActivityManager().getCurrentUser();
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to talk to activity managed.", e);
return false;
@@ -5346,7 +5312,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
} finally {
- binderRestoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
return true;
}
@@ -5412,7 +5378,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public List getPermittedInputMethodsForCurrentUser() {
UserInfo currentUser;
try {
- currentUser = getIActivityManager().getCurrentUser();
+ currentUser = mInjector.getIActivityManager().getCurrentUser();
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to make remote calls to get current user", e);
// Activity managed is dead, just allow all IMEs
@@ -5450,9 +5416,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
InputMethodManager inputMethodManager = (InputMethodManager) mContext
.getSystemService(Context.INPUT_METHOD_SERVICE);
List<InputMethodInfo> imes = inputMethodManager.getInputMethodList();
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- IPackageManager pm = getIPackageManager();
if (imes != null) {
for (InputMethodInfo ime : imes) {
ServiceInfo serviceInfo = ime.getServiceInfo();
@@ -5463,7 +5428,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
return result;
@@ -5476,7 +5441,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserInfo userInfo = mUserManager.createUser(name, 0 /* flags */);
if (userInfo != null) {
@@ -5484,7 +5449,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
return null;
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5496,21 +5461,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (user == null) {
return null;
}
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
String profileOwnerPkg = profileOwnerComponent.getPackageName();
- final IPackageManager ipm = getIPackageManager();
- IActivityManager activityManager = getIActivityManager();
final int userHandle = user.getIdentifier();
try {
// Install the profile owner if not present.
- if (!ipm.isPackageAvailable(profileOwnerPkg, userHandle)) {
- ipm.installExistingPackageAsUser(profileOwnerPkg, userHandle);
+ if (!mIPackageManager.isPackageAvailable(profileOwnerPkg, userHandle)) {
+ mIPackageManager.installExistingPackageAsUser(profileOwnerPkg, userHandle);
}
// Start user in background.
- activityManager.startUserInBackground(userHandle);
+ mInjector.getIActivityManager().startUserInBackground(userHandle);
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to make remote calls for configureUser", e);
}
@@ -5519,7 +5482,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
setProfileOwner(profileOwnerComponent, ownerName, userHandle);
return user;
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -5529,11 +5492,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
return mUserManager.removeUser(userHandle.getIdentifier());
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5544,18 +5507,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
int userId = UserHandle.USER_SYSTEM;
if (userHandle != null) {
userId = userHandle.getIdentifier();
}
- return getIActivityManager().switchUser(userId);
+ return mInjector.getIActivityManager().switchUser(userId);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Couldn't switch user", e);
return false;
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5568,14 +5531,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle);
// if no restrictions were saved, mUserManager.getApplicationRestrictions
// returns null, but DPM method should return an empty Bundle as per JavaDoc
return bundle != null ? bundle : Bundle.EMPTY;
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5598,22 +5561,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user);
- IAudioService iAudioService = null;
- if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)
- || UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
- iAudioService = IAudioService.Stub.asInterface(
- ServiceManager.getService(Context.AUDIO_SERVICE));
- }
-
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
if (enabled && !alreadyRestricted) {
if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
- iAudioService.setMicrophoneMute(true, mContext.getPackageName(),
- userHandle);
+ mInjector.getIAudioService()
+ .setMicrophoneMute(true, mContext.getPackageName(), userHandle);
} else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
- iAudioService.setMasterMute(true, 0, mContext.getPackageName(),
- userHandle);
+ mInjector.getIAudioService()
+ .setMasterMute(true, 0, mContext.getPackageName(), userHandle);
} else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0,
@@ -5651,8 +5607,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Send out notifications however as some clients may want to reread the
// value which actually changed due to a restriction having been applied.
final String property = Settings.Secure.SYS_PROP_SETTING_VERSION;
- long version = systemPropertiesGetLong(property, 0) + 1;
- systemPropertiesSet(property, Long.toString(version));
+ long version = mInjector.systemPropertiesGetLong(property, 0) + 1;
+ mInjector.systemPropertiesSet(property, Long.toString(version));
final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED;
Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
@@ -5661,17 +5617,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (!enabled && alreadyRestricted) {
if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
- iAudioService.setMicrophoneMute(false, mContext.getPackageName(),
- userHandle);
+ mInjector.getIAudioService()
+ .setMicrophoneMute(false, mContext.getPackageName(), userHandle);
} else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
- iAudioService.setMasterMute(false, 0, mContext.getPackageName(),
- userHandle);
+ mInjector.getIAudioService()
+ .setMasterMute(false, 0, mContext.getPackageName(), userHandle);
}
}
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
sendChangedNotification(userHandle);
}
@@ -5685,15 +5641,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- IPackageManager pm = getIPackageManager();
- return pm.setApplicationHiddenSettingAsUser(packageName, hidden, callingUserId);
+ return mIPackageManager.setApplicationHiddenSettingAsUser(
+ packageName, hidden, callingUserId);
} catch (RemoteException re) {
// shouldn't happen
Slog.e(LOG_TAG, "Failed to setApplicationHiddenSetting", re);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return false;
}
@@ -5706,15 +5662,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- IPackageManager pm = getIPackageManager();
- return pm.getApplicationHiddenSettingAsUser(packageName, callingUserId);
+ return mIPackageManager.getApplicationHiddenSettingAsUser(
+ packageName, callingUserId);
} catch (RemoteException re) {
// shouldn't happen
Slog.e(LOG_TAG, "Failed to getApplicationHiddenSettingAsUser", re);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return false;
}
@@ -5729,7 +5685,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
if (DBG) {
@@ -5745,19 +5701,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
primaryUser = um.getUserInfo(userId);
}
- IPackageManager pm = getIPackageManager();
- if (!isSystemApp(pm, packageName, primaryUser.id)) {
+ if (!isSystemApp(mIPackageManager, packageName, primaryUser.id)) {
throw new IllegalArgumentException("Only system apps can be enabled this way.");
}
// Install the app.
- pm.installExistingPackageAsUser(packageName, userId);
+ mIPackageManager.installExistingPackageAsUser(packageName, userId);
} catch (RemoteException re) {
// shouldn't happen
Slog.wtf(LOG_TAG, "Failed to install " + packageName, re);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5771,7 +5726,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserManager um = UserManager.get(mContext);
@@ -5782,8 +5737,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
primaryUser = um.getUserInfo(userId);
}
- IPackageManager pm = getIPackageManager();
- List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent,
+ List<ResolveInfo> activitiesToEnable = mIPackageManager.queryIntentActivities(
+ intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
0, // no flags
primaryUser.id);
@@ -5794,9 +5749,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
for (ResolveInfo info : activitiesToEnable) {
if (info.activityInfo != null) {
String packageName = info.activityInfo.packageName;
- if (isSystemApp(pm, packageName, primaryUser.id)) {
+ if (isSystemApp(mIPackageManager, packageName, primaryUser.id)) {
numberOfAppsInstalled++;
- pm.installExistingPackageAsUser(packageName, userId);
+ mIPackageManager.installExistingPackageAsUser(packageName, userId);
} else {
Slog.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
+ " system app");
@@ -5810,7 +5765,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slog.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
return 0;
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5876,15 +5831,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- IPackageManager pm = getIPackageManager();
- pm.setBlockUninstallForUser(packageName, uninstallBlocked, userId);
+ mIPackageManager.setBlockUninstallForUser(packageName, uninstallBlocked, userId);
} catch (RemoteException re) {
// Shouldn't happen.
Slog.e(LOG_TAG, "Failed to setBlockUninstallForUser", re);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5901,15 +5855,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
}
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- IPackageManager pm = getIPackageManager();
- return pm.getBlockUninstallForUser(packageName, userId);
+ return mIPackageManager.getBlockUninstallForUser(packageName, userId);
} catch (RemoteException re) {
// Shouldn't happen.
Slog.e(LOG_TAG, "Failed to getBlockUninstallForUser", re);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
return false;
@@ -5961,7 +5914,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
actualLookupKey, actualContactId, originalIntent);
final int callingUserId = UserHandle.getCallingUserId();
- final long ident = binderClearCallingIdentity();
+ final long ident = mInjector.binderClearCallingIdentity();
try {
synchronized (this) {
final int managedUserId = getManagedUserId(callingUserId);
@@ -5979,7 +5932,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext, intent, new UserHandle(managedUserId));
}
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -6060,7 +6013,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- int userHandle = binderGetCallingUserHandle().getIdentifier();
+ int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
}
}
@@ -6082,7 +6035,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- int userHandle = binderGetCallingUserHandle().getIdentifier();
+ int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
final List<String> packages = getLockTaskPackagesLocked(userHandle);
return packages.toArray(new String[packages.size()]);
}
@@ -6101,7 +6054,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public boolean isLockTaskPermitted(String pkg) {
// Get current user's devicepolicy
- int uid = binderGetCallingUid();
+ int uid = mInjector.binderGetCallingUid();
int userHandle = UserHandle.getUserId(uid);
DevicePolicyData policy = getUserData(userHandle);
synchronized (this) {
@@ -6120,7 +6073,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userHandle) {
- if (binderGetCallingUid() != Process.SYSTEM_UID) {
+ if (mInjector.binderGetCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("notifyLockTaskModeChanged can only be called by system");
}
synchronized (this) {
@@ -6171,11 +6124,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
Settings.Global.putString(contentResolver, setting, value);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -6200,11 +6153,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"Permission denial: Profile owners cannot update %1$s", setting));
}
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
Settings.Secure.putStringForUser(contentResolver, setting, value, callingUserId);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -6215,7 +6168,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
- long identity = binderClearCallingIdentity();
+ long identity = mInjector.binderClearCallingIdentity();
try {
IAudioService iAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
@@ -6223,7 +6176,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed to setMasterMute", re);
} finally {
- binderRestoreCallingIdentity(identity);
+ mInjector.binderRestoreCallingIdentity(identity);
}
}
}
@@ -6247,11 +6200,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
- long id = binderClearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
mUserManager.setUserIcon(userId, icon);
} finally {
- binderRestoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -6265,7 +6218,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int userId = UserHandle.getCallingUserId();
LockPatternUtils utils = new LockPatternUtils(mContext);
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
// disallow disabling the keyguard if a password is currently set
if (disabled && utils.isSecure(userId)) {
@@ -6273,7 +6226,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
utils.setLockScreenDisabled(disabled, userId);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
return true;
}
@@ -6296,7 +6249,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private boolean setStatusBarDisabledInternal(boolean disabled, int userId) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
ServiceManager.checkService(Context.STATUS_BAR_SERVICE));
@@ -6310,7 +6263,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to disable the status bar", e);
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
return false;
}
@@ -6541,7 +6494,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.e(LOG_TAG, "Cannot find device owner package", e);
}
if (receivers != null) {
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
for (int i = 0; i < receivers.length; i++) {
if (permission.BIND_DEVICE_ADMIN.equals(receivers[i].permission)) {
@@ -6551,7 +6504,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -6582,12 +6535,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public boolean setPermissionGrantState(ComponentName admin, String packageName,
String permission, int grantState) throws RemoteException {
- UserHandle user = binderGetCallingUserHandle();
+ UserHandle user = mInjector.binderGetCallingUserHandle();
synchronized (this) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- final ApplicationInfo ai = getIPackageManager()
+ final ApplicationInfo ai = mIPackageManager
.getApplicationInfo(packageName, 0, user.getIdentifier());
final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion;
if (targetSdkVersion < android.os.Build.VERSION_CODES.M) {
@@ -6619,7 +6572,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} catch (SecurityException se) {
return false;
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -6629,12 +6582,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
String permission) throws RemoteException {
PackageManager packageManager = mContext.getPackageManager();
- UserHandle user = binderGetCallingUserHandle();
+ UserHandle user = mInjector.binderGetCallingUserHandle();
synchronized (this) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long ident = binderClearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- int granted = getIPackageManager().checkPermission(permission,
+ int granted = mIPackageManager.checkPermission(permission,
packageName, user.getIdentifier());
int permFlags = packageManager.getPermissionFlags(permission, packageName, user);
if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED)
@@ -6648,8 +6601,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
: DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
}
} finally {
- binderRestoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
+
+ boolean isPackageInstalledForUser(String packageName, int userHandle) {
+ try {
+ PackageInfo pi = mIPackageManager.getPackageInfo(packageName, 0, userHandle);
+ return (pi != null) && (pi.applicationInfo.flags != 0);
+ } catch (RemoteException re) {
+ throw new RuntimeException("Package manager has died", re);
+ }
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 87cf28f861d8..370cf48b4655 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -101,7 +101,7 @@ class Owners {
public Owners(Context context) {
mContext = context;
- mUserManager = UserManager.get(mContext);
+ mUserManager = context.getSystemService(UserManager.class);
}
/**
@@ -230,20 +230,6 @@ class Owners {
return mDeviceOwner != null;
}
- static boolean isInstalledForUser(String packageName, int userHandle) {
- try {
- PackageInfo pi = (AppGlobals.getPackageManager())
- .getPackageInfo(packageName, 0, userHandle);
- if (pi != null && pi.applicationInfo.flags != 0) {
- return true;
- }
- } catch (RemoteException re) {
- throw new RuntimeException("Package manager has died", re);
- }
-
- return false;
- }
-
private boolean readLegacyOwnerFile(File file) {
if (!file.exists()) {
// Already migrated or the device has no owners.
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 93dc6cbcfe99..1ec1a46f3620 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -867,6 +867,11 @@ public final class SystemServer {
if (!disableNonCoreServices) {
mSystemServiceManager.startService(DockObserver.class);
+
+ if (context.getPackageManager().hasSystemFeature
+ (PackageManager.FEATURE_WATCH)) {
+ mSystemServiceManager.startService(ThermalObserver.class);
+ }
}
traceBeginAndSlog("StartWiredAccessoryManager");
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 9ee9cf4fbcc6..e0d2ac12be21 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -244,8 +244,9 @@ public class DhcpClient extends BaseDhcpStateMachine {
private PendingIntent createStateMachineCommandIntent(final String cmdName, final int cmd) {
String action = DhcpClient.class.getName() + "." + mIfaceName + "." + cmdName;
- Intent intent = new Intent(action, null)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ Intent intent = new Intent(action, null).addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+ Intent.FLAG_RECEIVER_FOREGROUND);
// TODO: The intent's package covers the whole of the system server, so it's pretty generic.
// Consider adding some sort of token as well.
intent.setPackage(mContext.getPackageName());
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 3acd56560f4a..53f55cdc847f 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -60,6 +60,74 @@ import java.util.Set;
* Monitors on-link IP reachability and notifies callers whenever any on-link
* addresses of interest appear to have become unresponsive.
*
+ * This code does not concern itself with "why" a neighbour might have become
+ * unreachable. Instead, it primarily reacts to the kernel's notion of IP
+ * reachability for each of the neighbours we know to be critically important
+ * to normal network connectivity. As such, it is often "just the messenger":
+ * the neighbours about which it warns are already deemed by the kernel to have
+ * become unreachable.
+ *
+ *
+ * How it works:
+ *
+ * 1. The "on-link neighbours of interest" found in a given LinkProperties
+ * instance are added to a "watch list" via #updateLinkProperties().
+ * This usually means all default gateways and any on-link DNS servers.
+ *
+ * 2. We listen continuously for netlink neighbour messages (RTM_NEWNEIGH,
+ * RTM_DELNEIGH), watching only for neighbours in the watch list.
+ *
+ * - A neighbour going into NUD_REACHABLE, NUD_STALE, NUD_DELAY, and
+ * even NUD_PROBE is perfectly normal; we merely record the new state.
+ *
+ * - A neighbour's entry may be deleted (RTM_DELNEIGH), for example due
+ * to garbage collection. This is not necessarily of immediate
+ * concern; we record the neighbour as moving to NUD_NONE.
+ *
+ * - A neighbour transitioning to NUD_FAILED (for any reason) is
+ * critically important and is handled as described below in #4.
+ *
+ * 3. All on-link neighbours in the watch list can be forcibly "probed" by
+ * calling #probeAll(). This should be called whenever it is important to
+ * verify that critical neighbours on the link are still reachable, e.g.
+ * when roaming between BSSIDs.
+ *
+ * - The kernel will send unicast ARP requests for IPv4 neighbours and
+ * unicast NS packets for IPv6 neighbours. The expected replies will
+ * likely be unicast.
+ *
+ * - The forced probing is done holding a wakelock. The kernel may,
+ * however, initiate probing of a neighbor on its own, i.e. whenever
+ * a neighbour has expired from NUD_DELAY.
+ *
+ * - The kernel sends:
+ *
+ * /proc/sys/net/ipv{4,6}/neigh/<ifname>/ucast_solicit
+ *
+ * number of probes (usually 3) every:
+ *
+ * /proc/sys/net/ipv{4,6}/neigh/<ifname>/retrans_time_ms
+ *
+ * number of milliseconds (usually 1000ms). This normally results in
+ * 3 unicast packets, 1 per second.
+ *
+ * - If no response is received to any of the probe packets, the kernel
+ * marks the neighbour as being in state NUD_FAILED, and the listening
+ * process in #2 will learn of it.
+ *
+ * 4. We call the supplied Callback#notifyLost() function if the loss of a
+ * neighbour in NUD_FAILED would cause IPv4 or IPv6 configuration to
+ * become incomplete (a loss of provisioning).
+ *
+ * - For example, losing all our IPv4 on-link DNS servers (or losing
+ * our only IPv6 default gateway) constitutes a loss of IPv4 (IPv6)
+ * provisioning; Callback#notifyLost() would be called.
+ *
+ * - Since it can be non-trivial to reacquire certain IP provisioning
+ * state it may be best for the link to disconnect completely and
+ * reconnect afresh.
+ *
+ *
* @hide
*/
public class IpReachabilityMonitor {
@@ -355,7 +423,7 @@ public class IpReachabilityMonitor {
try {
byteBuffer = recvKernelReply();
} catch (ErrnoException e) {
- Log.w(TAG, "ErrnoException: ", e);
+ if (stillRunning()) { Log.w(TAG, "ErrnoException: ", e); }
break;
}
final long whenMs = SystemClock.elapsedRealtime();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
deleted file mode 100644
index ca270e7a4b2a..000000000000
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 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.server.devicepolicy;
-
-import android.app.admin.DeviceAdminReceiver;
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-/**
- * Tests for application restrictions persisting via profile owner:
- * make -j FrameworksServicesTests
- * runtest --path frameworks/base/services/tests/servicestests/ \
- * src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
- */
-public class ApplicationRestrictionsTest extends AndroidTestCase {
-
- static DevicePolicyManager sDpm;
- static ComponentName sAdminReceiver;
- private static final String RESTRICTED_APP = "com.example.restrictedApp";
- static boolean sAddBack = false;
-
- public static class AdminReceiver extends DeviceAdminReceiver {
-
- @Override
- public void onDisabled(Context context, Intent intent) {
- if (sAddBack) {
- sDpm.setActiveAdmin(sAdminReceiver, false);
- sAddBack = false;
- }
-
- super.onDisabled(context, intent);
- }
- }
-
- @Override
- public void setUp() {
- final Context context = getContext();
- sAdminReceiver = new ComponentName(mContext.getPackageName(),
- AdminReceiver.class.getName());
- sDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
- Settings.Secure.putInt(context.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0);
- sDpm.setProfileOwner(sAdminReceiver, "Test", UserHandle.myUserId());
- Settings.Secure.putInt(context.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 1);
- // Remove the admin if already registered. It's async, so add it back
- // when the admin gets a broadcast. Otherwise add it back right away.
- if (sDpm.isAdminActive(sAdminReceiver)) {
- sAddBack = true;
- sDpm.removeActiveAdmin(sAdminReceiver);
- } else {
- sDpm.setActiveAdmin(sAdminReceiver, false);
- }
- }
-
- @Override
- public void tearDown() {
- Settings.Secure.putInt(getContext().getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0);
- sDpm.removeActiveAdmin(sAdminReceiver);
- Settings.Secure.putInt(getContext().getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 1);
- }
-
- public void testSettingRestrictions() {
- Bundle restrictions = new Bundle();
- restrictions.putString("KEY_STRING", "Foo");
- assertNotNull(sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP));
- sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
- Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
- assertNotNull(returned);
- assertEquals(returned.size(), 1);
- assertEquals(returned.get("KEY_STRING"), "Foo");
- sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, new Bundle());
- returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
- assertEquals(returned.size(), 0);
- }
-
- public void testRestrictionTypes() {
- Bundle restrictions = new Bundle();
- restrictions.putString("KEY_STRING", "Foo");
- restrictions.putInt("KEY_INT", 7);
- restrictions.putBoolean("KEY_BOOLEAN", true);
- restrictions.putBoolean("KEY_BOOLEAN_2", false);
- restrictions.putString("KEY_STRING_2", "Bar");
- restrictions.putStringArray("KEY_STR_ARRAY", new String[] { "Foo", "Bar" });
- sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
- Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
- assertTrue(returned.getBoolean("KEY_BOOLEAN"));
- assertFalse(returned.getBoolean("KEY_BOOLEAN_2"));
- assertFalse(returned.getBoolean("KEY_BOOLEAN_3"));
- assertEquals(returned.getInt("KEY_INT"), 7);
- assertTrue(returned.get("KEY_BOOLEAN") instanceof Boolean);
- assertTrue(returned.get("KEY_INT") instanceof Integer);
- assertEquals(returned.get("KEY_STRING"), "Foo");
- assertEquals(returned.get("KEY_STRING_2"), "Bar");
- assertTrue(returned.getStringArray("KEY_STR_ARRAY") instanceof String[]);
- sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, new Bundle());
- }
-
- public void testTextEscaping() {
- String fancyText = "<This contains XML/> <JSON> "
- + "{ \"One\": { \"OneOne\": \"11\", \"OneTwo\": \"12\" }, \"Two\": \"2\" } <JSON/>";
- Bundle restrictions = new Bundle();
- restrictions.putString("KEY_FANCY_TEXT", fancyText);
- sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
- Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
- assertEquals(returned.getString("KEY_FANCY_TEXT"), fancyText);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 7e730f6b5289..f4ffe2ee1d27 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -19,11 +19,11 @@ import com.android.internal.widget.LockPatternUtils;
import android.app.IActivityManager;
import android.app.NotificationManager;
+import android.app.backup.IBackupManager;
import android.content.Context;
import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
+import android.media.IAudioService;
import android.os.Looper;
-import android.os.PowerManager.WakeLock;
import android.os.PowerManagerInternal;
import android.os.UserHandle;
import android.os.UserManager;
@@ -50,11 +50,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
private final File mDeviceOwnerFile;
private final File mProfileOwnerBase;
- public OwnersTestable(Context context, File dataDir) {
+ public OwnersTestable(DpmMockContext context) {
super(context);
- mLegacyFile = new File(dataDir, LEGACY_FILE);
- mDeviceOwnerFile = new File(dataDir, DEVICE_OWNER_FILE);
- mProfileOwnerBase = new File(dataDir, PROFILE_OWNER_FILE_BASE);
+ mLegacyFile = new File(context.dataDir, LEGACY_FILE);
+ mDeviceOwnerFile = new File(context.dataDir, DEVICE_OWNER_FILE);
+ mProfileOwnerBase = new File(context.dataDir, PROFILE_OWNER_FILE_BASE);
}
@Override
@@ -73,146 +73,157 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
}
}
- public final File dataDir;
- public final File systemUserDataDir;
- public final File secondUserDataDir;
+ public final DpmMockContext context;
public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
- super(context);
- this.dataDir = dataDir;
+ this(new MockInjector(context, dataDir));
+ }
- systemUserDataDir = new File(dataDir, "user0");
- DpmTestUtils.clearDir(dataDir);
+ private DevicePolicyManagerServiceTestable(MockInjector injector) {
+ super(injector);
+ this.context = injector.context;
+ }
- secondUserDataDir = new File(dataDir, "user" + DpmMockContext.CALLER_USER_HANDLE);
- DpmTestUtils.clearDir(secondUserDataDir);
+ private static class MockInjector extends Injector {
- when(getContext().environment.getUserSystemDirectory(
- eq(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(secondUserDataDir);
- }
+ public final DpmMockContext context;
- @Override
- DpmMockContext getContext() {
- return (DpmMockContext) super.getContext();
- }
+ public final File dataDir;
- @Override
- Owners newOwners() {
- return new OwnersTestable(getContext(), dataDir);
- }
+ private MockInjector(DpmMockContext context, File dataDir) {
+ super(context);
+ this.context = context;
+ this.dataDir = dataDir;
+ }
- @Override
- UserManager getUserManager() {
- return getContext().userManager;
- }
+ @Override
+ Owners newOwners() {
+ return new OwnersTestable(context);
+ }
- @Override
- PackageManager getPackageManager() {
- return getContext().packageManager;
- }
+ @Override
+ UserManager getUserManager() {
+ return context.userManager;
+ }
- @Override
- PowerManagerInternal getPowerManagerInternal() {
- return getContext().powerManagerInternal;
- }
+ @Override
+ PowerManagerInternal getPowerManagerInternal() {
+ return context.powerManagerInternal;
+ }
- @Override
- NotificationManager getNotificationManager() {
- return getContext().notificationManager;
- }
+ @Override
+ NotificationManager getNotificationManager() {
+ return context.notificationManager;
+ }
- @Override
- IWindowManager getIWindowManager() {
- return getContext().iwindowManager;
- }
+ @Override
+ IWindowManager getIWindowManager() {
+ return context.iwindowManager;
+ }
- @Override
- IActivityManager getIActivityManager() {
- return getContext().iactivityManager;
- }
+ @Override
+ IActivityManager getIActivityManager() {
+ return context.iactivityManager;
+ }
- @Override
- IPackageManager getIPackageManager() {
- return getContext().ipackageManager;
- }
+ @Override
+ IPackageManager getIPackageManager() {
+ return context.ipackageManager;
+ }
- @Override
- LockPatternUtils newLockPatternUtils(Context context) {
- return getContext().lockPatternUtils;
- }
+ @Override
+ IBackupManager getIBackupManager() {
+ return context.ibackupManager;
+ }
- @Override
- Looper getMyLooper() {
- return Looper.getMainLooper();
- }
+ @Override
+ IAudioService getIAudioService() {
+ return context.iaudioService;
+ }
- @Override
- String getDevicePolicyFilePathForSystemUser() {
- return systemUserDataDir.getAbsolutePath();
- }
+ @Override
+ Looper getMyLooper() {
+ return Looper.getMainLooper();
+ }
- @Override
- long binderClearCallingIdentity() {
- return getContext().binder.clearCallingIdentity();
- }
+ @Override
+ LockPatternUtils newLockPatternUtils() {
+ return context.lockPatternUtils;
+ }
- @Override
- void binderRestoreCallingIdentity(long token) {
- getContext().binder.restoreCallingIdentity(token);
- }
+ @Override
+ String getDevicePolicyFilePathForSystemUser() {
+ return context.systemUserDataDir.getAbsolutePath();
+ }
- @Override
- int binderGetCallingUid() {
- return getContext().binder.getCallingUid();
- }
+ @Override
+ long binderClearCallingIdentity() {
+ return context.binder.clearCallingIdentity();
+ }
- @Override
- int binderGetCallingPid() {
- return getContext().binder.getCallingPid();
- }
+ @Override
+ void binderRestoreCallingIdentity(long token) {
+ context.binder.restoreCallingIdentity(token);
+ }
- @Override
- UserHandle binderGetCallingUserHandle() {
- return getContext().binder.getCallingUserHandle();
- }
+ @Override
+ int binderGetCallingUid() {
+ return context.binder.getCallingUid();
+ }
- @Override
- boolean binderIsCallingUidMyUid() {
- return getContext().binder.isCallerUidMyUid();
- }
+ @Override
+ int binderGetCallingPid() {
+ return context.binder.getCallingPid();
+ }
- @Override
- File environmentGetUserSystemDirectory(int userId) {
- return getContext().environment.getUserSystemDirectory(userId);
- }
+ @Override
+ UserHandle binderGetCallingUserHandle() {
+ return context.binder.getCallingUserHandle();
+ }
- @Override
- void powerManagerGoToSleep(long time, int reason, int flags) {
- getContext().powerManager.goToSleep(time, reason, flags);
- }
+ @Override
+ boolean binderIsCallingUidMyUid() {
+ return context.binder.isCallerUidMyUid();
+ }
- @Override
- boolean systemPropertiesGetBoolean(String key, boolean def) {
- return getContext().systemProperties.getBoolean(key, def);
- }
+ @Override
+ File environmentGetUserSystemDirectory(int userId) {
+ return context.environment.getUserSystemDirectory(userId);
+ }
- @Override
- long systemPropertiesGetLong(String key, long def) {
- return getContext().systemProperties.getLong(key, def);
- }
+ @Override
+ void powerManagerGoToSleep(long time, int reason, int flags) {
+ context.powerManager.goToSleep(time, reason, flags);
+ }
- @Override
- String systemPropertiesGet(String key, String def) {
- return getContext().systemProperties.get(key, def);
- }
+ @Override
+ boolean systemPropertiesGetBoolean(String key, boolean def) {
+ return context.systemProperties.getBoolean(key, def);
+ }
- @Override
- String systemPropertiesGet(String key) {
- return getContext().systemProperties.get(key);
- }
+ @Override
+ long systemPropertiesGetLong(String key, long def) {
+ return context.systemProperties.getLong(key, def);
+ }
- @Override
- void systemPropertiesSet(String key, String value) {
- getContext().systemProperties.set(key, value);
+ @Override
+ String systemPropertiesGet(String key, String def) {
+ return context.systemProperties.get(key, def);
+ }
+
+ @Override
+ String systemPropertiesGet(String key) {
+ return context.systemProperties.get(key);
+ }
+
+ @Override
+ void systemPropertiesSet(String key, String value) {
+ context.systemProperties.set(key, value);
+ }
+
+ @Override
+ boolean userManagerIsSplitSystemUser() {
+ return context.userManagerForMock.isSplitSystemUser();
+ }
}
}
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 0da459dab0d6..5b2379833ad6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -30,15 +30,24 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
+import android.content.pm.PackageInfo;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.util.Pair;
import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -82,11 +91,15 @@ public class DevicePolicyManagerTest extends DpmTestBase {
admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
- setUpPackageManagerForAdmin(admin1);
- setUpPackageManagerForAdmin(admin2);
- setUpPackageManagerForAdmin(admin3);
+ setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
+ setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
+ setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
- setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
+ setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
+ DpmMockContext.CALLER_UID);
+
+ setUpPackageInfo();
+ setUpUserManager();
}
/**
@@ -94,7 +107,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
* the actual ResolveInfo for the admin component, but we need to mock PM so it'll return
* it for user {@link DpmMockContext#CALLER_USER_HANDLE}.
*/
- private void setUpPackageManagerForAdmin(ComponentName admin) {
+ private void setUpPackageManagerForAdmin(ComponentName admin, int packageUid) {
final Intent resolveIntent = new Intent();
resolveIntent.setComponent(admin);
final List<ResolveInfo> realResolveInfo =
@@ -104,35 +117,109 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertNotNull(realResolveInfo);
assertEquals(1, realResolveInfo.size());
+ // We need to change AI, so set a clone.
+ realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0)));
+
// We need to rewrite the UID in the activity info.
- realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID;
+ realResolveInfo.get(0).activityInfo.applicationInfo.uid = packageUid;
doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers(
MockUtils.checkIntentComponent(admin),
eq(PackageManager.GET_META_DATA
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
- eq(DpmMockContext.CALLER_USER_HANDLE)
- );
+ eq(UserHandle.getUserId(packageUid)));
}
/**
* Set up a mock result for {@link IPackageManager#getApplicationInfo} for user
* {@link DpmMockContext#CALLER_USER_HANDLE}.
*/
- private void setUpApplicationInfo(int enabledSetting) throws Exception {
- final ApplicationInfo ai = mRealTestContext.getPackageManager().getApplicationInfo(
- admin1.getPackageName(),
- PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
+ private void setUpApplicationInfo(int enabledSetting, int packageUid) throws Exception {
+ final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
+ mRealTestContext.getPackageManager().getApplicationInfo(
+ admin1.getPackageName(),
+ PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
ai.enabledSetting = enabledSetting;
+ ai.uid = packageUid;
doReturn(ai).when(mContext.ipackageManager).getApplicationInfo(
eq(admin1.getPackageName()),
eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+ eq(UserHandle.getUserId(packageUid)));
+ }
+
+ /**
+ * Set up a mock result for {@link IPackageManager#getPackageInfo(String, int, int)} for user
+ * {@link DpmMockContext#CALLER_USER_HANDLE} as well as the system user.
+ */
+ private void setUpPackageInfo() throws Exception {
+ final PackageInfo pi = mRealTestContext.getPackageManager().getPackageInfo(
+ admin1.getPackageName(), 0);
+ assertTrue(pi.applicationInfo.flags != 0);
+
+ doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
+ eq(admin1.getPackageName()),
+ eq(0),
eq(DpmMockContext.CALLER_USER_HANDLE));
+ doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
+ eq(admin1.getPackageName()),
+ eq(0),
+ eq(UserHandle.USER_SYSTEM));
+ }
+
+ private void setUpUserManager() {
+ // Emulate UserManager.set/getApplicationRestriction().
+ final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>();
+
+ // UM.setApplicationRestrictions() will save to appRestrictions.
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String pkg = (String) invocation.getArguments()[0];
+ Bundle bundle = (Bundle) invocation.getArguments()[1];
+ UserHandle user = (UserHandle) invocation.getArguments()[2];
+
+ appRestrictions.put(Pair.create(pkg, user), bundle);
+
+ return null;
+ }
+ }).when(mContext.userManager).setApplicationRestrictions(
+ anyString(), any(Bundle.class), any(UserHandle.class));
+
+ // UM.getApplicationRestrictions() will read from appRestrictions.
+ doAnswer(new Answer<Bundle>() {
+ @Override
+ public Bundle answer(InvocationOnMock invocation) throws Throwable {
+ String pkg = (String) invocation.getArguments()[0];
+ UserHandle user = (UserHandle) invocation.getArguments()[1];
+
+ return appRestrictions.get(Pair.create(pkg, user));
+ }
+ }).when(mContext.userManager).getApplicationRestrictions(
+ anyString(), any(UserHandle.class));
+
+ // Add the first secondary user.
+ mContext.addUser(DpmMockContext.CALLER_USER_HANDLE, 0);
}
- public void testHasNoFeature() {
+ private void setAsProfileOwner(ComponentName admin) {
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+ final UserInfo uh = new UserInfo(DpmMockContext.CALLER_USER_HANDLE, "user", 0);
+
+ // DO needs to be an DA.
+ dpm.setActiveAdmin(admin, /* replace =*/ false);
+
+ // Fire!
+ assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
+
+ // Check
+ assertEquals(admin1, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE));
+ }
+
+ public void testHasNoFeature() throws Exception {
when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
.thenReturn(false);
@@ -220,7 +307,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Next, add one more admin.
// Before doing so, update the application info, now it's enabled.
- setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+ setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ DpmMockContext.CALLER_UID);
dpm.setActiveAdmin(admin2, /* replace =*/ false);
@@ -265,6 +353,35 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
}
+ public void testSetActiveAdmin_multiUsers() throws Exception {
+
+ final int ANOTHER_USER_ID = 100;
+ final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 20456);
+
+ mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user.
+
+ // Set up pacakge manager for the other user.
+ setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID);
+ setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
+ ANOTHER_ADMIN_UID);
+
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+ mMockContext.binder.callingUid = ANOTHER_ADMIN_UID;
+ dpm.setActiveAdmin(admin2, /* replace =*/ false);
+
+
+ mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ assertTrue(dpm.isAdminActive(admin1));
+ assertFalse(dpm.isAdminActive(admin2));
+
+ mMockContext.binder.callingUid = ANOTHER_ADMIN_UID;
+ assertFalse(dpm.isAdminActive(admin1));
+ assertTrue(dpm.isAdminActive(admin2));
+ }
+
/**
* Test for:
* {@link DevicePolicyManager#setActiveAdmin}
@@ -311,9 +428,11 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// having MANAGE_DEVICE_ADMINS.
mContext.callerPermissions.clear();
+ // Change the caller, and call into DPMS directly with a different user-id.
+
mContext.binder.callingUid = 1234567;
try {
- dpm.removeActiveAdmin(admin1);
+ dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
fail("Didn't throw SecurityException");
} catch (SecurityException expected) {
}
@@ -323,7 +442,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
* Test for:
* {@link DevicePolicyManager#removeActiveAdmin}
*/
- public void testRemoveActiveAdmin_fromDifferentUserWithMINTERACT_ACROSS_USERS_FULL() {
+ public void testRemoveActiveAdmin_fromDifferentUserWithINTERACT_ACROSS_USERS_FULL() {
mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
// Add admin1.
@@ -335,8 +454,11 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Different user, but should work, because caller has proper permissions.
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+
+ // Change the caller, and call into DPMS directly with a different user-id.
mContext.binder.callingUid = 1234567;
- dpm.removeActiveAdmin(admin1);
+
+ dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
@@ -399,6 +521,108 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// TODO Check other internal calls.
}
-}
+ /**
+ * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs
+ * successfully.
+ */
+ public void testSetDeviceOwner() throws Exception {
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+
+ // In this test, change the caller user to "system".
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ // Make sure admin1 is installed on system user.
+ setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+ setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
+ DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+ // DO needs to be an DA.
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+ // Fire!
+ assertTrue(dpm.setDeviceOwner(admin1.getPackageName(), "owner-name"));
+
+ // Verify internal calls.
+ verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
+ eq(admin1.getPackageName()));
+
+ // TODO We should check if the caller has called clearCallerIdentity().
+ verify(mContext.ibackupManager, times(1)).setBackupServiceActive(
+ eq(UserHandle.USER_SYSTEM), eq(false));
+
+ verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+ MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
+ MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
+ assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+
+ // TODO Test getDeviceOwnerName() too. To do so, we need to change
+ // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
+ }
+
+ /**
+ * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist.
+ */
+ public void testSetDeviceOwner_noSuchPackage() {
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+
+ // Call from a process on the system user.
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ try {
+ dpm.setDeviceOwner("a.b.c");
+ fail("Didn't throw IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSetDeviceOwner_failures() throws Exception {
+ // TODO Test more failure cases. Basically test all chacks in enforceCanSetDeviceOwner().
+ }
+
+ public void testSetProfileOwner() throws Exception {
+ setAsProfileOwner(admin1);
+ }
+
+ public void testSetProfileOwner_failures() throws Exception {
+ // TODO Test more failure cases. Basically test all chacks in enforceCanSetProfileOwner().
+ }
+
+ public void testSetGetApplicationRestriction() {
+ setAsProfileOwner(admin1);
+
+ {
+ Bundle rest = new Bundle();
+ rest.putString("KEY_STRING", "Foo1");
+ dpm.setApplicationRestrictions(admin1, "pkg1", rest);
+ }
+
+ {
+ Bundle rest = new Bundle();
+ rest.putString("KEY_STRING", "Foo2");
+ dpm.setApplicationRestrictions(admin1, "pkg2", rest);
+ }
+
+ {
+ Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg1");
+ assertNotNull(returned);
+ assertEquals(returned.size(), 1);
+ assertEquals(returned.get("KEY_STRING"), "Foo1");
+ }
+
+ {
+ Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg2");
+ assertNotNull(returned);
+ assertEquals(returned.size(), 1);
+ assertEquals(returned.get("KEY_STRING"), "Foo2");
+ }
+
+ dpm.setApplicationRestrictions(admin1, "pkg2", new Bundle());
+ assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
index 325bf9ff0225..b80f3bf8d58d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
@@ -16,6 +16,7 @@
package com.android.server.devicepolicy;
import android.app.admin.DevicePolicyManager;
+import android.os.UserHandle;
/**
* Overrides {@link #DevicePolicyManager} for dependency injection.
@@ -31,6 +32,6 @@ public class DevicePolicyManagerTestable extends DevicePolicyManager {
@Override
public int myUserId() {
- return DpmMockContext.CALLER_USER_HANDLE;
+ return UserHandle.getUserId(dpms.context.binder.callingUid);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 6bb9833a883c..7b36e88c5e29 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -16,33 +16,38 @@
package com.android.server.devicepolicy;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
import android.app.IActivityManager;
import android.app.NotificationManager;
+import android.app.backup.IBackupManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.media.IAudioService;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager.WakeLock;
import android.os.PowerManagerInternal;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.mock.MockContext;
import android.view.IWindowManager;
+import org.junit.Assert;
+
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
/**
* Context used throughout DPMS tests.
@@ -54,9 +59,14 @@ public class DpmMockContext extends MockContext {
public static final int CALLER_USER_HANDLE = 20;
/**
- * UID of the caller.
+ * UID corresponding to {@link #CALLER_USER_HANDLE}.
+ */
+ public static final int CALLER_UID = UserHandle.getUid(CALLER_USER_HANDLE, 20123);
+
+ /**
+ * UID used when a caller is on the system user.
*/
- public static final int CALLER_UID = UserHandle.PER_USER_RANGE * CALLER_USER_HANDLE + 123;
+ public static final int CALLER_SYSTEM_USER_UID = 20321;
/**
* PID of the caller.
@@ -142,6 +152,12 @@ public class DpmMockContext extends MockContext {
}
}
+ public static class UserManagerForMock {
+ public boolean isSplitSystemUser() {
+ return false;
+ }
+ }
+
public final Context realTestContext;
/**
@@ -151,16 +167,22 @@ public class DpmMockContext extends MockContext {
*/
public final Context spiedContext;
+ public final File dataDir;
+ public final File systemUserDataDir;
+
public final MockBinder binder;
public final EnvironmentForMock environment;
public final SystemPropertiesForMock systemProperties;
public final UserManager userManager;
+ public final UserManagerForMock userManagerForMock;
public final PowerManagerForMock powerManager;
public final PowerManagerInternal powerManagerInternal;
public final NotificationManager notificationManager;
public final IWindowManager iwindowManager;
public final IActivityManager iactivityManager;
public final IPackageManager ipackageManager;
+ public final IBackupManager ibackupManager;
+ public final IAudioService iaudioService;
public final LockPatternUtils lockPatternUtils;
/** Note this is a partial mock, not a real mock. */
@@ -168,24 +190,66 @@ public class DpmMockContext extends MockContext {
public final List<String> callerPermissions = new ArrayList<>();
- public DpmMockContext(Context context) {
+ private final ArrayList<UserInfo> mUserInfos = new ArrayList<>();
+
+ public DpmMockContext(Context context, File dataDir) {
realTestContext = context;
+
+ this.dataDir = dataDir;
+ DpmTestUtils.clearDir(dataDir);
+
binder = new MockBinder();
environment = mock(EnvironmentForMock.class);
systemProperties= mock(SystemPropertiesForMock.class);
userManager = mock(UserManager.class);
+ userManagerForMock = mock(UserManagerForMock.class);
powerManager = mock(PowerManagerForMock.class);
powerManagerInternal = mock(PowerManagerInternal.class);
notificationManager = mock(NotificationManager.class);
iwindowManager = mock(IWindowManager.class);
iactivityManager = mock(IActivityManager.class);
ipackageManager = mock(IPackageManager.class);
+ ibackupManager = mock(IBackupManager.class);
+ iaudioService = mock(IAudioService.class);
lockPatternUtils = mock(LockPatternUtils.class);
// Package manager is huge, so we use a partial mock instead.
packageManager = spy(context.getPackageManager());
spiedContext = mock(Context.class);
+
+ // Add the system user
+ systemUserDataDir = addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY);
+
+ // System user is always running.
+ when(userManager.isUserRunning(MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)))
+ .thenReturn(true);
+ }
+
+ public File addUser(int userId, int flags) {
+
+ // Set up (default) UserInfo for CALLER_USER_HANDLE.
+ final UserInfo uh = new UserInfo(userId, "user" + userId, flags);
+ when(userManager.getUserInfo(eq(userId))).thenReturn(uh);
+
+ mUserInfos.add(uh);
+ when(userManager.getUsers()).thenReturn(mUserInfos);
+
+ // Create a data directory.
+ final File dir = new File(dataDir, "user" + userId);
+ DpmTestUtils.clearDir(dir);
+
+ when(environment.getUserSystemDirectory(eq(userId))).thenReturn(dir);
+ return dir;
+ }
+
+ /**
+ * Add multiple users at once. They'll all have flag 0.
+ */
+ public void addUsers(int... userIds) {
+ for (int userId : userIds) {
+ addUser(userId, 0);
+ }
}
@Override
@@ -200,6 +264,11 @@ public class DpmMockContext extends MockContext {
}
@Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ return realTestContext.getSystemServiceName(serviceClass);
+ }
+
+ @Override
public PackageManager getPackageManager() {
return packageManager;
}
@@ -272,6 +341,13 @@ public class DpmMockContext extends MockContext {
@Override
public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+ if (binder.callingPid != SYSTEM_PID) {
+ // Unless called as the system process, can only call if the target user is the
+ // calling user.
+ // (The actual check is more complex; we may need to change it later.)
+ Assert.assertEquals(UserHandle.getUserId(binder.getCallingUid()), user.getIdentifier());
+ }
+
spiedContext.sendBroadcastAsUser(intent, user);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 77270c8cec55..63bf12558dd1 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -21,7 +21,7 @@ import android.test.AndroidTestCase;
import java.io.File;
-public class DpmTestBase extends AndroidTestCase {
+public abstract class DpmTestBase extends AndroidTestCase {
public static final String TAG = "DpmTest";
protected Context mRealTestContext;
@@ -34,10 +34,9 @@ public class DpmTestBase extends AndroidTestCase {
super.setUp();
mRealTestContext = super.getContext();
- mMockContext = new DpmMockContext(super.getContext());
- dataDir = new File(mRealTestContext.getCacheDir(), "test-data");
- DpmTestUtils.clearDir(dataDir);
+ mMockContext = new DpmMockContext(
+ mRealTestContext, new File(mRealTestContext.getCacheDir(), "test-data"));
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
index 44a851abe476..7506273accb7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
@@ -17,6 +17,8 @@
package com.android.server.devicepolicy;
import android.os.FileUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.util.Log;
import android.util.Printer;
@@ -41,6 +43,15 @@ public class DpmTestUtils {
return list == null ? 0 : list.size();
}
+ public static <T extends Parcelable> T cloneParcelable(T source) {
+ Parcel p = Parcel.obtain();
+ p.writeParcelable(source, 0);
+ p.setDataPosition(0);
+ final T clone = p.readParcelable(DpmTestUtils.class.getClassLoader());
+ p.recycle();
+ return clone;
+ }
+
public static Printer LOG_PRINTER = new Printer() {
@Override
public void println(String x) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
index 5cd15557a80d..08293a259145 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
@@ -24,4 +24,4 @@ public class DummyDeviceAdmins {
}
public static class Admin3 extends DeviceAdminReceiver {
}
-} \ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
index a07d61520fa4..4a39614aed99 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -69,22 +69,12 @@ public class OwnersTest extends DpmTestBase {
}
}
- private void addUsersToUserManager(int... userIds) {
- final ArrayList<UserInfo> userInfos = new ArrayList<>();
- for (int userId : userIds) {
- final UserInfo ui = new UserInfo();
- ui.id = userId;
- userInfos.add(ui);
- }
- when(getContext().userManager.getUsers()).thenReturn(userInfos);
- }
-
public void testUpgrade01() throws Exception {
- addUsersToUserManager(10, 11, 20, 21);
+ getContext().addUsers(10, 11, 20, 21);
// First, migrate.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test01/input.xml"));
@@ -111,7 +101,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
owners.load();
assertFalse(owners.hasDeviceOwner());
@@ -123,11 +113,11 @@ public class OwnersTest extends DpmTestBase {
}
public void testUpgrade02() throws Exception {
- addUsersToUserManager(10, 11, 20, 21);
+ getContext().addUsers(10, 11, 20, 21);
// First, migrate.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test02/input.xml"));
@@ -156,7 +146,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
owners.load();
assertTrue(owners.hasDeviceOwner());
@@ -171,11 +161,11 @@ public class OwnersTest extends DpmTestBase {
}
public void testUpgrade03() throws Exception {
- addUsersToUserManager(10, 11, 20, 21);
+ getContext().addUsers(10, 11, 20, 21);
// First, migrate.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test03/input.xml"));
@@ -212,7 +202,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
owners.load();
assertFalse(owners.hasDeviceOwner());
@@ -235,11 +225,11 @@ public class OwnersTest extends DpmTestBase {
}
public void testUpgrade04() throws Exception {
- addUsersToUserManager(10, 11, 20, 21);
+ getContext().addUsers(10, 11, 20, 21);
// First, migrate.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test04/input.xml"));
@@ -281,7 +271,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
owners.load();
assertTrue(owners.hasDeviceOwner());
@@ -309,11 +299,11 @@ public class OwnersTest extends DpmTestBase {
}
public void testUpgrade05() throws Exception {
- addUsersToUserManager(10, 11, 20, 21);
+ getContext().addUsers(10, 11, 20, 21);
// First, migrate.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test05/input.xml"));
@@ -341,7 +331,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
owners.load();
assertFalse(owners.hasDeviceOwner());
@@ -356,11 +346,11 @@ public class OwnersTest extends DpmTestBase {
}
public void testUpgrade06() throws Exception {
- addUsersToUserManager(10, 11, 20, 21);
+ getContext().addUsers(10, 11, 20, 21);
// First, migrate.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test06/input.xml"));
@@ -387,7 +377,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
owners.load();
assertFalse(owners.hasDeviceOwner());
@@ -401,9 +391,9 @@ public class OwnersTest extends DpmTestBase {
}
public void testRemoveExistingFiles() throws Exception {
- addUsersToUserManager(10, 11, 20, 21);
+ getContext().addUsers(10, 11, 20, 21);
- final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
+ final OwnersTestable owners = new OwnersTestable(getContext());
// First, migrate to create new-style config files.
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 8779462e073e..a8f2aca43708 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -14,6 +14,7 @@
package android.telecom;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
@@ -116,6 +117,15 @@ public class TelecomManager {
"android.telecom.action.PHONE_ACCOUNT_REGISTERED";
/**
+ * The {@link android.content.Intent} action used indicate that a phone account was
+ * just unregistered.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_PHONE_ACCOUNT_UNREGISTERED =
+ "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED";
+
+ /**
* Activity action: Shows a dialog asking the user whether or not they want to replace the
* current default Dialer with the one specified in
* {@link #EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME}.
@@ -472,9 +482,12 @@ public class TelecomManager {
* <p>
* If no {@link PhoneAccount} fits the criteria above, this method will return {@code null}.
*
+ * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+ *
* @param uriScheme The URI scheme.
* @return The {@link PhoneAccountHandle} corresponding to the account to be used.
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
try {
if (isServiceConnected()) {
@@ -606,9 +619,12 @@ public class TelecomManager {
* calls. The returned list includes only those accounts which have been explicitly enabled
* by the user.
*
+ * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+ *
* @see #EXTRA_PHONE_ACCOUNT_HANDLE
* @return A list of {@code PhoneAccountHandle} objects.
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
return getCallCapablePhoneAccounts(false);
}
@@ -881,9 +897,12 @@ public class TelecomManager {
* Return whether a given phone number is the configured voicemail number for a
* particular phone account.
*
+ * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+ *
* @param accountHandle The handle for the account to check the voicemail number against
* @param number The number to look up.
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
try {
if (isServiceConnected()) {
@@ -899,10 +918,13 @@ public class TelecomManager {
/**
* Return the voicemail number for a given phone account.
*
+ * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+ *
* @param accountHandle The handle for the phone account.
* @return The voicemail number for the phone account, and {@code null} if one has not been
* configured.
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getVoiceMailNumber(PhoneAccountHandle accountHandle) {
try {
if (isServiceConnected()) {
@@ -918,9 +940,12 @@ public class TelecomManager {
/**
* Return the line 1 phone number for given phone account.
*
+ * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+ *
* @param accountHandle The handle for the account retrieve a number for.
* @return A string representation of the line 1 phone number.
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getLine1Number(PhoneAccountHandle accountHandle) {
try {
if (isServiceConnected()) {
@@ -940,6 +965,7 @@ public class TelecomManager {
* Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
* </p>
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public boolean isInCall() {
try {
if (isServiceConnected()) {
@@ -1031,7 +1057,10 @@ public class TelecomManager {
/**
* Silences the ringer if a ringing call exists.
+ *
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void silenceRinger() {
try {
if (isServiceConnected()) {
@@ -1136,9 +1165,12 @@ public class TelecomManager {
* Requires that the method-caller be set as the system dialer app.
* </p>
*
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ *
* @param dialString The digits to dial.
* @return True if the digits were processed as an MMI code, false otherwise.
*/
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean handleMmi(String dialString) {
ITelecomService service = getTelecomService();
if (service != null) {
@@ -1159,10 +1191,13 @@ public class TelecomManager {
* Requires that the method-caller be set as the system dialer app.
* </p>
*
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ *
* @param accountHandle The handle for the account the MMI code should apply to.
* @param dialString The digits to dial.
* @return True if the digits were processed as an MMI code, false otherwise.
*/
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean handleMmi(String dialString, PhoneAccountHandle accountHandle) {
ITelecomService service = getTelecomService();
if (service != null) {
@@ -1177,11 +1212,14 @@ public class TelecomManager {
}
/**
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ *
* @param accountHandle The handle for the account to derive an adn query URI for or
* {@code null} to return a URI which will use the default account.
* @return The URI (with the content:// scheme) specific to the specified {@link PhoneAccount}
* for the the content retrieve.
*/
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) {
ITelecomService service = getTelecomService();
if (service != null && accountHandle != null) {
@@ -1199,7 +1237,10 @@ public class TelecomManager {
* <p>
* Requires that the method-caller be set as the system dialer app.
* </p>
+ *
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void cancelMissedCallsNotification() {
ITelecomService service = getTelecomService();
if (service != null) {
@@ -1221,6 +1262,7 @@ public class TelecomManager {
*
* @param showDialpad Brings up the in-call dialpad as part of showing the in-call screen.
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public void showInCallScreen(boolean showDialpad) {
ITelecomService service = getTelecomService();
if (service != null) {
@@ -1262,6 +1304,7 @@ public class TelecomManager {
* @param address The address to make the call to.
* @param extras Bundle of extras to use with the call.
*/
+ @RequiresPermission(android.Manifest.permission.CALL_PHONE)
public void placeCall(Uri address, Bundle extras) {
ITelecomService service = getTelecomService();
if (service != null) {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 1ff621a6cac9..17c24af8992c 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -63,8 +63,14 @@ import java.util.List;
public class MockPackageManager extends PackageManager {
@Override
- public PackageInfo getPackageInfo(String packageName, int flags)
- throws NameNotFoundException {
+ public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
+ public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+ throws NameNotFoundException {
throw new UnsupportedOperationException();
}
@@ -524,6 +530,14 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,
+ int flags, String installerPackageName, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
+
@Override
public void setInstallerPackageName(String targetPackage,
String installerPackageName) {
@@ -629,6 +643,15 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
+ /**
+ * @hide - to match hiding in superclass
+ */
+ @Override
+ public void deletePackageAsUser(
+ String packageName, IPackageDeleteObserver observer, int flags, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void addPackageToPreferred(String packageName) {
throw new UnsupportedOperationException();
@@ -792,7 +815,15 @@ public class MockPackageManager extends PackageManager {
* @hide
*/
@Override
- public int installExistingPackage(String packageName)
+ public int installExistingPackage(String packageName) throws NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int installExistingPackageAsUser(String packageName, int userId)
throws NameNotFoundException {
throw new UnsupportedOperationException();
}
diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
index 0b43666a5453..8085db72fba5 100644
--- a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
+++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
@@ -31,5 +31,7 @@ public class CameraActivity extends Activity {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_activity);
Log.i(TAG, "Activity created");
+ Log.i(TAG, "Source: "
+ + getIntent().getStringExtra("com.android.systemui.camera_launch_source"));
}
}
diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
index 530fe0063954..242d3b2c2a98 100644
--- a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
+++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
@@ -17,6 +17,7 @@
package com.google.android.test.cameraprewarm;
import android.app.Activity;
+import android.graphics.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
@@ -31,5 +32,7 @@ public class SecureCameraActivity extends Activity {
setContentView(R.layout.camera_activity);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
Log.i(CameraActivity.TAG, "Activity created");
+ Log.i(CameraActivity.TAG, "Source: "
+ + getIntent().getStringExtra("com.android.systemui.camera_launch_source"));
}
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
index b458d9b14096..7628c5c24941 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
@@ -188,7 +188,7 @@ public class MultiProducerActivity extends Activity implements OnClickListener {
// This call should be done while the rendernode's displaylist is produced.
// For simplicity of this test we do this before we kick off the draw.
mContent.getLocationInSurface(surfaceOrigin);
- mRenderer.setContentOverdrawProtectionBounds(surfaceOrigin[0], surfaceOrigin[1],
+ mRenderer.setContentDrawBounds(surfaceOrigin[0], surfaceOrigin[1],
surfaceOrigin[0] + mContent.getWidth(),
surfaceOrigin[1] + mContent.getHeight());
// Determine new position for frame.
diff --git a/tests/WindowAnimationJank/Android.mk b/tests/WindowAnimationJank/Android.mk
new file mode 100644
index 000000000000..888ae6434516
--- /dev/null
+++ b/tests/WindowAnimationJank/Android.mk
@@ -0,0 +1,31 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := WindowAnimationJank
+
+LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator ub-janktesthelper
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tests/WindowAnimationJank/AndroidManifest.xml b/tests/WindowAnimationJank/AndroidManifest.xml
new file mode 100644
index 000000000000..d7aef3348af3
--- /dev/null
+++ b/tests/WindowAnimationJank/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.windowanimationjank">
+
+ <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name="ElementLayoutActivity"
+ android:label="ElementLayoutActivity"
+ android:taskAffinity="android.windowanimationjank.ElementLayoutActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <!-- self-instrumenting test package. -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="android.windowanimationjank">
+ </instrumentation>
+
+</manifest>
diff --git a/tests/WindowAnimationJank/res/layout/flowlayout.xml b/tests/WindowAnimationJank/res/layout/flowlayout.xml
new file mode 100644
index 000000000000..f2b559b2dd02
--- /dev/null
+++ b/tests/WindowAnimationJank/res/layout/flowlayout.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+<android.windowanimationjank.FlowLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/root_flow_layout"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" /> \ No newline at end of file
diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/ElementLayoutActivity.java b/tests/WindowAnimationJank/src/android/windowanimationjank/ElementLayoutActivity.java
new file mode 100644
index 000000000000..3b1fabcb59ec
--- /dev/null
+++ b/tests/WindowAnimationJank/src/android/windowanimationjank/ElementLayoutActivity.java
@@ -0,0 +1,159 @@
+/*
+ * 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.windowanimationjank;
+
+import java.util.Random;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+import android.widget.Chronometer;
+import android.widget.RadioButton;
+import android.widget.Switch;
+import android.widget.TextView;
+import android.widget.ToggleButton;
+
+/*
+ * Activity with arbitrary number of random UI elements, refresh itself constantly.
+ */
+public class ElementLayoutActivity extends Activity implements OnPreDrawListener {
+ public final static String NUM_ELEMENTS_KEY = "num_elements";
+
+ private final static int DEFAULT_NUM_ELEMENTS = 100;
+ private final static int BACKGROUND_COLOR = 0xfffff000;
+ private final static int INDICATOR_COLOR = 0xffff0000;
+
+ private FlowLayout mLayout;
+ // Use the constant seed in order to get predefined order of elements.
+ private Random mRandom = new Random(0);
+ // Blinker indicator for visual feedback that Activity is currently updating.
+ private TextView mIndicator;
+ private static float mIndicatorState;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.flowlayout);
+
+ mLayout = (FlowLayout)findViewById(R.id.root_flow_layout);
+ mLayout.setBackgroundColor(BACKGROUND_COLOR);
+
+ mIndicator = new TextView(this);
+ mLayout.addView(mIndicator);
+ mIndicator.setText("***\n***");
+ mIndicator.setBackgroundColor(BACKGROUND_COLOR);
+ mIndicatorState = 0.0f;
+
+ // Need constantly invalidate view in order to get max redraw rate.
+ mLayout.getViewTreeObserver().addOnPreDrawListener(this);
+
+ // Read requested number of elements in layout.
+ int numElements = getIntent().getIntExtra(NUM_ELEMENTS_KEY, DEFAULT_NUM_ELEMENTS);
+
+ for (int i = 0; i < numElements; ++i) {
+ switch (mRandom.nextInt(5)) {
+ case 0:
+ createRadioButton();
+ break;
+ case 1:
+ createToggleButton();
+ break;
+ case 2:
+ createSwitch();
+ break;
+ case 3:
+ createTextView();
+ break;
+ case 4:
+ createChronometer();
+ break;
+ }
+ }
+
+ setContentView(mLayout);
+ }
+
+ private void createTextView() {
+ TextView textView = new TextView(this);
+ int lineCnt = mRandom.nextInt(4);
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < lineCnt; ++i) {
+ if (i != 0) {
+ buffer.append("\n");
+ }
+ buffer.append("Line:" + mRandom.nextInt());
+ }
+ textView.setText(buffer);
+ mLayout.addView(textView);
+ }
+
+ private void createRadioButton() {
+ RadioButton button = new RadioButton(this);
+ button.setText("RadioButton:" + mRandom.nextInt());
+ mLayout.addView(button);
+ }
+
+ private void createToggleButton() {
+ ToggleButton button = new ToggleButton(this);
+ button.setChecked(mRandom.nextBoolean());
+ mLayout.addView(button);
+ }
+
+ private void createSwitch() {
+ Switch button = new Switch(this);
+ button.setChecked(mRandom.nextBoolean());
+ mLayout.addView(button);
+ }
+
+ private void createChronometer() {
+ Chronometer chronometer = new Chronometer(this);
+ chronometer.setBase(mRandom.nextLong());
+ mLayout.addView(chronometer);
+ chronometer.start();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ public boolean onPreDraw() {
+ // Interpolate indicator color
+ int background = 0xff000000;
+ for (int i = 0; i < 3; ++i) {
+ int shift = 8 * i;
+ int colorB = (BACKGROUND_COLOR >> shift) & 0xff;
+ int colorI = (INDICATOR_COLOR >> shift) & 0xff;
+ int color = (int)((float)colorB * (1.0f - mIndicatorState) +
+ (float)colorI * mIndicatorState);
+ if (color > 255) {
+ color = 255;
+ }
+ background |= (color << shift);
+ }
+
+ mIndicator.setBackgroundColor(background);
+ mIndicatorState += (3 / 60.0f); // around 3 times per second
+ mIndicatorState = mIndicatorState - (int)mIndicatorState;
+
+ mLayout.postInvalidate();
+ return true;
+ }
+} \ No newline at end of file
diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/FlowLayout.java b/tests/WindowAnimationJank/src/android/windowanimationjank/FlowLayout.java
new file mode 100644
index 000000000000..9a2b9ccb4f90
--- /dev/null
+++ b/tests/WindowAnimationJank/src/android/windowanimationjank/FlowLayout.java
@@ -0,0 +1,111 @@
+/*
+ * 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.windowanimationjank;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Custom layout that place all elements in flows with and automatically wraps them.
+ */
+public class FlowLayout extends ViewGroup {
+ private int mLineHeight;
+
+ public FlowLayout(Context context) {
+ super(context);
+ }
+
+ public FlowLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int width =
+ MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() -getPaddingRight();
+ int height =
+ MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
+ final int count = getChildCount();
+
+ int x = getPaddingLeft();
+ int y = getPaddingTop();
+ int lineHeight = 0;
+
+ int childHeightMeasureSpec;
+ if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+ childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+ } else {
+ childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ }
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
+ childHeightMeasureSpec);
+ final int childWidth = child.getMeasuredWidth();
+ lineHeight = Math.max(lineHeight, child.getMeasuredHeight());
+
+ if (x + childWidth > width) {
+ x = getPaddingLeft();
+ y += lineHeight;
+ }
+
+ x += childWidth;
+ }
+ }
+ mLineHeight = lineHeight;
+
+ if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
+ height = y + lineHeight;
+ } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+ if (y + lineHeight < height) {
+ height = y + lineHeight;
+ }
+ }
+ setMeasuredDimension(width, height);
+ }
+
+ @Override
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+ if (p instanceof LayoutParams) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int count = getChildCount();
+ final int width = r - l;
+ int x = getPaddingLeft();
+ int y = getPaddingTop();
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ final int childWidth = child.getMeasuredWidth();
+ final int childHeight = child.getMeasuredHeight();
+ if (x + childWidth > width) {
+ x = getPaddingLeft();
+ y += mLineHeight;
+ }
+ child.layout(x, y, x + childWidth, y + childHeight);
+ x += childWidth;
+ }
+ }
+ }
+}
diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java b/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java
new file mode 100644
index 000000000000..1fb502a09874
--- /dev/null
+++ b/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.windowanimationjank;
+
+import android.os.Bundle;
+import android.support.test.jank.JankTest;
+import android.support.test.jank.GfxMonitor;
+
+/**
+ * Detect janks during screen rotation for full-screen activity. Periodically change
+ * orientation from left to right and track ElementLayoutActivity rendering performance
+ * via GfxMonitor.
+ */
+public class FullscreenRotationTest extends WindowAnimationJankTestBase {
+ private final static int STEP_CNT = 3;
+
+ @Override
+ public void beforeTest() throws Exception {
+ getUiDevice().setOrientationLeft();
+ Utils.startElementLayout(getInstrumentation(), 100);
+ super.beforeTest();
+ }
+
+ @Override
+ public void afterTest(Bundle metrics) {
+ Utils.rotateDevice(getInstrumentation(), Utils.ROTATION_MODE_NATURAL);
+ super.afterTest(metrics);
+ }
+
+ @JankTest(expectedFrames=100, defaultIterationCount=2)
+ @GfxMonitor(processName=Utils.PACKAGE)
+ public void testRotation() throws Exception {
+ for (int i = 0; i < STEP_CNT; ++i) {
+ Utils.rotateDevice(getInstrumentation(),
+ Utils.getDeviceRotation(getInstrumentation()) == Utils.ROTATION_MODE_LEFT ?
+ Utils.ROTATION_MODE_RIGHT : Utils.ROTATION_MODE_LEFT);
+ }
+ }
+}
diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java b/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java
new file mode 100644
index 000000000000..25314644ca7e
--- /dev/null
+++ b/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java
@@ -0,0 +1,118 @@
+/*
+ * 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.windowanimationjank;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.SystemClock;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+/**
+ * Set of helpers to manipulate test activities.
+ */
+public class Utils {
+ protected final static String PACKAGE = "android.windowanimationjank";
+ protected final static String ELEMENT_LAYOUT_ACTIVITY = "ElementLayoutActivity";
+ protected final static String ELEMENT_LAYOUT_CLASS = PACKAGE + "." + ELEMENT_LAYOUT_ACTIVITY;
+ protected final static long WAIT_FOR_ACTIVITY_TIMEOUT = 10000;
+ private static final BySelector ROOT_ELEMENT_LAYOUT = By.res(PACKAGE, "root_flow_layout");
+
+ private final static long ROTATION_ANIMATION_TIME_FULL_SCREEN_MS = 1000;
+
+ protected final static int ROTATION_MODE_NATURAL = 0;
+ protected final static int ROTATION_MODE_LEFT = 1;
+ protected final static int ROTATION_MODE_RIGHT = 2;
+
+ private static UiObject2 waitForActivity(Instrumentation instrumentation, BySelector selector) {
+ UiDevice device = UiDevice.getInstance(instrumentation);
+ UiObject2 window = device.wait(Until.findObject(selector), WAIT_FOR_ACTIVITY_TIMEOUT);
+ if (window == null) {
+ throw new RuntimeException(selector.toString() + " has not been started.");
+ }
+
+ // Get root object.
+ while (window.getParent() != null) {
+ window = window.getParent();
+ }
+ return window;
+ }
+
+ public static UiObject2 waitForElementLayout(Instrumentation instrumentation) {
+ return waitForActivity(instrumentation, ROOT_ELEMENT_LAYOUT);
+ }
+
+ /**
+ * Start and return activity with requested number of random elements.
+ */
+ public static UiObject2 startElementLayout(Instrumentation instrumentation, int numElements) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setComponent(new ComponentName(PACKAGE, ELEMENT_LAYOUT_CLASS));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(ElementLayoutActivity.NUM_ELEMENTS_KEY, numElements);
+ instrumentation.getTargetContext().startActivity(intent);
+ return waitForElementLayout(instrumentation);
+ }
+
+ public static int getDeviceRotation(Instrumentation instrumentation) {
+ try {
+ UiDevice device = UiDevice.getInstance(instrumentation);
+ switch (device.getDisplayRotation()) {
+ case UiAutomation.ROTATION_FREEZE_90:
+ return ROTATION_MODE_LEFT;
+ case UiAutomation.ROTATION_FREEZE_270:
+ return ROTATION_MODE_RIGHT;
+ case UiAutomation.ROTATION_FREEZE_0:
+ case UiAutomation.ROTATION_FREEZE_180:
+ return ROTATION_MODE_NATURAL;
+ }
+ } catch(Exception e) {
+ throw new RuntimeException();
+ }
+ throw new RuntimeException("Unsupported device rotation.");
+ }
+
+ public static void rotateDevice(Instrumentation instrumentation, int rotationMode) {
+ try {
+ UiDevice device = UiDevice.getInstance(instrumentation);
+ long startTime = System.currentTimeMillis();
+ switch (rotationMode) {
+ case ROTATION_MODE_NATURAL:
+ device.setOrientationNatural();
+ break;
+ case ROTATION_MODE_LEFT:
+ device.setOrientationLeft();
+ break;
+ case ROTATION_MODE_RIGHT:
+ device.setOrientationRight();
+ break;
+ default:
+ throw new RuntimeException("Unsupported rotation mode: " + rotationMode);
+ }
+
+ long toSleep = ROTATION_ANIMATION_TIME_FULL_SCREEN_MS -
+ (System.currentTimeMillis() - startTime);
+ if (toSleep > 0) {
+ SystemClock.sleep(toSleep);
+ }
+ } catch(Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java b/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java
new file mode 100644
index 000000000000..bf739fa8da07
--- /dev/null
+++ b/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java
@@ -0,0 +1,56 @@
+/*
+ * 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.windowanimationjank;
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+import android.support.test.jank.JankTestBase;
+import android.support.test.uiautomator.UiDevice;
+
+/**
+ * This adds additional system level jank monitor and its result is merged with primary monitor
+ * used in test.
+ */
+public abstract class WindowAnimationJankTestBase extends JankTestBase {
+ private static final String TAG = "WindowAnimationJankTestBase";
+
+ protected WindowAnimationJankTestBase() {
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // fix device orientation
+ getUiDevice().setOrientationNatural();
+
+ // Start from the home screen
+ getUiDevice().pressHome();
+ getUiDevice().waitForIdle();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ getUiDevice().unfreezeRotation();
+ super.tearDown();
+ }
+
+ protected UiDevice getUiDevice() {
+ return UiDevice.getInstance(getInstrumentation());
+ }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index b9e7500598d1..a390b0cab321 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -175,16 +175,6 @@ public class WindowManagerPermissionTests extends TestCase {
}
try {
- mWm.setAppWillBeHidden(null);
- fail("IWindowManager.setAppWillBeHidden did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
mWm.setAppVisibility(null, false);
fail("IWindowManager.setAppVisibility did not throw SecurityException as"
+ " expected");
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 3b7bf8549181..f4b1f2cd363f 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -401,7 +401,7 @@ public final class BridgeResources extends Resources {
if (xml.isFile()) {
// we need to create a pull parser around the layout XML file, and then
// give that to our XmlBlockParser
- parser = ParserFactory.create(xml);
+ parser = ParserFactory.create(xml, true);
}
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index 857e6d03283e..c7b24bcb352d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -178,7 +178,9 @@ public class FontFamily_Delegate {
desiredStyle.mIsItalic = isItalic;
FontInfo bestFont = null;
int bestMatch = Integer.MAX_VALUE;
- for (FontInfo font : mFonts) {
+ //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation)
+ for (int i = 0, n = mFonts.size(); i < n; i++) {
+ FontInfo font = mFonts.get(i);
int match = computeMatch(font, desiredStyle);
if (match < bestMatch) {
bestMatch = match;
@@ -415,7 +417,9 @@ public class FontFamily_Delegate {
boolean isItalic = fontInfo.mIsItalic;
// The list is usually just two fonts big. So iterating over all isn't as bad as it looks.
// It's biggest for roboto where the size is 12.
- for (FontInfo font : mFonts) {
+ //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation)
+ for (int i = 0, n = mFonts.size(); i < n; i++) {
+ FontInfo font = mFonts.get(i);
if (font.mWeight == weight && font.mIsItalic == isItalic) {
return false;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 65b65ec759d0..a545283ea0ca 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -480,8 +480,10 @@ public class Paint_Delegate {
return;
}
- delegate.mTextSize = textSize;
- delegate.updateFontObject();
+ if (delegate.mTextSize != textSize) {
+ delegate.mTextSize = textSize;
+ delegate.updateFontObject();
+ }
}
@LayoutlibDelegate
@@ -503,8 +505,10 @@ public class Paint_Delegate {
return;
}
- delegate.mTextScaleX = scaleX;
- delegate.updateFontObject();
+ if (delegate.mTextScaleX != scaleX) {
+ delegate.mTextScaleX = scaleX;
+ delegate.updateFontObject();
+ }
}
@LayoutlibDelegate
@@ -526,8 +530,10 @@ public class Paint_Delegate {
return;
}
- delegate.mTextSkewX = skewX;
- delegate.updateFontObject();
+ if (delegate.mTextSkewX != skewX) {
+ delegate.mTextSkewX = skewX;
+ delegate.updateFontObject();
+ }
}
@LayoutlibDelegate
@@ -897,9 +903,12 @@ public class Paint_Delegate {
return 0;
}
- delegate.mTypeface = Typeface_Delegate.getDelegate(typeface);
- delegate.mNativeTypeface = typeface;
- delegate.updateFontObject();
+ Typeface_Delegate typefaceDelegate = Typeface_Delegate.getDelegate(typeface);
+ if (delegate.mTypeface != typefaceDelegate || delegate.mNativeTypeface != typeface) {
+ delegate.mTypeface = Typeface_Delegate.getDelegate(typeface);
+ delegate.mNativeTypeface = typeface;
+ delegate.updateFontObject();
+ }
return typeface;
}
@@ -1214,13 +1223,31 @@ public class Paint_Delegate {
mCap = paint.mCap;
mJoin = paint.mJoin;
mTextAlign = paint.mTextAlign;
- mTypeface = paint.mTypeface;
- mNativeTypeface = paint.mNativeTypeface;
+
+ boolean needsFontUpdate = false;
+ if (mTypeface != paint.mTypeface || mNativeTypeface != paint.mNativeTypeface) {
+ mTypeface = paint.mTypeface;
+ mNativeTypeface = paint.mNativeTypeface;
+ needsFontUpdate = true;
+ }
+
+ if (mTextSize != paint.mTextSize) {
+ mTextSize = paint.mTextSize;
+ needsFontUpdate = true;
+ }
+
+ if (mTextScaleX != paint.mTextScaleX) {
+ mTextScaleX = paint.mTextScaleX;
+ needsFontUpdate = true;
+ }
+
+ if (mTextSkewX != paint.mTextSkewX) {
+ mTextSkewX = paint.mTextSkewX;
+ needsFontUpdate = true;
+ }
+
mStrokeWidth = paint.mStrokeWidth;
mStrokeMiter = paint.mStrokeMiter;
- mTextSize = paint.mTextSize;
- mTextScaleX = paint.mTextScaleX;
- mTextSkewX = paint.mTextSkewX;
mXfermode = paint.mXfermode;
mColorFilter = paint.mColorFilter;
mShader = paint.mShader;
@@ -1228,7 +1255,10 @@ public class Paint_Delegate {
mMaskFilter = paint.mMaskFilter;
mRasterizer = paint.mRasterizer;
mHintingMode = paint.mHintingMode;
- updateFontObject();
+
+ if (needsFontUpdate) {
+ updateFontObject();
+ }
}
private void reset() {
@@ -1264,10 +1294,18 @@ public class Paint_Delegate {
// Get the fonts from the TypeFace object.
List<Font> fonts = mTypeface.getFonts(mFontVariant);
+ if (fonts.isEmpty()) {
+ mFonts = Collections.emptyList();
+ return;
+ }
+
// create new font objects as well as FontMetrics, based on the current text size
// and skew info.
- ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
- for (Font font : fonts) {
+ int nFonts = fonts.size();
+ ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(nFonts);
+ //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation)
+ for (int i = 0; i < nFonts; i++) {
+ Font font = fonts.get(i);
if (font == null) {
// If the font is null, add null to infoList. When rendering the text, if this
// null is reached, a warning will be logged.
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index f1726ebae4cb..5db1bde5f3f0 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -206,7 +206,7 @@ public final class BridgeInflater extends LayoutInflater {
File f = new File(value.getValue());
if (f.isFile()) {
try {
- XmlPullParser parser = ParserFactory.create(f);
+ XmlPullParser parser = ParserFactory.create(f, true);
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
parser, bridgeContext, value.isFramework());
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 778d1a5e51ac..0da6bb62006c 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -338,11 +338,6 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public void setAppWillBeHidden(IBinder arg0) throws RemoteException {
- // TODO Auto-generated method stub
- }
-
- @Override
public void setEventDispatching(boolean arg0) throws RemoteException {
// TODO Auto-generated method stub
}
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 689e3597720b..b2dc29a90fb1 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
@@ -436,7 +436,7 @@ public final class BridgeContext extends Context {
// we need to create a pull parser around the layout XML file, and then
// give that to our XmlBlockParser
try {
- XmlPullParser parser = ParserFactory.create(xml);
+ XmlPullParser parser = ParserFactory.create(xml, true);
// set the resource ref to have correct view cookies
mBridgeInflater.setResourceReference(resource);
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 f04654eded0f..e3a19e76a3ef 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
@@ -65,6 +65,12 @@ public class BridgePackageManager extends PackageManager {
}
@Override
+ public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+ throws NameNotFoundException {
+ return null;
+ }
+
+ @Override
public String[] currentToCanonicalPackageNames(String[] names) {
return new String[0];
}
@@ -499,6 +505,11 @@ public class BridgePackageManager extends PackageManager {
}
@Override
+ public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,int flags,
+ String installerPackageName, int userId) {
+ }
+
+ @Override
public void installPackageWithVerification(Uri packageURI, PackageInstallObserver observer,
int flags, String installerPackageName, Uri verificationURI,
ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
@@ -516,6 +527,12 @@ public class BridgePackageManager extends PackageManager {
}
@Override
+ public int installExistingPackageAsUser(String packageName, int userId)
+ throws NameNotFoundException {
+ return 0;
+ }
+
+ @Override
public void verifyPendingInstall(int id, int verificationCode) {
}
@@ -568,6 +585,11 @@ public class BridgePackageManager extends PackageManager {
}
@Override
+ public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags,
+ int userId) {
+ }
+
+ @Override
public String getInstallerPackageName(String packageName) {
return null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutParserWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutParserWrapper.java
new file mode 100644
index 000000000000..71e7fd2c5eea
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutParserWrapper.java
@@ -0,0 +1,377 @@
+/*
+ * 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.layoutlib.bridge.impl;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.Nullable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A wrapper around XmlPullParser that can peek forward to inspect if the file is a data-binding
+ * layout and some parts need to be stripped.
+ */
+public class LayoutParserWrapper implements XmlPullParser {
+
+ // Data binding constants.
+ private static final String TAG_LAYOUT = "layout";
+ private static final String TAG_DATA = "data";
+ private static final String DEFAULT = "default=";
+
+ private final XmlPullParser mDelegate;
+
+ // Storage for peeked values.
+ private boolean mPeeked;
+ private int mEventType;
+ private int mDepth;
+ private int mNext;
+ private List<Attribute> mAttributes;
+ private String mText;
+ private String mName;
+
+ // Used to end the document before the actual parser ends.
+ private int mFinalDepth = -1;
+ private boolean mEndNow;
+
+ public LayoutParserWrapper(XmlPullParser delegate) {
+ mDelegate = delegate;
+ }
+
+ public LayoutParserWrapper peekTillLayoutStart() throws IOException, XmlPullParserException {
+ final int STATE_LAYOUT_NOT_STARTED = 0; // <layout> tag not encountered yet.
+ final int STATE_ROOT_NOT_STARTED = 1; // the main view root not found yet.
+ final int STATE_INSIDE_DATA = 2; // START_TAG for <data> found, but not END_TAG.
+
+ int state = STATE_LAYOUT_NOT_STARTED;
+ int dataDepth = -1; // depth of the <data> tag. Should be two.
+ while (true) {
+ int peekNext = peekNext();
+ switch (peekNext) {
+ case START_TAG:
+ if (state == STATE_LAYOUT_NOT_STARTED) {
+ if (mName.equals(TAG_LAYOUT)) {
+ state = STATE_ROOT_NOT_STARTED;
+ } else {
+ return this; // no layout tag in the file.
+ }
+ } else if (state == STATE_ROOT_NOT_STARTED) {
+ if (mName.equals(TAG_DATA)) {
+ state = STATE_INSIDE_DATA;
+ dataDepth = mDepth;
+ } else {
+ mFinalDepth = mDepth;
+ return this;
+ }
+ }
+ break;
+ case END_TAG:
+ if (state == STATE_INSIDE_DATA) {
+ if (mDepth <= dataDepth) {
+ state = STATE_ROOT_NOT_STARTED;
+ }
+ }
+ break;
+ case END_DOCUMENT:
+ // No layout start found.
+ return this;
+ }
+ // consume the peeked tag.
+ next();
+ }
+ }
+
+ private int peekNext() throws IOException, XmlPullParserException {
+ if (mPeeked) {
+ return mNext;
+ }
+ mEventType = mDelegate.getEventType();
+ mNext = mDelegate.next();
+ if (mEventType == START_TAG) {
+ int count = mDelegate.getAttributeCount();
+ mAttributes = count > 0 ? new ArrayList<Attribute>(count) :
+ Collections.<Attribute>emptyList();
+ for (int i = 0; i < count; i++) {
+ mAttributes.add(new Attribute(mDelegate.getAttributeNamespace(i),
+ mDelegate.getAttributeName(i), mDelegate.getAttributeValue(i)));
+ }
+ }
+ mDepth = mDelegate.getDepth();
+ mText = mDelegate.getText();
+ mName = mDelegate.getName();
+ mPeeked = true;
+ return mNext;
+ }
+
+ private void reset() {
+ mAttributes = null;
+ mText = null;
+ mName = null;
+ mPeeked = false;
+ }
+
+ @Override
+ public int next() throws XmlPullParserException, IOException {
+ int returnValue;
+ int depth;
+ if (mPeeked) {
+ returnValue = mNext;
+ depth = mDepth;
+ reset();
+ } else if (mEndNow) {
+ return END_DOCUMENT;
+ } else {
+ returnValue = mDelegate.next();
+ depth = getDepth();
+ }
+ if (returnValue == END_TAG && depth <= mFinalDepth) {
+ mEndNow = true;
+ }
+ return returnValue;
+ }
+
+ @Override
+ public int getEventType() throws XmlPullParserException {
+ return mPeeked ? mEventType : mDelegate.getEventType();
+ }
+
+ @Override
+ public int getDepth() {
+ return mPeeked ? mDepth : mDelegate.getDepth();
+ }
+
+ @Override
+ public String getName() {
+ return mPeeked ? mName : mDelegate.getName();
+ }
+
+ @Override
+ public String getText() {
+ return mPeeked ? mText : mDelegate.getText();
+ }
+
+ @Override
+ public String getAttributeValue(@Nullable String namespace, String name) {
+ String returnValue = null;
+ if (mPeeked) {
+ if (mAttributes == null) {
+ if (mEventType != START_TAG) {
+ throw new IndexOutOfBoundsException("getAttributeValue() called when not at START_TAG.");
+ } else {
+ return null;
+ }
+ } else {
+ for (Attribute attribute : mAttributes) {
+ //noinspection StringEquality for nullness check.
+ if (attribute.name.equals(name) && (attribute.namespace == namespace ||
+ attribute.namespace != null && attribute.namespace.equals(namespace))) {
+ returnValue = attribute.value;
+ break;
+ }
+ }
+ }
+ } else {
+ returnValue = mDelegate.getAttributeValue(namespace, name);
+ }
+ // Check if the value is bound via data-binding, if yes get the default value.
+ if (returnValue != null && mFinalDepth >= 0 && returnValue.startsWith("@{")) {
+ // TODO: Improve the detection of default keyword.
+ int i = returnValue.lastIndexOf(DEFAULT);
+ return i > 0 ? returnValue.substring(i + DEFAULT.length(), returnValue.length() - 1)
+ : null;
+ }
+ return returnValue;
+ }
+
+ private static class Attribute {
+ @Nullable
+ public final String namespace;
+ public final String name;
+ public final String value;
+
+ public Attribute(@Nullable String namespace, String name, String value) {
+ this.namespace = namespace;
+ this.name = name;
+ this.value = value;
+ }
+ }
+
+ // Not affected by peeking.
+
+ @Override
+ public void setFeature(String s, boolean b) throws XmlPullParserException {
+ mDelegate.setFeature(s, b);
+ }
+
+ @Override
+ public void setProperty(String s, Object o) throws XmlPullParserException {
+ mDelegate.setProperty(s, o);
+ }
+
+ @Override
+ public void setInput(InputStream inputStream, String s) throws XmlPullParserException {
+ mDelegate.setInput(inputStream, s);
+ }
+
+ @Override
+ public void setInput(Reader reader) throws XmlPullParserException {
+ mDelegate.setInput(reader);
+ }
+
+ @Override
+ public String getInputEncoding() {
+ return mDelegate.getInputEncoding();
+ }
+
+ @Override
+ public String getNamespace(String s) {
+ return mDelegate.getNamespace(s);
+ }
+
+ @Override
+ public String getPositionDescription() {
+ return mDelegate.getPositionDescription();
+ }
+
+ @Override
+ public int getLineNumber() {
+ return mDelegate.getLineNumber();
+ }
+
+ @Override
+ public String getNamespace() {
+ return mDelegate.getNamespace();
+ }
+
+ @Override
+ public int getColumnNumber() {
+ return mDelegate.getColumnNumber();
+ }
+
+ // -- We don't care much about the methods that follow.
+
+ @Override
+ public void require(int i, String s, String s1) throws XmlPullParserException, IOException {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public boolean getFeature(String s) {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public void defineEntityReplacementText(String s, String s1) throws XmlPullParserException {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public Object getProperty(String s) {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public int nextToken() throws XmlPullParserException, IOException {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public int getNamespaceCount(int i) throws XmlPullParserException {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public String getNamespacePrefix(int i) throws XmlPullParserException {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public String getNamespaceUri(int i) throws XmlPullParserException {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public boolean isWhitespace() throws XmlPullParserException {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public char[] getTextCharacters(int[] ints) {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public String getPrefix() {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public boolean isEmptyElementTag() throws XmlPullParserException {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public int getAttributeCount() {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public String getAttributeNamespace(int i) {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public String getAttributeName(int i) {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public String getAttributePrefix(int i) {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public String getAttributeType(int i) {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public boolean isAttributeDefault(int i) {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public String getAttributeValue(int i) {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public String nextText() throws XmlPullParserException, IOException {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+
+ @Override
+ public int nextTag() throws XmlPullParserException, IOException {
+ throw new UnsupportedOperationException("Only few parser methods are supported.");
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
index 6e67f593aa53..e273b2cd75cc 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
@@ -53,24 +53,35 @@ public class ParserFactory {
@NonNull
public static XmlPullParser create(@NonNull File f)
throws XmlPullParserException, FileNotFoundException {
- InputStream stream = new FileInputStream(f);
- return create(stream, f.getName(), f.length());
+ return create(f, false);
}
+ public static XmlPullParser create(@NonNull File f, boolean isLayout)
+ throws XmlPullParserException, FileNotFoundException {
+ InputStream stream = new FileInputStream(f);
+ return create(stream, f.getName(), f.length(), isLayout);
+ }
@NonNull
public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name)
throws XmlPullParserException {
- return create(stream, name, -1);
+ return create(stream, name, -1, false);
}
@NonNull
private static XmlPullParser create(@NonNull InputStream stream, @Nullable String name,
- long size) throws XmlPullParserException {
+ long size, boolean isLayout) throws XmlPullParserException {
XmlPullParser parser = instantiateParser(name);
stream = readAndClose(stream, name, size);
parser.setInput(stream, ENCODING);
+ if (isLayout) {
+ try {
+ return new LayoutParserWrapper(parser).peekTillLayoutStart();
+ } catch (IOException e) {
+ throw new XmlPullParserException(null, parser, e);
+ }
+ }
return parser;
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/impl/LayoutParserWrapperTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/impl/LayoutParserWrapperTest.java
new file mode 100644
index 000000000000..2c338622301b
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/impl/LayoutParserWrapperTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.layoutlib.bridge.impl;
+
+import org.junit.Test;
+import org.kxml2.io.KXmlParser;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.StringReader;
+
+import static com.android.SdkConstants.NS_RESOURCES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+
+public class LayoutParserWrapperTest {
+ @Test
+ @SuppressWarnings("StatementWithEmptyBody") // some for loops need to be empty statements.
+ public void testDataBindingLayout() throws Exception {
+ LayoutParserWrapper parser = getParserFromString(sDataBindingLayout);
+ parser.peekTillLayoutStart();
+ assertEquals("Expected START_TAG", START_TAG, parser.next());
+ assertEquals("RelativeLayout", parser.getName());
+ for (int next = parser.next(); next != START_TAG && next != END_DOCUMENT;
+ next = parser.next());
+ assertEquals("Expected START_TAG", START_TAG, parser.getEventType());
+ assertEquals("TextView", parser.getName());
+ assertEquals("layout_width incorrect for first text view.", "wrap_content",
+ parser.getAttributeValue(NS_RESOURCES, "layout_width"));
+ // Ensure that data-binding part is stripped.
+ assertEquals("Bound attribute android:text incorrect", "World",
+ parser.getAttributeValue(NS_RESOURCES, "text"));
+ assertEquals("resource attribute 'id' for first text view incorrect.", "@+id/first",
+ parser.getAttributeValue(NS_RESOURCES, "id"));
+ for (int next = parser.next();
+ (next != END_TAG || !"RelativeLayout".equals(parser.getName())) && next != END_DOCUMENT;
+ next = parser.next());
+ assertNotSame("Unexpected end of document", END_DOCUMENT, parser.getEventType());
+ assertEquals("Document didn't end when expected.", END_DOCUMENT, parser.next());
+ }
+
+ @Test
+ @SuppressWarnings("StatementWithEmptyBody")
+ public void testNonDataBindingLayout() throws Exception {
+ LayoutParserWrapper parser = getParserFromString(sNonDataBindingLayout);
+ parser.peekTillLayoutStart();
+ assertEquals("Expected START_TAG", START_TAG, parser.next());
+ assertEquals("RelativeLayout", parser.getName());
+ for (int next = parser.next(); next != START_TAG && next != END_DOCUMENT;
+ next = parser.next());
+ assertEquals("Expected START_TAG", START_TAG, parser.getEventType());
+ assertEquals("TextView", parser.getName());
+ assertEquals("layout_width incorrect for first text view.", "wrap_content",
+ parser.getAttributeValue(NS_RESOURCES, "layout_width"));
+ // Ensure that value isn't modified.
+ assertEquals("Bound attribute android:text incorrect", "@{user.firstName,default=World}",
+ parser.getAttributeValue(NS_RESOURCES, "text"));
+ assertEquals("resource attribute 'id' for first text view incorrect.", "@+id/first",
+ parser.getAttributeValue(NS_RESOURCES, "id"));
+ for (int next = parser.next();
+ (next != END_TAG || !"RelativeLayout".equals(parser.getName())) && next != END_DOCUMENT;
+ next = parser.next());
+ assertNotSame("Unexpected end of document", END_DOCUMENT, parser.getEventType());
+ assertEquals("Document didn't end when expected.", END_DOCUMENT, parser.next());
+ }
+
+ private static LayoutParserWrapper getParserFromString(String layoutContent) throws
+ XmlPullParserException {
+ XmlPullParser parser = new KXmlParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ parser.setInput(new StringReader(layoutContent));
+ return new LayoutParserWrapper(parser);
+ }
+
+ private static final String sDataBindingLayout =
+ //language=XML
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+ "<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+ " xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n" +
+ " xmlns:tools=\"http://schemas.android.com/tools\"\n" +
+ " tools:context=\".MainActivity\"\n" +
+ " tools:showIn=\"@layout/activity_main\">\n" +
+ "\n" +
+ " <data>\n" +
+ "\n" +
+ " <variable\n" +
+ " name=\"user\"\n" +
+ " type=\"com.example.User\" />\n" +
+ " <variable\n" +
+ " name=\"activity\"\n" +
+ " type=\"com.example.MainActivity\" />\n" +
+ " </data>\n" +
+ "\n" +
+ " <RelativeLayout\n" +
+ " android:layout_width=\"match_parent\"\n" +
+ " android:layout_height=\"match_parent\"\n" +
+ " android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" +
+ " android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" +
+ " android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" +
+ " android:paddingTop=\"@dimen/activity_vertical_margin\"\n" +
+ " app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n" +
+ " >\n" +
+ "\n" +
+ " <TextView\n" +
+ " android:id=\"@+id/first\"\n" +
+ " android:layout_width=\"wrap_content\"\n" +
+ " android:layout_alignParentStart=\"true\"\n" +
+ " android:layout_alignParentLeft=\"true\"\n" +
+ " android:layout_height=\"wrap_content\"\n" +
+ " android:text=\"@{user.firstName,default=World}\" />\n" +
+ "\n" +
+ " <TextView\n" +
+ " android:id=\"@+id/last\"\n" +
+ " android:layout_width=\"wrap_content\"\n" +
+ " android:layout_height=\"wrap_content\"\n" +
+ " android:layout_toEndOf=\"@id/first\"\n" +
+ " android:layout_toRightOf=\"@id/first\"\n" +
+ " android:text=\"@{user.lastName,default=Hello}\" />\n" +
+ "\n" +
+ " <Button\n" +
+ " android:layout_width=\"wrap_content\"\n" +
+ " android:layout_height=\"wrap_content\"\n" +
+ " android:layout_below=\"@id/last\"\n" +
+ " android:text=\"Submit\"\n" +
+ " android:onClick=\"@{activity.onClick}\"/>\n" +
+ " </RelativeLayout>\n" +
+ "</layout>";
+
+ private static final String sNonDataBindingLayout =
+ //language=XML
+ "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+ " xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n" +
+ " android:layout_width=\"match_parent\"\n" +
+ " android:layout_height=\"match_parent\"\n" +
+ " android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" +
+ " android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" +
+ " android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" +
+ " android:paddingTop=\"@dimen/activity_vertical_margin\"\n" +
+ " app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n" +
+ ">\n" +
+ "\n" +
+ " <TextView\n" +
+ " android:id=\"@+id/first\"\n" +
+ " android:layout_width=\"wrap_content\"\n" +
+ " android:layout_alignParentStart=\"true\"\n" +
+ " android:layout_alignParentLeft=\"true\"\n" +
+ " android:layout_height=\"wrap_content\"\n" +
+ " android:text=\"@{user.firstName,default=World}\" />\n" +
+ "\n" +
+ " <TextView\n" +
+ " android:id=\"@+id/last\"\n" +
+ " android:layout_width=\"wrap_content\"\n" +
+ " android:layout_height=\"wrap_content\"\n" +
+ " android:layout_toEndOf=\"@id/first\"\n" +
+ " android:layout_toRightOf=\"@id/first\"\n" +
+ " android:text=\"@{user.lastName,default=Hello}\" />\n" +
+ "\n" +
+ " <Button\n" +
+ " android:layout_width=\"wrap_content\"\n" +
+ " android:layout_height=\"wrap_content\"\n" +
+ " android:layout_below=\"@id/last\"\n" +
+ " android:text=\"Submit\"\n" +
+ " android:onClick=\"@{activity.onClick}\"/>\n" +
+ "</RelativeLayout>";
+}